java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Mybatis中SQL执行过程

Mybatis中SQL的执行过程详解

作者:骑个小蜗牛

MyBatis框架通过映射文件或注解将Java代码中的方法与数据库操作进行映射,执行过程包括SQL解析、参数绑定、SQL预编译、执行、结果映射、事务处理、缓存处理和日志记录

Mybatis 框架

SQL执行过程

数据库操作映射方式

MyBatis支持两种方式进行数据库操作映射:

这两种方式都可以实现数据库操作的映射,具体使用哪种方式取决于个人的喜好和项目需求。本文都以映射文件的方式进行分析。

SQL的执行过程

  1. SQL解析

    MyBatis 会将SQL 语句解析为内部的数据结构。这一过程中,MyBatis 会根据 SQL 中的参数类型、数量等信息,生成一个 MappedStatement 对象,表示当前的 SQL 语句及其相关的执行元数据。

  2. 参数绑定

    在 SQL 解析完成后,MyBatis 会在 SQL 参数映射阶段,将 SQL 语句中的参数与 Java 对象进行映射,并将参数值处理成符合数据库预编译要求的形式。这样,在 SQL 预编译和执行阶段,就可以正确地传递参数并执行 SQL 语句。

  3. SQL预编译

    MyBatis 利用 JDBC 的 PreparedStatement 接口进行 SQL 语句的预编译。预编译过程会将 SQL 中的占位符(?)替换为实际参数,并将其转化为数据库可以优化执行的形式,从而提高 SQL 执行效率。

  4. 执SQL行

    完成预编译后,MyBatis 会通过 JDBC API 将 SQL 语句提交给数据库执行,并获取查询结果或执行结果。数据库执行完成后,结果会返回给 MyBatis 进行进一步处理。

  5. 结果映射

    MyBatis 会将数据库返回的结果集转换为相应的 Java 对象。这一过程包括类型转换、字段匹配等,通常通过 TypeHandler 来完成。TypeHandler 负责将数据库中的列值与 Java 对象的属性进行映射。

  6. 事务处理

    如果启用了手动事务管理,MyBatis 会在 SQL 执行完成后,根据配置的事务管理策略,提交或回滚事务,确保数据一致性和事务的完整性。

  7. 缓存处理

    若启用了缓存,MyBatis 会将查询结果存储到缓存中,以便下次执行相同的 SQL 语句时能够直接从缓存中获取结果,从而减少数据库的访问频率,提高性能。MyBatis 支持一级缓存(SqlSession 范围内)和二级缓存(跨 SqlSession 的共享缓存)。

  8. 日志记录与监控

    MyBatis 会通过集成日志框架(如 Log4j、SLF4J)记录 SQL 执行的详细日志。这些日志信息可以帮助开发人员分析 SQL 执行的性能,发现潜在的问题,优化查询效率。

最后,将查询结果返回给调用方,自此,完成整个 SQL 执行过程。

下面详细介绍每一个过程:

SQL解析

当 MyBatis 执行一个查询时,首先会对传入的 SQL 语句进行解析,解析 SQL 语句的结构和参数信息,为后续的参数绑定和执行做准备。

MyBatis 使用 XML 或注解中的 SQL 语句,结合映射文件中的 MappedStatement 对象来表示 SQL 信息。

MappedStatement 是 MyBatis 核心的配置对象,包含了 SQL 的元数据、类型处理器、缓存策略等。

解析过程涉及到标签的解析、参数的解析和动态SQL的处理

标签解析:

动态SQL处理:

参考:

<select id="findUserById" resultType="User">
    SELECT * FROM users WHERE id = #{id}
</select>

SQL参数映射

MyBatis 在 SQL 参数映射阶段,会将用户提供的参数绑定到 SQL 语句中的占位符。根据映射文件或注解中的 SQL 语句,MyBatis 会分析哪些占位符需要绑定哪些参数。这样,在 SQL 预编译和执行阶段,就可以正确地传递参数并执行 SQL 语句。

