MyBatis

回顾 JDBC开发

  1. 优点:简单易学,上手快, 非常灵活构建SQL,效率高
  2. 缺点:代码繁琐,难以写出高质量的代码(例如:资源的释放,SQL注入安全性等)。开发者既要写业务逻辑,又要管理对象的创建和销毁,同时必须关注底层数据库的语法。
  3. 适合超大批量数据操作,速度快

性能比较:jdbc > mybatis > hibernate > jpa

什么是 MyBatis,有什么特点

  1. MyBatis 结合了 JDBC 和 ORM 的优点,避免了各自的缺点,因此被广泛应用于企业中。
  2. MyBatis 的前身是 iBatis,原为 Apache 的开源项目,2010年迁移至 Google,并改名为 MyBatis。2013年移至 GitHub。
  3. iBATIS 一词来源于“internet”和“abatis”的组合,是基于 Java 的持久层框架,提供了 SQL Maps 和 DAO。
  4. 常见的持久层技术:
    • JDBC/Dbutils/springDAO
    • ORM框架:包括 MyBatis、Hibernate、JPA 等

1. 准备 Maven pom.xml

在 IntelliJ IDEA 中配置 pom.xml 引入类库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>

<dependencies>
<!-- 测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<!-- MySQL Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<!-- 日志库 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<!-- Log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
</dependencies>

2. 创建 POJO 实体类

使用 @Data 注解自动生成 getter、setter 和 toString 方法。

1
2
3
4
5
6
7
8
9
10
11
@Data // lombok类库 生成getter, setter, toString
public class Employee {
private Integer empno; // Integer=null, int=0
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double comm;
private Integer deptno;
}

3. 创建 mybatis-config.xml 配置文件

src/main/resources 目录下新建 mybatis-config.xml 文件。此文件包含 MyBatis 的核心配置,包括数据库连接、SQL Mapper 映射文件等。

  • 配置相关属性(可选):引入数据库连接信息。
  • 配置连接池环境:设定数据库连接和事务管理。
  • 注册 SQL Mapper 映射文件:定义 SQL Mapper 映射的 XML 文件。

mybatis-config.xml 配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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>
<!-- 加载外部的属性文件 -->
<properties resource="jdbc.properties"/>

<!-- 配置不同的数据库环境 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>

<!-- 注册 SQL Mapper 映射文件 -->
<mappers>
<!-- <mapper resource="org/mybatis/example/BlogMapper.xml"/> -->
</mappers>
</configuration>

jdbc.properties

1
2
3
4
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/scott?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root

<typeAliases> 类型别名

<typeAliases> 用于为 Java 类型设置简短的名字,帮助减少类的完全限定名,提升 XML 配置的可读性。

1
2
3
4
5
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<package name="org.glut.mybatismapper.entity"/>
</typeAliases>

<settings> 特性配置

<settings> 配置包含 MyBatis 中的一些重要调整选项,可以影响 MyBatis 的运行时行为。

1
2
3
4
<settings>
<setting name="logImpl" value="LOG4J"/>
<setting name="cacheEnabled" value="true"/>
</settings>

logImpl:指定日志的实现方式,LOG4J 表示使用 Log4j 日志框架。

cacheEnabled:全局二级缓存开关,true 表示启用二级缓存。此设置使映射器默认支持二级缓存。

4. 创建 SqlSessionFactory

使用 SqlSessionFactory 通过加载核心配置文件来创建实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSession sqlSession = sqlSessionFactory.openSession();
System.out.println(sqlSession.getConnection());

List list = sqlSession.selectList("名字空间 + 语句 ID");

} catch (IOException e) {
e.printStackTrace();
}
}

5. 编写 SQL 映射文件

MyBatis 使用 XML 文件编写 SQL 映射配置。以下是常用的 SQL 语句元素和动态 SQL 元素。

SQL 语句元素

  • <select>:查询语句
  • <insert>:插入语句
  • <update>:更新语句
  • <delete>:删除语句

动态 SQL 元素

  • <where>:用于生成动态 WHERE 子句
  • <if>:条件判断
  • <choose>:分支结构
  • <trim>:灵活地处理 SQL 语句中的逗号等
  • <foreach>:循环处理
  • <bind>:绑定变量

<mapper> 根元素

<mapper>namespace 通常是接口映射的全类名。在同一命名空间内,SQL 语句的 id 必须唯一。

<mapper> 配置示例

1
2
3
4
5
<?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="mapper.EmployeeMapper">
</mapper>

<select><where> 元素

