MyBatis

概述

MyBatis是一种轻量级的Java持久层框架,它提供了简单而强大的数据库访问功能,帮助开发者将Java对象与数据库之间进行映射和交互。

  1. ORM(对象关系映射):MyBatis采用ORM的思想,将数据库表和Java对象之间建立映射关系。通过配置和编写SQL映射文件,开发者可以直接使用Java对象来操作数据库,而无需手动编写大量的JDBC代码。
  2. 核心组件:
    • SqlSessionFactory:SqlSessionFactory是MyBatis的核心接口,负责创建和管理SqlSession对象。它是单个数据库映射关系的工厂类,通过它可以获取SqlSession对象来执行SQL操作。
    • SqlSession:SqlSession是与数据库交互的会话对象,它提供了执行SQL语句、获取映射器(Mapper)和管理事务的方法。
    • Mapper接口:Mapper接口定义了与数据库交互的方法,通过编写Mapper接口的方法以及对应的XML配置文件,可以实现Java方法和SQL语句的映射关系。

作用

MyBatis的作用是简化和优化Java应用程序与数据库之间的交互过程。它提供了以下主要功能和作用:

  1. 数据库访问:MyBatis使得数据库的访问变得简单和高效。通过编写SQL映射文件和Mapper接口,开发者可以使用面向对象的方式执行数据库操作,包括插入、更新、删除和查询等常见操作。

  2. 对象关系映射(ORM):MyBatis实现了数据库表和Java对象之间的映射关系,通过配置和映射文件,可以将查询结果自动映射到Java对象中。这使得开发者可以使用面向对象的方式操作数据,而无需手动编写JDBC代码。

  3. 灵活的SQL编写:MyBatis提供了灵活的SQL编写方式,支持静态SQL和动态SQL。开发者可以在SQL映射文件中编写SQL语句,通过使用条件判断、循环和参数绑定等功能,可以动态构建SQL语句,满足各种复杂的查询需求。

  4. 缓存支持:MyBatis内置了缓存机制,可以将查询结果缓存起来,提高查询性能。通过配置和合理使用缓存,可以减少数据库的访问次数,加快应用程序的响应速度。

  5. 事务管理:MyBatis提供了事务管理的支持,开发者可以通过SqlSession来管理事务。MyBatis可以与Spring等框架集成,实现声明式事务管理,保证数据库操作的原子性和一致性。

  6. 扩展性和插件:MyBatis具有良好的扩展性,允许开发者编写自定义的类型处理器、拦截器和插件等,以满足特定的需求。这使得开发者可以根据应用程序的需求进行定制和扩展。

原理

  • 配置文件:MyBatis使用一个配置文件(mybatis-config.xml)来配置和初始化框架的各种设置,例如数据库连接、类型处理器、插件等。
  • SQL映射文件:SQL映射文件(Mapper)定义了Java方法和对应的SQL语句的映射关系。通过配置SQL映射文件,MyBatis可以自动执行SQL语句并将结果映射到Java对象中。
  • SqlSessionFactoryBuilder:SqlSessionFactoryBuilder是用于创建SqlSessionFactory的构建器,它读取配置文件并解析配置信息,然后构建出SqlSessionFactory对象。
  • SqlSessionFactory:SqlSessionFactory是由SqlSessionFactoryBuilder创建的,它是一个线程安全的工厂类,用于创建SqlSession对象。
  • SqlSession:SqlSession是与数据库交互的会话对象,它提供了执行SQL语句、获取映射器(Mapper)和管理事务的方法。每个线程都应该拥有自己的SqlSession实例。

安装配置

  1. 引入MyBatis依赖:在您的Java项目中,需要将MyBatis作为依赖添加到项目的构建文件(如Maven或Gradle)中。您可以从Maven中央存储库或MyBatis官方网站获取最新的MyBatis依赖。

  2. 创建MyBatis配置文件:在项目的资源目录下创建一个名为mybatis-config.xml的文件,用于配置MyBatis的各种设置。

  3. 配置数据源:在mybatis-config.xml文件中配置数据库连接信息和连接池。您可以使用MyBatis提供的内置连接池(如PooledDataSource),或者使用第三方的连接池库(如Druid或HikariCP)。

  4. 创建SQL映射文件(Mapper):创建一个或多个XML文件,用于定义SQL语句和与之对应的映射关系。这些文件通常与数据库表或Java对象相关联。

  5. 配置SQL映射文件:在mybatis-config.xml文件中配置SQL映射文件的路径,以便MyBatis可以找到并加载它们。您可以使用相对路径或绝对路径,确保文件能够正确加载。

  6. 创建SqlSessionFactory:使用mybatis-config.xml文件的配置信息,通过编程方式创建SqlSessionFactory实例。可以使用SqlSessionFactoryBuilder类来构建SqlSessionFactory

  7. 获取SqlSession:使用SqlSessionFactory创建SqlSession对象。SqlSession是与数据库交互的会话对象,它提供了执行SQL语句、获取映射器(Mapper)和管理事务的方法。

  8. 编写Mapper接口:创建Java接口,定义与数据库交互的方法。每个方法对应于一个SQL语句。可以使用注解或XML文件来配置方法与SQL语句的映射关系。

  9. 执行数据库操作:使用SqlSession通过调用Mapper接口的方法执行数据库操作。MyBatis将根据配置的映射关系执行对应的SQL语句,并将结果映射到Java对象中。


当安装和配置MyBatis时,涉及的配置文件和代码如下所示:

  1. 创建mybatis-config.xml文件(示例内容):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 配置数据源 -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/mydatabase" />
                <property name="username" value="root" />
                <property name="password" value="password" />
            </dataSource>
        </environment>
    </environments>
    <!-- 配置SQL映射文件的路径 -->
    <mappers>
        <mapper resource="com/example/mappers/MyMapper.xml" />
    </mappers>
