概述
MyBatis是一种轻量级的Java持久层
框架,它提供了简单而强大的数据库访问功能,帮助开发者将Java对象与数据库之间进行映射和交互。
- ORM(对象关系映射):MyBatis采用ORM的思想,将数据库表和Java对象之间建立映射关系。通过配置和编写SQL映射文件,开发者可以直接使用Java对象来操作数据库,而无需手动编写大量的JDBC代码。
- 核心组件:
- SqlSessionFactory:SqlSessionFactory是MyBatis的核心接口,负责创建和管理SqlSession对象。它是单个数据库映射关系的工厂类,通过它可以获取SqlSession对象来执行SQL操作。
- SqlSession:SqlSession是与数据库交互的会话对象,它提供了执行SQL语句、获取映射器(Mapper)和管理事务的方法。
- Mapper接口:Mapper接口定义了与数据库交互的方法,通过编写Mapper接口的方法以及对应的XML配置文件,可以实现Java方法和SQL语句的映射关系。
作用
MyBatis的作用是简化和优化Java应用程序与数据库之间的交互过程。它提供了以下主要功能和作用:
-
数据库访问:MyBatis使得数据库的访问变得简单和高效。通过编写SQL映射文件和Mapper接口,开发者可以使用面向对象的方式执行数据库操作,包括插入、更新、删除和查询等常见操作。
-
对象关系映射(ORM):MyBatis实现了数据库表和Java对象之间的映射关系,通过配置和映射文件,可以将查询结果自动映射到Java对象中。这使得开发者可以使用面向对象的方式操作数据,而无需手动编写JDBC代码。
-
灵活的SQL编写:MyBatis提供了灵活的SQL编写方式,支持静态SQL和动态SQL。开发者可以在SQL映射文件中编写SQL语句,通过使用条件判断、循环和参数绑定等功能,可以动态构建SQL语句,满足各种复杂的查询需求。
-
缓存支持:MyBatis内置了缓存机制,可以将查询结果缓存起来,提高查询性能。通过配置和合理使用缓存,可以减少数据库的访问次数,加快应用程序的响应速度。
-
事务管理:MyBatis提供了事务管理的支持,开发者可以通过SqlSession来管理事务。MyBatis可以与Spring等框架集成,实现声明式事务管理,保证数据库操作的原子性和一致性。
-
扩展性和插件: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实例。
安装配置
-
引入MyBatis依赖:在您的Java项目中,需要将MyBatis作为依赖添加到项目的构建文件(如Maven或Gradle)中。您可以从Maven中央存储库或MyBatis官方网站获取最新的MyBatis依赖。
-
创建MyBatis配置文件:在项目的资源目录下创建一个名为
mybatis-config.xml
的文件,用于配置MyBatis的各种设置。 -
配置数据源:在
mybatis-config.xml
文件中配置数据库连接信息和连接池。您可以使用MyBatis提供的内置连接池(如PooledDataSource),或者使用第三方的连接池库(如Druid或HikariCP)。 -
创建SQL映射文件(Mapper):创建一个或多个XML文件,用于定义SQL语句和与之对应的映射关系。这些文件通常与数据库表或Java对象相关联。
-
配置SQL映射文件:在
mybatis-config.xml
文件中配置SQL映射文件的路径,以便MyBatis可以找到并加载它们。您可以使用相对路径或绝对路径,确保文件能够正确加载。 -
创建SqlSessionFactory:使用
mybatis-config.xml
文件的配置信息,通过编程方式创建SqlSessionFactory
实例。可以使用SqlSessionFactoryBuilder
类来构建SqlSessionFactory
。 -
获取SqlSession:使用
SqlSessionFactory
创建SqlSession
对象。SqlSession
是与数据库交互的会话对象,它提供了执行SQL语句、获取映射器(Mapper)和管理事务的方法。 -
编写Mapper接口:创建Java接口,定义与数据库交互的方法。每个方法对应于一个SQL语句。可以使用注解或XML文件来配置方法与SQL语句的映射关系。
-
执行数据库操作:使用
SqlSession
通过调用Mapper接口的方法执行数据库操作。MyBatis将根据配置的映射关系执行对应的SQL语句,并将结果映射到Java对象中。
当安装和配置MyBatis时,涉及的配置文件和代码如下所示:
- 创建
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>
- 创建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>
- 创建Mapper接口
MyMapper.java
(示例内容):
package com.example.mappers;
import com.example.models.MyModel;
public interface MyMapper {
MyModel getById(int id);
void insert(MyModel model);
// 其他方法声明
}
- 创建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 提供的一些特性来实现。下面是详细讲解如何在插入操作中返回添加数据的主键:
-
在 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
属性。 -
在 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 方法。 -
在执行插入操作后,通过获取
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
具有以下结构和常用配置项:
-
根元素
<configuration>
:表示配置文件的根元素,包含了整个配置的内容。 -
<properties>
元素:用于定义属性,可以在配置文件中引用这些属性。常用的子元素有:<property>
:定义一个属性,包括name
和value
两个属性,用于设置属性的名称和值。
-
<settings>
元素:配置全局设置选项,用于影响 MyBatis 的运行时行为。常用的设置项有:<setting>
:用于设置具体的选项,包括name
和value
两个属性。cacheEnabled
:是否启用缓存,默认值为true
。lazyLoadingEnabled
:是否启用延迟加载,默认值为false
。mapUnderscoreToCamelCase
:是否开启自动驼峰命名规则映射,默认值为false
。
-
<typeAliases>
元素:用于配置类型别名,简化映射器中的类型引用。常用的子元素有:<typeAlias>
:用于定义一个类型别名,包括type
和alias
两个属性,分别指定类型和别名。
-
<typeHandlers>
元素:配置类型处理器,用于处理 Java 类型与数据库类型之间的转换。常用的子元素有:<typeHandler>
:用于配置具体的类型处理器,可以指定 Java 类型和对应的处理器类。
-
<objectFactory>
元素:配置对象工厂,用于创建映射器中的结果对象。常用的子元素有:<property>
:用于配置对象工厂的属性。
-
<plugins>
元素:用于配置插件,可以在 MyBatis 的执行过程中添加自定义的功能扩展。常用的子元素有:<plugin>
:用于配置具体的插件,需要指定插件的实现类。
-
<environments>
元素:配置 MyBatis 的环境,包括事务管理器和数据源。常用的子元素有:<environment>
:定义一个具体的环境,包含事务管理器和数据源配置。<transactionManager>
:配置事务管理器的类型。<dataSource>
:配置数据源的类型和相关属性。
-
<databaseIdProvider>
元素:用于根据数据库厂商标识(databaseId)选择不同的语句。常用的子元素有:<property>
:用于配置数据库厂商标识和对应的语句。
-
<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>
-
数据源配置:
<environments>
元素用于配置MyBatis的环境,包含多个<environment>
子元素,可用于定义多个环境,例如development
、production
等。<environment>
元素用于定义一个具体的环境,包括事务管理器和数据源配置。<transactionManager>
元素用于指定事务管理器的类型,常见的类型有:JDBC
:使用JDBC事务管理器,适用于单个数据库的场景。MANAGED
:使用容器管理的事务,例如Java EE容器管理的事务。
<dataSource>
元素用于配置数据源的类型,常用的类型有:POOLED
:使用连接池管理数据库连接,通过配置属性如driver
、url
、username
、password
等来连接数据库。UNPOOLED
:不使用连接池,每次请求都会创建新的数据库连接。JNDI
:使用Java命名和目录接口(JNDI)获取数据源。
-
映射器配置:
<mappers>
元素用于配置映射器,可以通过多种方式加载映射器。<mapper resource="com/example/mappers/MyMapper.xml" />
用于通过路径加载映射器,指定映射器文件的路径。<mapper class="com.example.mappers.OtherMapper" />
用于通过类加载映射器,指定映射器接口的类名。<package name="com.example.mappers" />
用于通过包扫描加载映射器,指定包的路径,MyBatis将扫描包路径下的映射器接口。
-
缓存配置:
<settings>
元素用于配置全局设置选项。<setting name="cacheEnabled" value="true" />
用于开启或关闭缓存,默认为true
。- MyBatis提供多种缓存实现,包括本地缓存、二级缓存等,可根据需要进行配置。
-
延迟加载配置:
<settings>
元素中的<setting name="lazyLoadingEnabled" value="false" />
用于开启或关闭延迟加载,默认为false
。- 当开启延迟加载时,MyBatis将延迟加载关联对象的属性,直到访问该属性时才进行加载。
-
命名规则映射配置:
<settings>
元素中的<setting name="mapUnderscoreToCamelCase" value="false" />
用于开启或关闭自动驼峰命名规则映射,默认为false
。- 当开启自动驼峰命名规则映射时,MyBatis会自动将数据库列名的下划线命名转换为Java对象的驼峰命名属性。
-
日志配置:
<settings>
元素中的<setting name="logImpl" value="LOG4J" />
用于设置日志实现类。- MyBatis支持多种日志实现,可根据项目使用的日志框架进行配置,如
LOG4J
、SLF4J
、STDOUT_LOGGING
等。
基本使用
-
定义数据模型(Model):
- 创建一个Java类,用于表示数据库表中的一行数据。
- 在类中定义与表中列对应的属性,并提供相应的getter和setter方法。
-
编写映射器(Mapper):
- 创建一个映射器接口,用于定义数据库操作的方法。
- 在接口中定义与数据库操作相对应的方法,并使用注解或XML配置SQL语句。
-
配置MyBatis:
- 创建
mybatis-config.xml
配置文件,配置数据源、映射器等相关设置。 - 在配置文件中指定映射器的位置,可以通过XML文件路径、类路径或包扫描等方式加载映射器。
- 创建
-
使用MyBatis进行数据库操作:
- 获取
SqlSessionFactory
对象,它是MyBatis的核心对象,负责创建SqlSession
对象。 - 通过
SqlSession
对象,调用映射器接口中的方法执行数据库操作。
- 获取
SQL映射文件(Mapper)
概述
SQL映射文件(Mapper)是MyBatis中定义数据库操作的地方。它包含了SQL语句和映射器接口方法之间的映射关系。
-
创建SQL映射文件:
- 创建一个以
.xml
为后缀的文件,用于存放SQL语句和映射关系。 - 可以将SQL映射文件放置在类路径下的任意位置,例如
resources
目录。
- 创建一个以
-
定义命名空间:
- 在SQL映射文件的根元素上,使用
namespace
属性定义一个命名空间,用于唯一标识该映射文件。 - 命名空间的值通常是映射器接口的完全限定名,例如
com.example.mappers.UserMapper
。
- 在SQL映射文件的根元素上,使用
-
编写SQL语句:
- 使用合适的SQL元素(如
<select>
、<insert>
、<update>
、<delete>
)编写SQL语句。 - 在SQL元素中,使用
${}
或#{}
来引用参数或属性。
- 使用合适的SQL元素(如
-
配置映射器接口方法:
- 在SQL映射文件中,通过与映射器接口中的方法相对应,建立方法与SQL语句之间的映射关系。
- 使用合适的SQL元素来定义SQL语句,并使用
id
属性指定映射器接口中的方法名。
-
使用参数:
- 在SQL语句中,可以使用
${}
和#{}
两种方式来引用参数。 ${}
会将参数的值直接替换到SQL语句中,可能会有SQL注入的风险
。#{}
会将参数作为预编译参数进行处理,更加安全。
- 在SQL语句中,可以使用
-
处理结果集:
- 使用
<resultMap>
元素定义结果集的映射关系,将查询结果的列与映射器接口方法返回类型中的属性进行映射。 - 使用
<result>
元素定义列和属性的映射关系。 - 使用
<association>
和<collection>
元素处理一对一和一对多的关联关系。
- 使用
-
配置其他元素:
- 可以在SQL映射文件中配置其他元素,如动态SQL、参数类型处理器、缓存等。
-
配置映射器:
- 在
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 的转义字符来处理。以下是常见的几个特殊字符及其对应的转义字符:
<
(小于号):使用<
表示。>
(大于号):使用>
表示。&
(和号):使用&
表示。"
(双引号):使用"
表示。'
(单引号):使用'
表示。
例如,如果你的 SQL 语句中包含一个 <
符号,你可以使用 <
替代它。
下面是一个示例,展示如何在 Mapper XML 文件中处理特殊字符:
<select id="getUserByName" resultType="com.example.User">
SELECT * FROM users WHERE name = '<John>'
</select>
在上述示例中,SQL 语句中的特殊字符 <
和 >
被转义为 <
和 >
。这样可以确保 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
属性,用于指定判断条件。
例如,如果传入了 name
和 age
参数,但没有传入 email
参数,则生成的 SQL 语句将只包含 name
和 age
条件的部分。
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 语句部分。
例如,如果传入了 name
和 age
参数,但没有传入 email
参数,则生成的 SQL 语句将只包含 name
和 age
条件的部分。
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
属性指定了要遍历的集合或数组,open
、separator
、close
属性用于指定拼接 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 语句。
例如,如果传入了 name
和 age
参数,则生成的 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 类型参数以及使用注解等方式。
下面是几种常见的参数传递方式:
-
单个参数:可以直接将单个参数传递给 SQL 语句,例如:
List<User> getUserList(String name);
在上述示例中,单个参数
name
会被传递给 SQL 语句,并在 SQL 语句中使用。 -
多个参数:可以使用
@Param
注解来标记多个参数,并在 SQL 语句中使用这些参数,例如:List<User> getUserList(@Param("name") String name, @Param("age") int age);
在上述示例中,使用
@Param
注解标记了两个参数name
和age
,并在 SQL 语句中使用它们。 -
Map 类型参数:可以将参数封装为一个 Map 对象,然后将 Map 对象传递给 SQL 语句,例如:
List<User> getUserList(Map<String, Object> paramMap);
在上述示例中,参数被封装为一个 Map 对象
paramMap
,其中键为参数名,值为参数值。在 SQL 语句中使用参数时,可以通过键来获取对应的值。 -
使用注解:可以使用 MyBatis 的注解方式来指定参数传递,例如
@Param
注解、@ParamMap
注解等。具体使用方式可参考 MyBatis 的注解文档。
在 SQL 语句中引用参数时,可以使用 ${}
或 #{}
语法来获取参数值。其中 ${}
使用的是直接替换的方式,而 #{}
使用的是预编译的方式,可以有效防止 SQL 注入攻击,并自动进行类型转换和特殊字符的处理。
小贴士
- 参数的命名在 SQL 语句中要与参数对象的属性或者注解中的名称一致,这样 MyBatis 才能正确地映射参数值。
结果集处理
在 MyBatis 中,结果集处理是指将数据库返回的查询结果映射到 Java 对象或其他数据结构的过程。MyBatis 提供了多种方式来处理结果集,包括自动映射、手动映射和使用结果集映射器。
下面是几种常见的结果集处理方式:
-
自动映射:MyBatis 提供了自动将查询结果集映射到 Java 对象的功能。它会根据查询结果集的列名与 Java 对象的属性名进行自动匹配,并将结果集中的数据赋值给对象的属性。要使用自动映射,可以在 SQL 映射文件(Mapper XML)中使用
resultType
属性指定结果对象的类型,或者使用注解方式指定结果对象的类型。 -
手动映射:如果查询结果集的列名与 Java 对象的属性名不完全匹配,或者需要进行复杂的映射操作,可以使用手动映射方式。手动映射需要在 SQL 映射文件中使用
<resultMap>
元素定义结果集的映射关系,将查询结果的列与映射器接口方法返回类型中的属性进行手动映射。 -
使用结果集映射器:MyBatis 还提供了结果集映射器(ResultMap)的功能,可以在 XML 配置文件中定义复杂的映射关系,包括一对一关联、一对多关联等。结果集映射器可以通过
<resultMap>
元素定义,然后在 SQL 映射文件中引用该结果集映射器,进行结果集的映射处理。
无论使用哪种方式进行结果集处理,都可以通过在 SQL 映射文件中编写相应的配置来指定映射关系,包括列名与属性名的映射、关联关系的映射等。具体的映射配置会根据查询的需求和结果的数据结构而有所不同。
通过 <resultMap>
元素来定义结果集的映射关系,将查询结果的列与映射器接口方法返回类型中的属性进行映射。同时,使用 <result>
元素定义列和属性的映射关系,以及 <association>
和 <collection>
元素处理一对一和一对多的关联关系。
以下是对处理结果集的详细讲解:
-
<resultMap>
元素:<resultMap>
元素用于定义结果集的映射关系。- 通过
id
属性指定<resultMap>
的唯一标识符。 - 使用
type
属性指定映射器接口方法的返回类型。 - 通过
<resultMap>
的子元素<result>
、<association>
和<collection>
来定义具体的映射关系。
-
<result>
元素:<result>
元素用于定义列和属性的映射关系。- 使用
column
属性指定查询结果的列名。 - 使用
property
属性指定映射器接口方法返回类型中的属性名。 - 可以使用
javaType
属性指定属性的 Java 类型。 - 可以使用
jdbcType
属性指定列的 JDBC 类型。
-
<association>
元素:<association>
元素用于处理一对一的关联关系。- 使用
property
属性指定映射器接口方法返回类型中的属性名。 - 使用
javaType
或resultMap
属性指定关联对象的类型或关联对象的映射关系。
-
<collection>
元素:<collection>
元素用于处理一对多的关联关系。- 使用
property
属性指定映射器接口方法返回类型中的属性名。 - 使用
ofType
或resultMap
属性指定集合元素的类型或集合元素的映射关系。
下面是一个包含 <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 接口或方法进行关联,使得代码更加紧凑和易于理解。
以下是注解开发的一般步骤:
-
创建实体类:创建一个 Java 类来表示数据库中的表,可以使用
@Entity
注解将其与数据库表进行映射。 -
创建 Mapper 接口:创建一个接口,其中定义了与数据库交互的方法。使用注解来标记接口中的方法与 SQL 语句的对应关系。可以使用
@Select
、@Insert
、@Update
、@Delete
注解等,分别对应查询、插入、更新和删除操作。 -
配置 MyBatis:在 MyBatis 的配置文件(
mybatis-config.xml
)中,需要配置将注解进行扫描的相关设置。通过<mappers>
元素和<package>
元素指定要扫描的 Mapper 接口所在的包。 -
使用注解开发:在 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 语句。
小贴士
- 使用注解开发可以简化 XML 配置文件的编写,提高开发效率。但需要注意,注解开发也有一些限制,例如无法实现复杂的动态 SQL 和复用 SQL 片段等。因此,在实际开发中,可以根据具体的需求和项目规模选择合适的开发方式(注解开发、XML 配置或混合使用),以达到最佳的开发效果和可维护性。
高级特性
缓存
在 MyBatis 中,缓存是一种机制,用于提高数据库查询性能和减少数据库访问的次数。MyBatis 提供了多级缓存的支持,包括一级缓存和二级缓存。
-
一级缓存:一级缓存是 MyBatis 默认开启的缓存机制,它是基于线程的缓存,每个 SqlSession 都有自己的一级缓存。当执行相同的查询语句时,如果查询条件相同,MyBatis 会先从一级缓存中查找结果,如果找到则直接返回,减少了数据库访问的次数。一级缓存的作用范围是同一个 SqlSession,在同一个 SqlSession 中执行相同的查询语句会命中缓存。
-
二级缓存:二级缓存是基于 SqlSessionFactory 的缓存,它可以被多个 SqlSession 共享。当不同的 SqlSession 执行相同的查询语句时,如果查询条件相同且命中了二级缓存,MyBatis 会直接从二级缓存中获取结果,避免了数据库的访问。二级缓存的作用范围是同一个 namespace 下的查询语句,在不同的 SqlSession 之间可以共享缓存。
配置和使用缓存的步骤如下:
-
开启缓存:在 MyBatis 的配置文件(mybatis-config.xml)中,设置
<setting>
元素的cacheEnabled
属性为true
,开启缓存。 -
配置缓存:对于需要开启二级缓存的 Mapper 接口,需要在对应的 Mapper XML 文件中添加
<cache>
元素进行配置。可以设置缓存的策略、过期时间等属性。 -
标记查询语句:对于希望使用缓存的查询语句,需要在对应的 Mapper XML 文件中设置
<select>
元素的useCache
属性为true
。
通过合理配置和使用缓存,可以显著提高数据库查询性能,减少数据库访问的次数,特别是对于重复性的查询操作。但需要注意的是,在使用缓存时要注意缓存的更新策略和时机,避免数据不一致的问题。可以使用 flushCache="true"
来手动刷新缓存,或者使用 @CacheEvict
注解来配置缓存的清除操作。
批处理
在 MyBatis 中,批处理(Batch Processing)是一种执行批量操作的机制,可以在一次数据库访问中执行多个 SQL 语句,从而提高数据库操作的效率。MyBatis 提供了批处理的支持,可以通过批量插入、批量更新或批量删除等方式来处理大量数据的操作。
使用批处理的步骤如下:
-
开启批处理:在 MyBatis 的配置文件(mybatis-config.xml)中,设置
<setting>
元素的defaultExecutorType
属性为BATCH
,或者在对应的 Mapper 接口方法上使用@Options
注解指定executorType
属性为ExecutorType.BATCH
,以开启批处理。 -
编写批处理操作:在 Mapper 接口中定义批处理的方法,可以是插入、更新或删除等操作。方法的参数可以是单个对象或对象列表。
-
执行批处理:通过 SqlSession 的
insert
、update
、delete
方法执行批处理操作。可以传入对象列表或使用可迭代对象进行批量操作。
下面是一个批量插入的示例:
void insertUsers(List<User> userList);
在 Mapper 接口中定义了一个 insertUsers
方法,接收一个 User 对象列表作为参数。
使用批处理时,需要注意以下几点:
-
数据库支持:批处理的可用性取决于所使用的数据库驱动程序和数据库本身。不是所有的数据库和数据库驱动程序都支持批处理操作,需要确保所使用的数据库和驱动程序支持批处理。
-
批处理大小:可以通过设置
jdbc.batch.size
属性来指定批处理的大小,默认值为 100。可以根据具体的场景和性能需求来调整批处理大小。 -
批处理提交:MyBatis 会根据批处理大小自动提交一部分操作,但需要注意在适当的时机进行提交,以避免内存溢出或长时间事务的问题。可以在方法执行完毕后手动提交事务。
通过合理使用批处理,可以有效减少数据库访问的次数,提高数据操作的效率。但需要根据具体的业务需求和数据规模来决定是否使用批处理,并进行适当的调整和优化。
插件
在 MyBatis 中,插件(Plugins)是一种可扩展的机制,可以在执行 SQL 语句的过程中进行拦截和增强操作。通过自定义插件,可以在 SQL 执行的各个阶段进行自定义处理,例如日志记录、性能监控、数据加解密等。
使用插件的步骤如下:
-
编写插件类:创建一个实现了
Interceptor
接口的插件类,该接口定义了插件的拦截方法。插件类需要实现intercept
方法,在该方法中编写自定义的处理逻辑。 -
定义插件拦截的目标:通过
@Intercepts
注解或者实现Interceptor
接口时传入的@Signature
注解,指定插件要拦截的目标方法和参数类型。可以拦截的目标包括 Executor、StatementHandler、ParameterHandler 和 ResultSetHandler 等。 -
配置插件:在 MyBatis 的配置文件(mybatis-config.xml)中,使用
<plugins>
元素进行插件的配置。将插件类添加到<plugins>
元素中,并指定插件的相关配置属性。 -
应用插件:在使用 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 执行过程进行拦截和增强,实现各种自定义的功能和处理逻辑。插件可以应用于日志记录、权限验证、性能监控等场景,提供了灵活的扩展机制。但需要注意插件的使用要遵循一定的原则和规范,确保插件的正确性和稳定性。