<select> 用来编写 SELECT 语句,而 <where> 用于生成 WHERE 关键字,并自动添加必要的逻辑操作符。

<select> 配置示例

1
2
3
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
SELECT * FROM EMP WHERE EMPNO=#{empno,jdbcType=INTEGER}
</select>
  • id:定义该查询语句的唯一标识符。
  • parameterType:指定传入参数的 Java 类型。
  • resultMap:引用结果映射,定义如何将查询结果映射到 Java 对象。

<resultMap> 结果映射元素

<resultMap> 用于将查询结果集映射到实体类的属性中,以确保数据库字段与 Java 对象属性之间的正确对应关系。

<resultMap> 配置示例

1
2
3
4
<resultMap id="BaseResultMap" type="com.lanqiao.domain.Employee">
<id property="empno" column="empno" jdbcType="INTEGER"/>
<result property="ename" column="ename" jdbcType="VARCHAR"/>
</resultMap>
  • id:定义 resultMap 的唯一标识符,用于在 <select> 等元素中引用。
  • type:指定映射的目标 Java 类型(即结果映射的实体类)。
  • :映射主键字段。
    • property:实体类中的属性名。
    • column:数据库表中的列名。
    • jdbcType:指定该列的 JDBC 类型。
  • <result>:用于映射普通字段,propertycolumn 属性类似于 <id> 标签。

此示例将 empnoename 列映射到 Employee 类中的对应属性。

<association> 多对一、一对一关联映射

<association> 用于映射实体类中的多对一或一对一关系,通常用于定义一个实体类包含另一个关联实体类的情况(如一个员工属于一个部门)。

<association> 配置示例

1
2
3
4
5
6
<resultMap id="baseResultMap" type="Employee">
<association property="dept" javaType="Department">
<id property="deptno" column="DEPTNO" />
<result property="dname" column="DNAME"/>
</association>
</resultMap>
  • property:在父类(Employee)中表示关联对象的属性名(这里是 dept)。

  • javaType:关联对象的 Java 类型(如 Department)。

  • <id>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    :用于映射关联对象的主键字段。

    - `property`:关联对象(`Department`)中的主键属性名。
    - `column`:数据库中关联对象的主键列名。

    - `<result>`:用于映射关联对象中的其他字段。

    在此示例中,`Employee` 类包含一个 `Department` 对象,关系通过 `dept` 属性表示,其中 `deptno` 和 `dname` 分别映射到 `Department` 类的属性。

    ## `<collection>` 一对多关联映射

    `<collection>` 用于映射实体类中的一对多关系,适合映射一个实体类包含多个关联实体类的情况。例如,一个部门包含多个员工。

    ### `<collection>` 配置示例

    ```xml
    <resultMap id="baseResultMap" type="department">
    <collection property="employeeList" ofType="employee" column="deptno"
    resultMap="com.lanqiao.mapper.EmployeeMapper.baseResultMap">
    </collection>
    </resultMap>
  • property:在父类(Department)中表示关联集合的属性名(此处为 employeeList)。

  • ofType:集合中每个元素的 Java 类型(如 Employee 类)。

  • column:用于关联的数据库列名(此处为 deptno,表示员工表中的外键)。

  • resultMap:指定关联的 resultMap 配置,用于映射集合中的每个元素(如 Employee 对象)。

在此示例中,Department 类包含一个 employeeList 集合属性,关联多个 Employee 对象,通过 deptno 列进行一对多映射。

<sql> 通用 SQL 片段

<sql> 元素用于定义可复用的 SQL 片段,使得在多条 SQL 语句中可以共享相同的片段,避免重复代码。

<sql> 配置示例

1
2
3
<sql id="Base_Column_List">
empno, ename, job, mgr, hiredate, sal, comm, deptno
</sql>

可以在其他 SQL 语句中通过 <include> 元素来引用这个通用 SQL 片段:

<if> 元素

<if> 元素用于根据条件判断来动态生成 SQL 语句的一部分。在运行时,只有满足条件的 SQL 片段才会被加入到最终生成的 SQL 中。

<if> 配置示例<if>

1
2
3
4
5
6
7
8
<where>
<if test="ename != null">
AND ENAME LIKE #{ename}
</if>
<if test="job != null">
AND JOB = #{job}
</if>
</where>
  • test:条件表达式,只有当条件为真时,<if> 中的 SQL 片段才会被包含在最终生成的 SQL 语句中。

在此示例中,<where> 会动态生成 WHERE 子句,包含根据条件加入的 ENAMEJOB 字段的过滤条件。