</configuration>
  1. 创建SQL映射文件 MyMapper.xml(示例内容):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mappers.MyMapper">

    <!-- 定义结果映射 -->
    <resultMap id="myModelResultMap" type="com.example.models.MyModel">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="email" column="email" />
        <!-- 其他属性映射 -->
    </resultMap>

    <!-- 查询操作 -->
    <select id="getById" resultMap="myModelResultMap" parameterType="int">
        SELECT * FROM my_table WHERE id = #{id}
    </select>

    <select id="getAll" resultMap="myModelResultMap">
        SELECT * FROM my_table
    </select>

    <!-- 插入操作 -->
    <insert id="insert" parameterType="com.example.models.MyModel">
        INSERT INTO my_table (name, email) VALUES (#{name}, #{email})
    </insert>

    <!-- 更新操作 -->
    <update id="update" parameterType="com.example.models.MyModel">
        UPDATE my_table SET name = #{name}, email = #{email} WHERE id = #{id}
    </update>

    <!-- 删除操作 -->
    <delete id="delete" parameterType="int">
        DELETE FROM my_table WHERE id = #{id}
    </delete>

    <!-- 其他SQL语句和映射关系 -->

</mapper>
  1. 创建Mapper接口 MyMapper.java(示例内容):
package com.example.mappers;

import com.example.models.MyModel;

public interface MyMapper {
    MyModel getById(int id);
    void insert(MyModel model);
    // 其他方法声明
}
  1. 创建SqlSessionFactory和SqlSession:
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.session.SqlSession;

public class MyBatisConfig {
    public static void main(String[] args) {
        // 读取mybatis-config.xml配置文件
        String configPath = "path/to/mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(configPath);
        
        // 创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        // 创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        
        // 通过SqlSession获取Mapper接口实例
        MyMapper myMapper = sqlSession.getMapper(MyMapper.class);

        // 执行数据库操作
        MyModel result = myMapper.getById(1);
        System.out.println(result);
        
        // 提交事务并关闭SqlSession
        sqlSession.commit();
        sqlSession.close();
    }
}

上述代码中,需要注意将mybatis-config.xml的路径、SQL映射文件的路径以及数据库连接的配置信息根据实际情况进行修改。


拓展:插入操作中返回添加数据的主键

在插入操作中,如果需要获取添加数据的主键,可以通过 MyBatis 提供的一些特性来实现。下面是详细讲解如何在插入操作中返回添加数据的主键:

  1. 在 Mapper XML 文件中,使用 <insert> 元素执行插入操作,并设置 useGeneratedKeys 属性为 true,同时指定 keyProperty 属性来指定保存主键值的属性。

    <insert id="insertUser" parameterType="com.example.User" useGeneratedKeys="true" keyProperty="id">
      INSERT INTO users (name, age) VALUES (#{name}, #{age})
    </insert>
    

    在上述示例中,useGeneratedKeys 属性设置为 true,表示开启自动生成主键的功能,keyProperty 属性设置为 id,表示将生成的主键值赋给 id 属性。

  2. 在 Java 对象中,需要为保存主键值的属性提供对应的 setter 方法。

    public class User {
      private Long id;
      private String name;
      private int age;
    
      // Getter and Setter for id
    
      // Getter and Setter for name and age
    }
    

    确保 User 类中的 id 属性有对应的 getter 和 setter 方法。

  3. 在执行插入操作后,通过获取 User 对象的 id 属性即可获取添加数据的主键值。

    User user = new User();
    user.setName("John");
    user.setAge(25);
    
    userMapper.insertUser(user);
    
    Long generatedId = user.getId();
    

    在上述示例中,通过调用 insertUser 方法插入数据后,可以通过 user.getId() 方法获取添加数据的主键值。

常用配置

MyBatis的核心配置文件mybatis-config.xml具有以下结构和常用配置项:

  1. 根元素 <configuration>:表示配置文件的根元素,包含了整个配置的内容。

  2. <properties> 元素:用于定义属性,可以在配置文件中引用这些属性。常用的子元素有:

    • <property>:定义一个属性,包括namevalue两个属性,用于设置属性的名称和值。
  3. <settings> 元素:配置全局设置选项,用于影响 MyBatis 的运行时行为。常用的设置项有:

    • <setting>:用于设置具体的选项,包括namevalue两个属性。
      • cacheEnabled:是否启用缓存,默认值为 true
      • lazyLoadingEnabled:是否启用延迟加载,默认值为 false
      • mapUnderscoreToCamelCase:是否开启自动驼峰命名规则映射,默认值为 false
  4. <typeAliases> 元素:用于配置类型别名,简化映射器中的类型引用。常用的子元素有:

    • <typeAlias>:用于定义一个类型别名,包括typealias两个属性,分别指定类型和别名。
  5. <typeHandlers> 元素:配置类型处理器,用于处理 Java 类型与数据库类型之间的转换。常用的子元素有:

    • <typeHandler>:用于配置具体的类型处理器,可以指定 Java 类型和对应的处理器类。
  6. <objectFactory> 元素:配置对象工厂,用于创建映射器中的结果对象。常用的子元素有:

    • <property>:用于配置对象工厂的属性。
  7. <plugins> 元素:用于配置插件,可以在 MyBatis 的执行过程中添加自定义的功能扩展。常用的子元素有:

    • <plugin>:用于配置具体的插件,需要指定插件的实现类。
  8. <environments> 元素:配置 MyBatis 的环境,包括事务管理器和数据源。常用的子元素有:

    • <environment>:定义一个具体的环境,包含事务管理器和数据源配置。
    • <transactionManager>:配置事务管理器的类型。
    • <dataSource>:配置数据源的类型和相关属性。
  9. <databaseIdProvider> 元素:用于根据数据库厂商标识(databaseId)选择不同的语句。常用的子元素有:

    • <property>:用于配置数据库厂商标识和对应的语句。
  10. <mappers> 元素:配置映射器,用于告知 MyBatis 哪些接口是映射器。常用的子元素有:

    • <mapper>:用于指定映射器的位置,可以通过路径、类或包进行配置。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <!-- 配置数据源 -->
    <environments default="development">
        <environment id="development">
            <!-- 配置事务管理器 -->
            <transactionManager type="JDBC" />
            
            <!-- 配置数据源类型 -->
            <dataSource type="POOLED">
                <!-- 数据库连接信息 -->
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/mydatabase" />
                <property name="username" value="root" />
                <property name="password" value="password" />
            </dataSource>
        </environment>
    </environments>
    
    <!-- 配置映射器 -->
    <mappers>
        <!-- 方式1:通过路径加载映射器 -->
        <mapper resource="com/example/mappers/MyMapper.xml" />
        
        <!-- 方式2:通过类加载映射器 -->
        <mapper class="com.example.mappers.OtherMapper" />
        
        <!-- 方式3:使用包扫描加载映射器 -->
        <package name="com.example.mappers" />
    </mappers>
    
    <!-- 其他常用配置选项 -->
    
    <!-- 开启或关闭缓存,默认为true -->
    <settings>
        <setting name="cacheEnabled" value="true" />
    </settings>
    
    <!-- 开启或关闭延迟加载,默认为false -->
    <settings>
        <setting name="lazyLoadingEnabled" value="false" />
    </settings>
    
    <!-- 开启或关闭自动驼峰命名规则映射,默认为false -->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="false" />
    </settings>
    
    <!-- 设置日志实现类 -->
    <settings>
        <setting name="logImpl" value="LOG4J" />
    </settings>
    
</configuration>

  1. 数据源配置:

    • <environments>元素用于配置MyBatis的环境,包含多个<environment>子元素,可用于定义多个环境,例如developmentproduction等。
    • <environment>元素用于定义一个具体的环境,包括事务管理器和数据源配置。
    • <transactionManager>元素用于指定事务管理器的类型,常见的类型有:
      • JDBC:使用JDBC事务管理器,适用于单个数据库的场景。
      • MANAGED:使用容器管理的事务,例如Java EE容器管理的事务。
    • <dataSource>元素用于配置数据源的类型,常用的类型有:
      • POOLED:使用连接池管理数据库连接,通过配置属性如driverurlusernamepassword等来连接数据库。
      • UNPOOLED:不使用连接池,每次请求都会创建新的数据库连接。
      • JNDI:使用Java命名和目录接口(JNDI)获取数据源。
  2. 映射器配置:

    • <mappers>元素用于配置映射器,可以通过多种方式加载映射器。
    • <mapper resource="com/example/mappers/MyMapper.xml" />用于通过路径加载映射器,指定映射器文件的路径。
    • <mapper class="com.example.mappers.OtherMapper" />用于通过类加载映射器,指定映射器接口的类名。
    • <package name="com.example.mappers" />用于通过包扫描加载映射器,指定包的路径,MyBatis将扫描包路径下的映射器接口。
  3. 缓存配置:

    • <settings>元素用于配置全局设置选项。
    • <setting name="cacheEnabled" value="true" />用于开启或关闭缓存,默认为true
    • MyBatis提供多种缓存实现,包括本地缓存、二级缓存等,可根据需要进行配置。
  4. 延迟加载配置:

    • <settings>元素中的<setting name="lazyLoadingEnabled" value="false" />用于开启或关闭延迟加载,默认为false
    • 当开启延迟加载时,MyBatis将延迟加载关联对象的属性,直到访问该属性时才进行加载。
  5. 命名规则映射配置:

    • <settings>元素中的<setting name="mapUnderscoreToCamelCase" value="false" />用于开启或关闭自动驼峰命名规则映射,默认为false
    • 当开启自动驼峰命名规则映射时,MyBatis会自动将数据库列名的下划线命名转换为Java对象的驼峰命名属性。
  6. 日志配置:

    • <settings>元素中的<setting name="logImpl" value="LOG4J" />用于设置日志实现类。
    • MyBatis支持多种日志实现,可根据项目使用的日志框架进行配置,如LOG4JSLF4JSTDOUT_LOGGING等。

基本使用

  1. 定义数据模型(Model):

    • 创建一个Java类,用于表示数据库表中的一行数据。
    • 在类中定义与表中列对应的属性,并提供相应的getter和setter方法。
  2. 编写映射器(Mapper):

    • 创建一个映射器接口,用于定义数据库操作的方法。
    • 在接口中定义与数据库操作相对应的方法,并使用注解或XML配置SQL语句。
  3. 配置MyBatis:

    • 创建mybatis-config.xml配置文件,配置数据源、映射器等相关设置。
    • 在配置文件中指定映射器的位置,可以通过XML文件路径、类路径或包扫描等方式加载映射器。
  4. 使用MyBatis进行数据库操作:

    • 获取SqlSessionFactory对象,它是MyBatis的核心对象,负责创建SqlSession对象。
    • 通过SqlSession对象,调用映射器接口中的方法执行数据库操作。

SQL映射文件(Mapper)

概述

SQL映射文件(Mapper)是MyBatis中定义数据库操作的地方。它包含了SQL语句和映射器接口方法之间的映射关系。

  1. 创建SQL映射文件:

    • 创建一个以.xml为后缀的文件,用于存放SQL语句和映射关系。
    • 可以将SQL映射文件放置在类路径下的任意位置,例如resources目录。
  2. 定义命名空间:

    • 在SQL映射文件的根元素上,使用namespace属性定义一个命名空间,用于唯一标识该映射文件。
    • 命名空间的值通常是映射器接口的完全限定名,例如com.example.mappers.UserMapper
  3. 编写SQL语句:

    • 使用合适的SQL元素(如<select><insert><update><delete>)编写SQL语句。
    • 在SQL元素中,使用${}#{}来引用参数或属性。
  4. 配置映射器接口方法:

    • 在SQL映射文件中,通过与映射器接口中的方法相对应,建立方法与SQL语句之间的映射关系。
    • 使用合适的SQL元素来定义SQL语句,并使用id属性指定映射器接口中的方法名。
  5. 使用参数:

    • 在SQL语句中,可以使用${}#{}两种方式来引用参数。
    • ${}会将参数的值直接替换到SQL语句中,可能会有SQL注入的风险
    • #{}会将参数作为预编译参数进行处理,更加安全。
  6. 处理结果集:

    • 使用<resultMap>元素定义结果集的映射关系,将查询结果的列与映射器接口方法返回类型中的属性进行映射。
    • 使用<result>元素定义列和属性的映射关系。
    • 使用<association><collection>元素处理一对一和一对多的关联关系。
  7. 配置其他元素:

    • 可以在SQL映射文件中配置其他元素,如动态SQL、参数类型处理器、缓存等。
  8. 配置映射器:

    • mybatis-config.xml中的<mappers>元素中配置映射器。
    • 可以通过多种方式加载映射器,如通过路径、类或包进行配置。

编写和配置

<!-- 定义命名空间 -->
<mapper namespace="com.example.mappers.UserMapper">

  <!-- 定义查询用户的SQL语句 -->
  <select id="getUserById" resultType="com.example.models.User">
    SELECT * FROM users WHERE id = #{id}
  </select>

  <!-- 定义插入用户的SQL语句 -->
  <insert id="insertUser">
    INSERT INTO users (name, email) VALUES (#{name}, #{email})
  </insert>

  <!-- 定义更新用户的SQL语句 -->
  <update id="updateUser">
    UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id}
  </update>

  <!-- 定义删除用户的SQL语句 -->
  <delete id="deleteUser">
    DELETE FROM users WHERE id = #{id}
  </delete>

</mapper>

特殊字符处理

在编写 Mapper XML 文件时,如果遇到特殊字符,可以使用 XML 的转义字符来处理。以下是常见的几个特殊字符及其对应的转义字符:

  1. <(小于号):使用 &lt; 表示。
  2. >(大于号):使用 &gt; 表示。
  3. &(和号):使用 &amp; 表示。
  4. "(双引号):使用 &quot; 表示。
  5. '(单引号):使用 &apos; 表示。

例如,如果你的 SQL 语句中包含一个 < 符号,你可以使用 &lt; 替代它。

下面是一个示例,展示如何在 Mapper XML 文件中处理特殊字符:

<select id="getUserByName" resultType="com.example.User">
  SELECT * FROM users WHERE name = '&lt;John&gt;'
</select>

在上述示例中,SQL 语句中的特殊字符 <> 被转义为 &lt;&gt;。这样可以确保 XML 解析时不会将其误认为是标签,而是作为普通的文本处理。


除了使用 XML 转义字符处理特殊字符之外,还有另一种处理方式,即使用 CDATA(字符数据)块来包裹包含特殊字符的内容。CDATA 块会告诉 XML 解析器将其中的内容视为纯文本,不会解析其中的标签或特殊字符。

以下是使用 CDATA 块处理特殊字符的示例:

<select id="getUserByName" resultType="com.example.User">
  <![CDATA[
    SELECT * FROM users WHERE name = '<John>'
  ]]>
</select>

在上述示例中,SQL 语句被包裹在 <![CDATA[]]> 之间,告诉 XML 解析器将其视为纯文本。这样可以避免解析器将 <> 等特殊字符作为标签进行处理。

使用 CDATA 块处理特殊字符的好处是可以更直观地表达包含特殊字符的内容,并且不需要手动转义每个特殊字符。但需要注意,CDATA 块内部仍然要遵循 XML 的语法规则,例如不可出现 ]]> 的内容。

