回顾MyBatis
1.在 Maven 中导入 MyBatis 需要的依赖
<dependencies>
<!--Mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!--MyBatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!--junit-->
<!--Junit单元测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.2</version>
<scope>test</scope>
</dependency>
</dependencies>
这些是 MyBatis 需要的依赖,还没有涉及到 Spring。
2.创建配置文件 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/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="0723"/>
</dataSource>
</environment>
</environments>
</configuration>
这里就不用 db.properties 文件获取属性了,后面这个工作要交给 Spring 了。
3.创建 MyBatis 工具类
public class MyBatisUtil {
// 提升作用域
private static SqlSessionFactory sqlSessionFactory;
static {
try {
// 使用MyBatis第一步:获取SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
// 从SqlSessionFactory中获取SqlSession
public static SqlSession getSqlSession(){
// sqlSession 其实类似于 connection
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
}
基本的统一配置就完成了,下面就是对应数据库编写实体类和对应的 Mapper 了。
4.编写实体类 User,属性对应数据库中的字段
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
private int id;
private String name;
private String pwd;
}
5.写完实体类,就要写对应的 Dao 层接口,即 UserMapper,放在 dao(或mapper) 包下
package com.qiyuan.dao;
...
public interface UserMapper {
// 查询全部用户
List<User> getUserList();
}
6.有了接口,就要有其对应的实现,即 UserMapper.xml,这里和 UserMapper接口放在同一包下(要记得让 Maven 能导出嗷)
<?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">
<!--命名空间namespace要绑定一个对应的Dao/Mapper接口,相当于实现它-->
<mapper namespace="com.qiyuan.dao.UserMapper">
<!--select查询语句,使用别名记得配置 typeAlias -->
<select id="getUserList" resultType="User">
select * from user
</select>
</mapper>
这里用到了别名,要在 mybatis-config.xml 中配置
<typeAliases>
<package name="com.baifu.pojo"/>
</typeAliases>
7.然后在 mybatis-config.xml 中注册映射 mapper
<mappers>
<!--要求接口和其对应的 XML 名字相同,且在同一个包下-->
<mapper class="com.baifu.mapper.UserMapper"/>
</mappers>
直接用 class 方式注册绑定,比较简洁,不过要求接口和其对应的 XML 名字相同,且在同一个包下。
8.执行测试方法
public class MyTest {
@Test
public void getUserListTest(){
// 不写注释了,看不懂入土吧!
SqlSession sqlSession = MyBatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
}
运行发信报错:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.baifu.mapper.UserMapper.getUserList
在“target-classes-com-baifu-mapper”下没有找到UserMapper.xml,**配置 Maven 以让 java 文件夹中的 xml 文件能成功导出!**在 pom.xml 中添加
<build>
<resources>
<!--让java目录下的properties和xml文件也能被导出-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
最基础的 MyBatis 应用就完成了,接下来引入 Spring。
MyBatis-Spring
通过 Spring 使用 MyBatis 有两种方式:使用 SqlSessionTemplate 和使用 SqlSessionDaoSupport。
1.导入依赖
要将 MyBatis 和 Spirng 结合起来,除了导入上面 MyBatis 的依赖,当然还要有 Spring 的依赖
<dependencies>
<!--上面 MyBtais 的包-->
...
<!-- Spring 框架 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
<!-- AOP -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
<!-- Spring 管理 JDBC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.9</version>
</dependency>
<!-- mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
</dependencies>
注意这里相比之前的 Spring 项目,多了 spring-jdbc 和 mybatis-spring 的包,前者用于 Spring 管理数据库,后者作用就是是将 MyBatis 和 Spring 结合起来。
什么是 MyBatis-Spring?
MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException。 最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。
2.使用SqlSessionTemplate
SqlSessionTemplate 是 MyBatis-Spring 的核心。作为 SqlSession 的一个实现,这意味着可以使用它无缝代替你代码中已经在使用的 SqlSession。 SqlSessionTemplate 是线程安全的,可以被多个 DAO 或映射器所共享使用。
通过 Spring 去使用 MyBatis 的步骤为
-
创建 spring-dao.xml 配置文件(任意名,其实就是Spring的applicationContext.xml文件),管理数据库的配置,也相当于 MyBatisUtil 工具类
配置数据源 dataSource
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--data source--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://111.230.212.103:3306/mybatis?userSSL=true& userUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="hsp"/> </bean> </beans>
在 Spring 中配置了数据源,mybatis-config 中的就可以删掉了
<!-- mybatis-config.xml --> <environments default="..."> <!--用不到了,删了吧!--> </environments>
-
在上边创建的spring-dao.xml 配置文件中创建 sqlSessionFactory 的 bean,同时设置数据源 dataSource 属性为上面配置的数据源,设置 configLocation 属性以绑定 MyBatis 配置文件
<!-- sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!--绑定 MyBatis 配置文件!--> <property name="configLocation" value="classpath:mybatis-config.xml"/> </bean>
这里相当于 MyBatisUtil 工具类中的获取 SqlSessionFactory 实例!
public class MyBatisUtil { private static SqlSessionFactory sqlSessionFactory; static { try { // 使用MyBatis第一步:获取SqlSessionFactory对象 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } ... }
-
在 sqlSessionFactory 的 bean 中也可以配置其属性,和在 mybatis-config 中配置是一样的!如注册 Mapper
<!-- sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> ... <!--如,在这里注册 Mapper --> <property name="mapperLocations" value="classpath:com/baifu/mapper/*.xml"/> </bean>
这里就用到之前 MyBatis 中不能用的通配符了,因为**通配符是由 Spring 提供**的! 在 bean 中配置了,mybatis-config 中配置的 mapper 也可以删掉了。
<!-- mybatis-config.xml --> <mappers> <!--不用了!--> </mappers>
这样一来,mybatis-config.xml 中几乎已经没有内容了(还剩一个别名 typeAlias ),虽然别名也能在 bean 中配置,不过最好将别名 typeAlias 和设置 settings 放在 mybatis-config.xml 中,方便查看和修改
<!--仅存的 mybatis-conifg 内容--> <?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> <typeAliases> <package name="com.baifu.pojo"/> </typeAliases> </configuration>
-
有了配置好的 sqlSessionFactory 后,就可以用它获取 sqlSession了。
创建 sqlSession 的 bean,注入 sqlSessionFactory 依赖
<!-- SqlSessionTemplate 就是 SqlSession!--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!--只能用构造器注入,因为它没有 set 方法!--> <!-- 把工厂给它,就能从中 get 到 SqlSession 了--> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean>
SqlSessionTemplate 类只能通过构造器注入 sqlSessionFactory 依赖,这就是一个 SqlSession 了。
-
重点来了!由于面向对象的思想,要把对象交给 Spring 管理,而之前使用 MyBatis 时,Mapper.xml 充当了接口的实现类,这个实现类无法让 Spring 管理,所以要写一个真正的接口实现类,封装 Mapper.xml,交给 Spring 管理!
创建 UserMapperImpl 类,实现了 UserMapper 接口,即有对数据库操作的方法
public class UserMapperImpl implements UserMapper{ // 原来的操作,使用 SqlSession 实现,现在使用 SqlSessionTemplate // 不过还是叫做 sqlSession 亲切! private SqlSessionTemplate sqlSession; // 添加 set 方法,以注入属性 public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } // 在这里进行封装! public List<User> getUserList() { // IoC 的思想!不用去 new 一个 sqlSession 了,注入后就能用! UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userList = mapper.getUserList(); return userList; } }
其中,有一个属性 sqlSession(变成了 SqlSessionTemplate 也是一样用法)及其对应的 set 方法,通过 Spring 依赖注入后就能使用,相当于之前的
SqlSession sqlSession = MyBatisUtil.getSqlSession(); // 关闭应该是由 Spring 管理的吧...
在这个“真”实现类( UserMapperImpl 类)中调用了“假”实现类( UserMapper.xml )的方法,相当于多了一层封装,也变成了一个真实存在的类,方便 Spring 管理!
-
把真实现类交给 Spring 管理,同时进行依赖注入
<bean id="userMapper" class="com.baifu.mapper.UserMapperImpl"> <!--注入 sqlSession!--> <property name="sqlSession" ref="sqlSession"/> </bean>
这时,获取 userMapper 对象后执行其中的方法,就会到 UserMapper.xml 执行对应的语句,和之前区别不大,只是多了一层封装以方便管理!
-
方法测试
public class MyTest { @Test public void MyBatisSpringTest(){ ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); List<User> userList = userMapper.getUserList(); for (User user : userList) { System.out.println(user); } } } // 执行结果 /* User(id=1, name=www, pwd=99999) User(id=2, name=baifu, pwd=6666) User(id=3, name=李四, pwd=123890) */
优化:可以注意到,大部分配置都在 spring-dao.xml 文件中,这个文件做了几件事
- 配置数据源,即连接数据库的一些配置( mybatis-config.xml 中的 environment 部分)
- 创建 sqlSessionFactory 的 bean,进行依赖注入( mybatis-config.xml 中的 mapper 部分,MyBatisUtil 的创建 sqlSessionFactory 部分)
- 创建 sqlSession 的 bean,将 sqlSessionFactory 注入进去( MyBatisUtil 中的 sqlSessionFactory.openSession )
- 创建真实现类 UserMapperImpl 的 bean,为其注入 sqlSession
其中,第1、2、3步都是配置和工具类干的事情,属于改动比较少的部分;而第4步属于会经常会进行的步骤,如增加 StudentMapperImpl、TeacherMapperImpl 等的 bean。
所以将第4步这种配置抽出来,留下1、2、3步,使得 spring-dao.xml 变成了一个比较纯洁的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 用 Spring 的数据源 替换 MyBatis 的数据源 -->
<!--data source-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="hsp"/>
</bean>
<!-- sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--绑定 MyBatis 配置文件!-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--如,在这里注册 Mapper -->
<property name="mapperLocations" value="classpath:com/baifu/mapper/UserMapper.xml"/>
</bean>
<!-- SqlSessionTemplate 就是 SqlSession!-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能用构造器注入,因为它没有 set 方法!-->
<!-- 把工厂给它,就能从中 get 到 SqlSession 了-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
至于第4步这种操作,创建了一个要具体用到的对象,还是放到 applicationContext.xml 中进行管理吧!
创建 applicationContext.xml,通过 import 标签引入 spring-dao.xml,把真正要用到的对象,即 userMapper 交给它管理
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--通过 import 标签引入 spring-dao.xml -->
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.baifu.mapper.UserMapperImpl">
<!--注入 sqlSession!-->
<property name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
测试时记着更改配置文件由于spring-dao.xml—>applicationContext.xml:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
这样几个配置文件的作用都很明确了,mybatis-config 负责 MyBatis 的一些配置(别名、设置),spring-dao 管理了 MyBatis 连接数据库、创建 SqlSession和注册 mapper 的配置,applicationContext 整合了 Spring 的配置(现在是 spring-dao,后面还会有 spring-mvc 等等)和管理要用到对象。
3.使用SqlSessionDaoSupport
使用 SqlSessionDaoSupport 与使用 SqlSessionTemplate 大同小异,只不过更简化了一点。
上面说到,UserMapperImpl 类中有一个 SqlSessionTemplate 类型的 sqlSession 属性,实现的方法中封装了使用 SqlSession 对数据库的操作,调用它的方法就相当于在使用 SqlSession。
这种方式在使用前需要注入 sqlSession 属性,而 SqlSession 又由 SqlSessionFactory 创建。也就是说,使用这种方式需要 SqlSessionFactory 和 SqlSession 的 bean。
使用 SqlSessionDaoSupport 省略了创建 SqlSession 的 bean 的步骤。
创建 UserMapperImpl2 实现类,继承 SqlSessionDaoSupport 类,实现 UserMapper 接口
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
public List<User> getUserList() {
return null;
}
}
重点来了!**SqlSessionDaoSupport 类中有 getSqlSession 方法,可以直接获得一个 sqlSession!**用这个 sqlSession 去执行数据库操作就行了!
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
public List<User> getUserList() {
SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
return userList;
}
}
能用是能用,但必须思考为什么能用。**为什么 SqlSessionDaoSupport 类可以通过 getSqlSession 方法返回一个 SqlSession?**我们知道,SqlSession 是由 SqlSessionFactory 创建的,所以,点进去看看
public abstract class SqlSessionDaoSupport extends DaoSupport {
private SqlSessionTemplate sqlSessionTemplate;
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
// 从工厂获取 sqlSessionTemplate
}
}
原来如此!SqlSessionDaoSupport 类中就需要注入一个 sqlSessionFactory,以获取其中的 sqlSessionTemplate 对象,返回的就是这个对象!
所以在注册 UserMapperImpl2 的实现类的时候,要注入 sqlSessionFactory 依赖
<bean id="userMapper2" class="com.baifu.mapper.UserMapperImpl2">
<!--注入 sqlSession!-->
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
它会通过注入的 sqlSessionFactory,获取 sqlSessionTemplate,也就是之前的方式获取到的 SqlSession 了(回见 2.2 / 4. )。
执行测试方法,获取的是 userMapper2 对象,执行结果相同!
public class MyTest {
@Test
public void MyBatisSpringTest2(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper2", UserMapper.class);
List<User> userList = userMapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
}
}
这样就完成了,相比直接使用 SqlSessionTemplate 的方式,SqlSessionDaoSupport 将其封装了起来,从 SqlSessionDaoSupport 中就可以获取到 SqlSession,不用配置 sqlSession 的 bean 和注入了(由继承的SqlSessionDaoSupport这个类完成了,剩一步)。
总结
使用 MyBatis-Spring 有两种方式
-
使用SqlSessionTemplate:就是直接使用 SqlSession,需要将 SqlSession 注入到实现类中进行使用。
-
使用SqlSessionDaoSupport:实现类继承 SqlSessionDaoSupport 类,把工厂交给它(通过注入),就能从它获取 SqlSession。
使用 MyBatis-Spring 需要创建与 Mapper.xml 对应的实现类,在实现类中调用 Mapper.xml 实现数据库操作。实例化 Mapper.xml 为一个实现类的目的是让 Spring 能管理它。
参考: https://blog.youkuaiyun.com/qq_43560701/article/details/119960903