在 MappedStatement 中,有一个 BoundSql 对象,它包含了实际的 SQL 语句以及绑定的参数。BoundSql 会根据 SQL 的占位符(如 ? 或 #{})将传入的参数与 SQL 语句进行绑定。

参考:

Map<String, Object> params = new HashMap<>();
params.put("id", 1);
userMapper.findUserById(params);

SQL预编译

MyBatis使用JDBC的PreparedStatement接口创建预编译的SQL语句,预编译的SQL语句中使用占位符(如?)代替参数。通过 SQL 预编译提升执行效率,并确保参数的安全性。

参考:

PreparedStatement ps = connection.prepareStatement("SELECT * FROM users WHERE id = ?");
ps.setInt(1, 1);

SQL执行

MyBatis 会通过 JDBC API 将编译后的 SQL 语句提交到数据库执行。执行过程会获取执行结果,例如查询结果或更新、删除操作的影响行数。

参考:

ResultSet rs = ps.executeQuery();

结果映射

执行 SQL 后,MyBatis 会将数据库返回的 ResultSet 映射为相应的 Java 对象。这个映射过程会根据 SQL 查询的字段与 Java 对象的属性进行转换。

参考:

<resultMap id="userResultMap" type="User">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
</resultMap>

事务处理

MyBatis 支持手动和自动事务管理。默认情况下,MyBatis 使用 JDBC 提供的事务控制。在执行数据库操作后,MyBatis 会根据配置决定是否提交或回滚事务。

参考:

sqlSession.commit();  // 提交事务
sqlSession.rollback();  // 回滚事务

缓存处理

MyBatis 提供了一级缓存和二级缓存机制来提高查询效率。一级缓存是 SqlSession 级别的缓存,而二级缓存是跨 SqlSession 的共享缓存。

日志记录与监控

MyBatis 可以集成各种日志框架(如 Log4j、SLF4J 等)来记录 SQL 执行过程中的信息。开发人员可以通过日志输出 SQL 执行的详细信息,包括查询语句、执行时间等。

参考:

<settings>
    <setting name="logImpl" value="SLF4J"/>
</settings>

扩展

#与$的区别

$ 符号

# 符号

总结示例

示例:

username的值为haha(String)

1. 使用$占位符

SELECT id, username, email FROM users WHERE username = ${username}
# 最终实际执行的sql
SELECT id, username, email FROM users WHERE username = haha

2. 使用#占位符

SELECT id, username, email FROM users WHERE username = #{username}
# 最终实际执行的sql
SELECT id, username, email FROM users WHERE username = 'haha'

Mybatis SQL分类

根据 SQL 查询的特性来区分的,可以将SQL分为动态 SQL静态 SQL

动态 SQL

使用动态SQL,可以根据不同的条件生成不同的SQL语句,从而实现灵活的查询和更新操作。

动态SQL可以使用if、choose、when、otherwise等标签来实现条件判断和循环操作,同时还可以使用foreach标签来实现对集合类型参数的遍历操作

这样可以避免在代码中使用大量的字符串拼接,提高代码的可读性和维护性。

动态 SQL 的特点:

常见的动态 SQL 的示例:

静态 SQL

静态 SQL 的特点:

常见的静态 SQL 的示例:

静态SQL和动态SQL选择

由于静态sql是在应用启动的时候就解析,而动态sql是在执行该sql相关操作的时候才根据传入的参数进行解析的,所以静态sql效率会比动态sql好。

${}、#{}与SQL是否静态SQL、动态SQL无直接关系

示例1:

使用了${} 、#{},不是动态SQL

<select id="getUserById" resultType="User">
    SELECT id, username, email
    FROM users
    WHERE id = #{id}
</select>

示例2:

使用 ${} 来动态拼接表名,不是动态SQL

<select id="getUsersByTableName" resultType="User">
    SELECT id, username, email
    FROM ${tableName}
    WHERE id = #{id}
</select>

示例3:

使用了${} 、#{},是动态SQL

<select id="selectUsers" resultType="User">
    SELECT id, username, email
    FROM users
    <where>
        <if test="username != null">AND username = #{username}</if>
        <if test="email != null">AND email = #{email}</if>
    </where>
</select>

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文