动态SQL语句

使用if语句

在 MyBatis 中,<if> 元素是一种常用的动态 SQL 标签,用于根据条件动态生成 SQL 语句的一部分。<if> 元素通常结合其他 SQL 标签一起使用,例如 <select><update><insert> 等,以根据条件决定是否包含某个语句块或生成特定的 SQL 语句。

下面是一个示例,展示如何在 MyBatis 中使用 <if> 元素生成动态的 SQL 语句:

<select id="getUserList" parameterType="com.example.UserSearchCriteria" resultType="com.example.User">
  SELECT * FROM users
  WHERE 1=1
    <if test="name != null">
      AND name = #{name}
    </if>
    <if test="age != null">
      AND age = #{age}
    </if>
    <if test="email != null and email != ''">
      AND email = #{email}
    </if>
</select>

在上述示例中,<if> 元素用于根据不同的条件判断是否生成对应的 SQL 语句部分。每个 <if> 元素都有一个 test 属性,用于指定判断条件。

例如,如果传入了 nameage 参数,但没有传入 email 参数,则生成的 SQL 语句将只包含 nameage 条件的部分。

UserSearchCriteria criteria = new UserSearchCriteria();
criteria.setName("John");
criteria.setAge(25);

List<User> userList = userMapper.getUserList(criteria);

