Spring 整合MyBatis

原始的 MyBatis 开发步骤

  1. 建表
  2. 创建与表结构对应的实体类
  3. 在 MyBatis 配置文件中创建实体类的别名,方便在映射文件中使用
  4. 创建 DAO 层接口
  5. 编写映射文件实现接口
  6. 在 MyBatis 配置文件中注册映射文件
  7. 调用接口方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
public void test() {
// 获取 SqlSession
InputStream is = MyBatisTest.class.getClassLoader().getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();

// 获取接口的实现类对象,这个对象是 MyBatis 通过动态代理生成的实现类的对象
UserDao mapper = session.getMapper(UserMapper.class);

// 通过实现类对象调用接口的方法
try {
List<User> users = mapper.findAll();
for(User user : users) {
System.out.println(user);
}
} finally {
session.close();
}
}

可以看到,使用 MyBatis 原始的开发步骤会存在配置繁琐和代码冗余的问题,例如,需要配置大量的实体类别名,以及大量的 Mapper 文件注册,在执行接口中的方法之前需要先获取 SqlSessionFactoryBuilderSqlSessionFactorySqlSession 等对象,最后需要手动关闭 SqlSession

Spring 整合 MyBatis

总体思路

  1. 将 MyBatis 配置文件转移到 Sping 配置文件中,主要是解决连接池、实体类别名、注册 Mapper 文件的配置
  2. 封装获取 SqlSessionFactory 的系列代码

环境搭建

引入一下依赖,注意 Spring 整合 MyBatis 的相关 jar 包是由 MyBatis 给出的

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
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.43</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>

编码实现

转移配置文件

在配置文件中主要配置一下内容:

  1. 数据源信息,使用的连接池
  2. SqlSessionFactory 对象纳入 IOC 容器管理
  3. 实体类所在的包、Mapper 文件的路径、DAO 接口的路径
    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
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/cap?characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=Asia/Shanghai"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
    </bean>

    <!--创建SqlSessionFactory SqlSessionFactoryBean-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <!-- 指定实体类所在的包 -->
    <property name="typeAliasesPackage" value="com.yusael.entity"/>
    <!--指定映射文件的路径-->
    <property name="mapperLocations">
    <list>
    <value>classpath:cool/yzt/dao/*Mapper.xml</value>
    </list>
    </property>
    </bean>

    <!--创建DAO对象 MapperScannerConfigure-->
    <bean id="scanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
    <!--指定DAO接口放置的包-->
    <property name="basePackage" value="cool.yzt.dao"/>
    </bean>

    </beans>

使用

Spring 帮我们接管了 MyBatis 的很多操作,需要我们自己编码实现的内容有

  1. 数据库表

  2. 实体类

    1
    2
    3
    4
    5
    6
    public class User implements Serializable {
    private Integer id;
    private String name;
    private String password;
    // getter setter
    }
  3. DAO 接口

    1
    2
    3
    public interface UserDAO {
    public void insert(User user);
    }
  4. 映射文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?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="cool.yzt.dao.UserDAO">
    <insert id="insert">
    insert into user (name,passwprd) values(#{name}, #{password})
    </insert>
    </mapper>
  5. 在 Service 层调用 DAO 接口,这里以单元测试代替

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Test
    public void test() {
    // 获取工厂
    ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
    // 获取DAO接口的代理实现类对象
    UserDAO userDAO = (UserDAO) ctx.getBean("userDAO");
    User user = new User();
    user.setName("xiaojr");
    user.setPassword("999999");
    // 执行insert操作
    userDAO.insert(user);
    }

细节问题

Spring 与 Myabatis 整合后,为什么 DAO 不提交事务,但是数据能够插入数据库中?

  • 可以这样说,谁控制了 Connection 谁就控制了事务
  • 在此之前,使用 MyBatis 提供的连接池获取 Connection,底层 Connection.setAutoCommit(false),需要手动提交
  • 我们选择外部的 Druid(C3P0、DBCP)作为连接池,所有的连接都是从连接池获得,也就是说连接池控制着 Connection 和事务,底层 Connection.setAutoCommit(true),一条 SQL 完成自动提交,不需要手动提交事务
  • 在实战中,对于多条增删改语句的执行,我们依然会手动控制事务的提交和回滚,而 Spring 为我们提供了事务控制的解决方案

参考

孙哥说Spring5