在上述示例中,根据传入的搜索条件对象 UserSearchCriteria 中的属性值,动态生成 SQL 语句。只有满足条件的 <if> 块中的语句会被包含在最终的 SQL 语句中。

通过使用 <if> 元素,可以根据不同的条件动态生成 SQL 语句的一部分,以适应不同的查询需求。在实际使用中,可以根据具体的业务场景和查询条件,结合其他动态 SQL 标签来编写更复杂的动态 SQL 语句。

使用choose语句

在 MyBatis 中,<choose> 元素是一种用于处理多个条件的动态 SQL 标签。它类似于 Java 中的 switch-case 语句,用于在多个条件中选择一个满足条件的分支。

下面是一个示例,展示如何在 MyBatis 中使用 <choose> 元素生成动态的 SQL 语句:

<select id="getUserList" parameterType="com.example.UserSearchCriteria" resultType="com.example.User">
  SELECT * FROM users
  WHERE 1=1
  <choose>
    <when test="name != null">
      AND name = #{name}
    </when>
    <when test="age != null">
      AND age = #{age}
    </when>
    <otherwise>
      AND email = #{email}
    </otherwise>
  </choose>
</select>

在上述示例中,<choose> 元素包含多个 <when> 元素和一个 <otherwise> 元素。每个 <when> 元素用于指定一个条件,如果满足该条件,则生成对应的 SQL 语句部分。<otherwise> 元素是可选的,用于指定默认的条件分支,当其他条件都不满足时,会生成对应的 SQL 语句部分。

例如,如果传入了 nameage 参数,但没有传入 email 参数,则生成的 SQL 语句将只包含 nameage 条件的部分。

UserSearchCriteria criteria = new UserSearchCriteria();
criteria.setName("John");
criteria.setAge(25);

List<User> userList = userMapper.getUserList(criteria);

在上述示例中,根据传入的搜索条件对象 UserSearchCriteria 中的属性值,动态生成 SQL 语句。只有满足条件的 <when> 块中的语句会被包含在最终的 SQL 语句中,如果所有的条件都不满足,则会执行 <otherwise> 块中的语句。

通过使用 <choose> 元素,可以根据多个条件选择一个满足条件的分支,并生成对应的 SQL 语句。这样可以在复杂的查询场景中灵活地处理多个条件的组合,以满足不同的查询需求。

使用Set语句

在 MyBatis 中,<set> 元素用于动态生成 SQL 语句中的 SET 子句,用于指定要修改的字段和对应的值。 <set> 元素可以与其他动态标签(如 <if><choose> 等)结合使用,以根据条件动态生成 SET 子句的内容。

下面是一个示例,展示如何在 MyBatis 中使用 <set> 元素生成动态的 SET 子句:

<update id="updateUser" parameterType="com.example.User">
  UPDATE users
  <set>
    <if test="name != null">
      name = #{name},
    </if>
    <if test="age != null">
      age = #{age},
    </if>
    <if test="email != null">
      email = #{email},
    </if>
  </set>
  WHERE id = #{id}
</update>

在上述示例中,<set> 元素包含了多个 <if> 元素。每个 <if> 元素用于判断某个字段是否需要修改。如果满足条件,就会生成对应的 SET 子句,将字段和值添加到 SQL 语句中。

例如,如果只传入了 name 字段和值,那么生成的 SQL 语句将只包含修改 name 字段的 SET 子句。

User user = new User();
user.setId(1L);
user.setName("John Doe");

userMapper.updateUser(user);

在上述示例中,只传入了 name 字段和值,生成的 SQL 语句将只修改 name 字段的值。

使用 <set> 元素可以灵活地根据条件动态生成 SET 子句,以满足不同的修改需求。可以根据具体的业务场景,结合其他动态标签来编写复杂的动态 SQL 语句。

使用foreach语句

在 MyBatis 中,<foreach> 元素是一种用于遍历集合或数组并生成动态 SQL 语句的标签。它可以循环处理集合中的元素,并将每个元素应用于指定的 SQL 语句部分。

下面是一个示例,展示如何在 MyBatis 中使用 <foreach> 元素生成动态的 SQL 语句:

<select id="getUserList" parameterType="java.util.List" resultType="com.example.User">
  SELECT * FROM users
  WHERE id IN
  <foreach item="id" collection="list" open="(" separator="," close=")">
    #{id}
  </foreach>
</select>

在上述示例中,<foreach> 元素用于遍历传入的 List 类型参数中的元素,并将每个元素应用于 SQL 语句中的 IN 子句中。item 属性指定了循环变量的名称,collection 属性指定了要遍历的集合或数组,openseparatorclose 属性用于指定拼接 SQL 语句时的开头、分隔符和结尾。

例如,传入了一个包含多个用户 ID 的列表:

List<Long> idList = Arrays.asList(1L, 2L, 3L);

List<User> userList = userMapper.getUserList(idList);

在上述示例中,根据传入的 ID 列表,动态生成 SQL 语句,使用 IN 子句查询符合条件的用户。

通过使用 <foreach> 元素,可以在 SQL 语句中循环遍历集合或数组,并将集合中的元素应用于指定的 SQL 语句部分。这样可以方便地处理需要循环操作的查询场景,如根据多个条件查询、批量插入等。

使用trim语句

在 MyBatis 中,<trim> 元素是一种用于修剪生成的 SQL 语句中不需要的部分的标签。它可以用于在生成 SQL 语句时去除开头、结尾或中间的多余字符,从而更灵活地构建动态 SQL 语句。

下面是一个示例,展示如何在 MyBatis 中使用 <trim> 元素:

<select id="getUserList" parameterType="com.example.UserSearchCriteria" resultType="com.example.User">
  SELECT * FROM users
  <trim prefix="WHERE" prefixOverrides="AND |OR ">
    <if test="name != null">
      AND name = #{name}
    </if>
    <if test="age != null">
      AND age = #{age}
    </if>
  </trim>
</select>

在上述示例中,<trim> 元素用于修剪生成的 SQL 语句中的不需要的部分。prefix 属性指定了修剪后添加的前缀,prefixOverrides 属性指定了要移除的前缀。在 <trim> 元素内部,可以使用其他动态 SQL 标签(如 <if><choose> 等)来生成动态的 SQL 语句。

例如,如果传入了 nameage 参数,则生成的 SQL 语句将包含对应的查询条件,并且以 WHERE 关键字开头。

UserSearchCriteria criteria = new UserSearchCriteria();
criteria.setName("John");
criteria.setAge(25);

List<User> userList = userMapper.getUserList(criteria);

在上述示例中,根据传入的搜索条件对象 UserSearchCriteria 中的属性值,动态生成 SQL 语句。只有满足条件的 <if> 块中的语句会被包含在最终的 SQL 语句中。

通过使用 <trim> 元素,可以更精确地控制生成的 SQL 语句中的部分内容,去除不需要的前缀或修剪掉多余的字符。这样可以减少手动拼接字符串的复杂性,提高动态 SQL 的可读性和灵活性。

使用sql片段

在 MyBatis 中,可以使用 <sql> 元素定义 SQL 片段(SQL Fragment),并在需要的地方引用这些片段。SQL 片段可以用于重复使用一段 SQL 代码,提高代码的可维护性和重用性。

下面是一个示例,展示如何在 MyBatis 中使用 <sql> 元素:

<sql id="userColumns">
  id, name, age, email
</sql>

<select id="getUserList" resultType="com.example.User">
  SELECT <include refid="userColumns"/>
  FROM users
</select>

在上述示例中,<sql> 元素用于定义了一个名为 "userColumns" 的 SQL 片段,其中包含了用户表的列名。通过 <include> 元素引用了这个 SQL 片段,将其插入到了 <select> 语句中。

这样,可以在多个 SQL 语句中重复使用 userColumns 的定义,避免重复编写相同的列名。

List<User> userList = userMapper.getUserList();

在上述示例中,查询语句中的 <include> 元素会被替换为 userColumns 定义的 SQL 片段,从而生成最终的 SQL 语句。

通过使用 <sql> 元素和 <include> 元素,可以方便地定义和引用 SQL 片段,提高 SQL 语句的可读性和重用性。这样可以简化 SQL 语句的编写,减少冗余代码,并增加代码的可维护性和可扩展性。

参数传递

在 MyBatis 中,参数传递是将数据传递给 SQL 语句的一种方式。MyBatis 支持多种参数传递方式,包括单个参数、多个参数、Map 类型参数以及使用注解等方式。

下面是几种常见的参数传递方式:

  1. 单个参数:可以直接将单个参数传递给 SQL 语句,例如:

    List<User> getUserList(String name);
    

    在上述示例中,单个参数 name 会被传递给 SQL 语句,并在 SQL 语句中使用。

  2. 多个参数:可以使用 @Param 注解来标记多个参数,并在 SQL 语句中使用这些参数,例如:

    List<User> getUserList(@Param("name") String name, @Param("age") int age);
    

    在上述示例中,使用 @Param 注解标记了两个参数 nameage,并在 SQL 语句中使用它们。

  3. Map 类型参数:可以将参数封装为一个 Map 对象,然后将 Map 对象传递给 SQL 语句,例如:

    List<User> getUserList(Map<String, Object> paramMap);
    

    在上述示例中,参数被封装为一个 Map 对象 paramMap,其中键为参数名,值为参数值。在 SQL 语句中使用参数时,可以通过键来获取对应的值。

  4. 使用注解:可以使用 MyBatis 的注解方式来指定参数传递,例如 @Param 注解、@ParamMap 注解等。具体使用方式可参考 MyBatis 的注解文档。

在 SQL 语句中引用参数时,可以使用 ${}#{} 语法来获取参数值。其中 ${} 使用的是直接替换的方式,而 #{} 使用的是预编译的方式,可以有效防止 SQL 注入攻击,并自动进行类型转换和特殊字符的处理。

小贴士

  1. 参数的命名在 SQL 语句中要与参数对象的属性或者注解中的名称一致,这样 MyBatis 才能正确地映射参数值。

结果集处理

在 MyBatis 中,结果集处理是指将数据库返回的查询结果映射到 Java 对象或其他数据结构的过程。MyBatis 提供了多种方式来处理结果集,包括自动映射、手动映射和使用结果集映射器。

下面是几种常见的结果集处理方式:

  1. 自动映射:MyBatis 提供了自动将查询结果集映射到 Java 对象的功能。它会根据查询结果集的列名与 Java 对象的属性名进行自动匹配,并将结果集中的数据赋值给对象的属性。要使用自动映射,可以在 SQL 映射文件(Mapper XML)中使用 resultType 属性指定结果对象的类型,或者使用注解方式指定结果对象的类型。

  2. 手动映射:如果查询结果集的列名与 Java 对象的属性名不完全匹配,或者需要进行复杂的映射操作,可以使用手动映射方式。手动映射需要在 SQL 映射文件中使用 <resultMap> 元素定义结果集的映射关系,将查询结果的列与映射器接口方法返回类型中的属性进行手动映射。

  3. 使用结果集映射器:MyBatis 还提供了结果集映射器(ResultMap)的功能,可以在 XML 配置文件中定义复杂的映射关系,包括一对一关联、一对多关联等。结果集映射器可以通过 <resultMap> 元素定义,然后在 SQL 映射文件中引用该结果集映射器,进行结果集的映射处理。

无论使用哪种方式进行结果集处理,都可以通过在 SQL 映射文件中编写相应的配置来指定映射关系,包括列名与属性名的映射、关联关系的映射等。具体的映射配置会根据查询的需求和结果的数据结构而有所不同。


通过 <resultMap> 元素来定义结果集的映射关系,将查询结果的列与映射器接口方法返回类型中的属性进行映射。同时,使用 <result> 元素定义列和属性的映射关系,以及 <association><collection> 元素处理一对一和一对多的关联关系。

以下是对处理结果集的详细讲解:

  1. <resultMap> 元素:

    • <resultMap> 元素用于定义结果集的映射关系。
    • 通过 id 属性指定 <resultMap> 的唯一标识符。
    • 使用 type 属性指定映射器接口方法的返回类型。
    • 通过 <resultMap> 的子元素 <result><association><collection> 来定义具体的映射关系。
  2. <result> 元素:

    • <result> 元素用于定义列和属性的映射关系。
    • 使用 column 属性指定查询结果的列名。
    • 使用 property 属性指定映射器接口方法返回类型中的属性名。
    • 可以使用 javaType 属性指定属性的 Java 类型。
    • 可以使用 jdbcType 属性指定列的 JDBC 类型。
  3. <association> 元素:

    • <association> 元素用于处理一对一的关联关系。
    • 使用 property 属性指定映射器接口方法返回类型中的属性名。
    • 使用 javaTyperesultMap 属性指定关联对象的类型或关联对象的映射关系。
  4. <collection> 元素:

    • <collection> 元素用于处理一对多的关联关系。
    • 使用 property 属性指定映射器接口方法返回类型中的属性名。
    • 使用 ofTyperesultMap 属性指定集合元素的类型或集合元素的映射关系。

下面是一个包含 <resultMap> 元素、<result> 元素、<association> 元素和 <collection> 元素的完整案例配置:

<resultMap id="userResultMap" type="com.example.User">
  <id property="id" column="id" />
  <result property="username" column="username" />
  <result property="password" column="password" />
  <result property="email" column="email" />
  <result property="phone" column="phone" />
  <result property="address" column="address" />
  
  <association property="role" javaType="com.example.Role">
    <id property="id" column="role_id" />
    <result property="name" column="role_name" />
  </association>
  
  <collection property="permissions" ofType="com.example.Permission">
    <id property="id" column="permission_id" />
    <result property="name" column="permission_name" />
  </collection>
</resultMap>

在上述案例中,假设有一个 User 类,其中包含了用户的基本信息以及关联的角色和权限信息。使用 <resultMap> 元素定义了名为 userResultMap 的结果映射关系,类型为 com.example.User。接下来使用 <id> 元素和 <result> 元素将列和属性进行映射。其中 <id> 元素用于指定主键映射,<result> 元素用于指定其他列和属性的映射。

<resultMap> 中还使用了 <association> 元素和 <collection> 元素来处理一对一和一对多的关联关系。通过 <association> 元素,定义了 role 属性的关联关系,指定了 com.example.Role 类型,并使用 <id> 元素和 <result> 元素将角色的列和属性进行映射。同样地,通过 <collection> 元素,定义了 permissions 属性的关联关系,指定了 com.example.Permission 类型,并使用 <id> 元素和 <result> 元素将权限的列和属性进行映射。

注解开发

在 MyBatis 中,除了使用 XML 配置文件来编写 SQL 映射和配置,还可以使用注解开发的方式来简化开发过程。注解开发可以将 SQL 语句直接与 Java 接口或方法进行关联,使得代码更加紧凑和易于理解。

以下是注解开发的一般步骤:

  1. 创建实体类:创建一个 Java 类来表示数据库中的表,可以使用 @Entity 注解将其与数据库表进行映射。

  2. 创建 Mapper 接口:创建一个接口,其中定义了与数据库交互的方法。使用注解来标记接口中的方法与 SQL 语句的对应关系。可以使用 @Select@Insert@Update@Delete 注解等,分别对应查询、插入、更新和删除操作。

  3. 配置 MyBatis:在 MyBatis 的配置文件(mybatis-config.xml)中,需要配置将注解进行扫描的相关设置。通过 <mappers> 元素和 <package> 元素指定要扫描的 Mapper 接口所在的包。

  4. 使用注解开发:在 Mapper 接口中,根据需要定义各种查询和操作的方法,并使用相应的注解来映射 SQL 语句。注解的参数可以直接传递 SQL 语句或者使用动态 SQL 的注解来构建动态 SQL。

下面是一个简单的注解开发的示例:

@Entity
public class User {
    private Long id;
    private String username;
    private String password;
    // getters and setters
}

public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User getUserById(Long id);
    
    @Insert("INSERT INTO users (username, password) VALUES (#{username}, #{password})")
    void addUser(User user);
    
    @Update("UPDATE users SET password = #{password} WHERE id = #{id}")
    void updatePassword(@Param("id") Long id, @Param("password") String password);
    
    @Delete("DELETE FROM users WHERE id = #{id}")
    void deleteUser(Long id);
}

在上述示例中,User 类使用 @Entity 注解与数据库表进行映射。UserMapper 接口定义了与用户相关的数据库操作方法,并使用了不同的注解来映射 SQL 语句。

小贴士

  1. 使用注解开发可以简化 XML 配置文件的编写,提高开发效率。但需要注意,注解开发也有一些限制,例如无法实现复杂的动态 SQL 和复用 SQL 片段等。因此,在实际开发中,可以根据具体的需求和项目规模选择合适的开发方式(注解开发、XML 配置或混合使用),以达到最佳的开发效果和可维护性。

高级特性

缓存

在 MyBatis 中,缓存是一种机制,用于提高数据库查询性能和减少数据库访问的次数。MyBatis 提供了多级缓存的支持,包括一级缓存和二级缓存。

  1. 一级缓存:一级缓存是 MyBatis 默认开启的缓存机制,它是基于线程的缓存,每个 SqlSession 都有自己的一级缓存。当执行相同的查询语句时,如果查询条件相同,MyBatis 会先从一级缓存中查找结果,如果找到则直接返回,减少了数据库访问的次数。一级缓存的作用范围是同一个 SqlSession,在同一个 SqlSession 中执行相同的查询语句会命中缓存。

  2. 二级缓存:二级缓存是基于 SqlSessionFactory 的缓存,它可以被多个 SqlSession 共享。当不同的 SqlSession 执行相同的查询语句时,如果查询条件相同且命中了二级缓存,MyBatis 会直接从二级缓存中获取结果,避免了数据库的访问。二级缓存的作用范围是同一个 namespace 下的查询语句,在不同的 SqlSession 之间可以共享缓存。

配置和使用缓存的步骤如下:

  1. 开启缓存:在 MyBatis 的配置文件(mybatis-config.xml)中,设置 <setting> 元素的 cacheEnabled 属性为 true,开启缓存。

  2. 配置缓存:对于需要开启二级缓存的 Mapper 接口,需要在对应的 Mapper XML 文件中添加 <cache> 元素进行配置。可以设置缓存的策略、过期时间等属性。

  3. 标记查询语句:对于希望使用缓存的查询语句,需要在对应的 Mapper XML 文件中设置 <select> 元素的 useCache 属性为 true

通过合理配置和使用缓存,可以显著提高数据库查询性能,减少数据库访问的次数,特别是对于重复性的查询操作。但需要注意的是,在使用缓存时要注意缓存的更新策略和时机,避免数据不一致的问题。可以使用 flushCache="true" 来手动刷新缓存,或者使用 @CacheEvict 注解来配置缓存的清除操作。

批处理

在 MyBatis 中,批处理(Batch Processing)是一种执行批量操作的机制,可以在一次数据库访问中执行多个 SQL 语句,从而提高数据库操作的效率。MyBatis 提供了批处理的支持,可以通过批量插入、批量更新或批量删除等方式来处理大量数据的操作。

使用批处理的步骤如下:

  1. 开启批处理:在 MyBatis 的配置文件(mybatis-config.xml)中,设置 <setting> 元素的 defaultExecutorType 属性为 BATCH,或者在对应的 Mapper 接口方法上使用 @Options 注解指定 executorType 属性为 ExecutorType.BATCH,以开启批处理。

  2. 编写批处理操作:在 Mapper 接口中定义批处理的方法,可以是插入、更新或删除等操作。方法的参数可以是单个对象或对象列表。

  3. 执行批处理:通过 SqlSession 的 insertupdatedelete 方法执行批处理操作。可以传入对象列表或使用可迭代对象进行批量操作。

下面是一个批量插入的示例:

void insertUsers(List<User> userList);

在 Mapper 接口中定义了一个 insertUsers 方法,接收一个 User 对象列表作为参数。

使用批处理时,需要注意以下几点:

  • 数据库支持:批处理的可用性取决于所使用的数据库驱动程序和数据库本身。不是所有的数据库和数据库驱动程序都支持批处理操作,需要确保所使用的数据库和驱动程序支持批处理。

  • 批处理大小:可以通过设置 jdbc.batch.size 属性来指定批处理的大小,默认值为 100。可以根据具体的场景和性能需求来调整批处理大小。

  • 批处理提交:MyBatis 会根据批处理大小自动提交一部分操作,但需要注意在适当的时机进行提交,以避免内存溢出或长时间事务的问题。可以在方法执行完毕后手动提交事务。

通过合理使用批处理,可以有效减少数据库访问的次数,提高数据操作的效率。但需要根据具体的业务需求和数据规模来决定是否使用批处理,并进行适当的调整和优化。

插件

在 MyBatis 中,插件(Plugins)是一种可扩展的机制,可以在执行 SQL 语句的过程中进行拦截和增强操作。通过自定义插件,可以在 SQL 执行的各个阶段进行自定义处理,例如日志记录、性能监控、数据加解密等。

使用插件的步骤如下:

  1. 编写插件类:创建一个实现了 Interceptor 接口的插件类,该接口定义了插件的拦截方法。插件类需要实现 intercept 方法,在该方法中编写自定义的处理逻辑。

  2. 定义插件拦截的目标:通过 @Intercepts 注解或者实现 Interceptor 接口时传入的 @Signature 注解,指定插件要拦截的目标方法和参数类型。可以拦截的目标包括 Executor、StatementHandler、ParameterHandler 和 ResultSetHandler 等。

  3. 配置插件:在 MyBatis 的配置文件(mybatis-config.xml)中,使用 <plugins> 元素进行插件的配置。将插件类添加到 <plugins> 元素中,并指定插件的相关配置属性。

  4. 应用插件:在使用 MyBatis 的 Mapper 接口方法时,插件会自动拦截目标方法,并执行插件中定义的处理逻辑。

下面是一个简单的插件示例:

@Intercepts({
  @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class MyPlugin implements Interceptor {
  // 实现 intercept 方法,在方法中编写自定义的处理逻辑
  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    // 拦截目标方法的处理逻辑
    // ...
    return invocation.proceed(); // 继续执行目标方法
  }
  
  // 实现 plugin 方法,返回被拦截的对象的代理对象
  @Override
  public Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }
  
  // 实现 setProperties 方法,可以通过配置属性初始化插件
  @Override
  public void setProperties(Properties properties) {
    // 初始化插件的相关配置
  }
}

在上述示例中,MyPlugin 类实现了 Interceptor 接口,并通过 @Intercepts 注解指定了要拦截的目标方法。在 intercept 方法中编写了自定义的处理逻辑,然后使用 Plugin.wrap 方法创建被拦截对象的代理对象。最后,可以在 MyBatis 的配置文件中配置该插件。

通过自定义插件,可以对 MyBatis 的 SQL 执行过程进行拦截和增强,实现各种自定义的功能和处理逻辑。插件可以应用于日志记录、权限验证、性能监控等场景,提供了灵活的扩展机制。但需要注意插件的使用要遵循一定的原则和规范,确保插件的正确性和稳定性。

赞赏