版本对应关系
MyBatis-Spring-Boot-Starter | MyBatis-Spring | Mybatis | Spring Framework | Spring Boot | Java |
---|---|---|---|---|---|
2.1 | 2.0 (need 2.0.2+ for enable all features) | 3.5+ | 5.0+ | 2.1 or higher | 8 or higher |
1.3 | 1.3 | 3.4+ | 3.2.2+ | 1.5 | 6 or higher |
MyBatis-Spring-Boot-Starter
MyBatis-Spring-Boot-Starter
可以帮助开发者快速构建基于Spring Boot的MyBatis应用。MyBatis-Spring-Boot-Starter
帮助我们实现:
- 自动检测存在的
DataSource
- 使用
SqlSessionFactoryBean
创建并注册一个SqlSessionFactory
实例,并设置DataSource
- 创建并注册一个
SqlSessionTemplate
实例 - 自动扫描Mappers,关联到
SqlSessionTemplate
并注册到Spring容器
使用
添加Maven依赖:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
Mapper类添加@Mapper
注解或者使用@MapperScan
注解指定包路径
配置文件必须添加:
mybatis.mapper-locations=classpath:/mapper/*Mapper.xml
不然会抛出异常:BindingException: Invalid bound statement (not found)
什么是 MyBatis-Spring?
MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession
并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException。 最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。
使用
添加Maven依赖:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
要和 Spring 一起使用 MyBatis,需要在 Spring 应用上下文中定义至少两样东西:一个 SqlSessionFactory
和至少一个数据映射器类。
在 MyBatis-Spring 中,可使用 SqlSessionFactoryBean
来创建 SqlSessionFactory。
要配置这个工厂 bean,只需要把下面代码放在 Spring 的 XML 配置文件中:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
@Configuration
public class MyBatisConfig {
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
return factoryBean.getObject();
}
}
注意:SqlSessionFactory 需要一个 DataSource(数据源)。这可以是任意的 DataSource,只需要和配置其它 Spring 数据库连接一样配置它就可以了。
假设现在有一个mapper接口,那么可以通过MapperFactoryBean
将接口加入到Spring中:
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
使用 Java 代码来配置的方式如下:
@Configuration
public class MyBatisConfig {
@Bean
public UserMapper userMapper() throws Exception {
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory());
return sqlSessionTemplate.getMapper(UserMapper.class);
}
}
什么是MyBatis?
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
使用
添加Maven依赖:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
从XML中构建SQLSessionFactory
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。后面会再探讨 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="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
不使用 XML 构建 SqlSessionFactory
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
MyBatis-Spring实现思路
在基础的 MyBatis 用法中,是通过 SqlSessionFactoryBuilder
来创建 SqlSessionFactory
的。而在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean
来创建。
(1)MybatisAutoConfiguration自动装配,实例化SqlSessionFactory, SqlSessionFactoryBean是一个工厂Bean, 最后调用SqlSessionFactoryBean#getObject()生成对应的SqlSessionFacatory
(2)生成SqlSessionTemplate,依赖于SqlSessionFacatory实例
(3)在配置@MapperScan注解之后,会调用MapperScannerRegistrar
,会创建MapperScannerConfigurer
bean定义及对象,然后委派ClassPathMapperScanner
根据MapperScan中的值,创建Mapper接口对应的MapperFactoryBean
,最后由MapperFactoryBean
生成对应的Mapper对象,即使用SqlSession获取对应的Mapper对象.
这就是为什么可以不用实现Mapper接口,就可以实现调用。原因就是Mapper接口对应的实例被换成了MapperProxy
。我们指定MapperProxy实现了InvocationHandler,所以调用Mapper接口中的方法走的是MapperProxy的invoke。
核心类介绍
SqlSessionFactory
SqlSessionFactory是MyBatis中的一个重要的对象,它是用来创建SqlSession对象的,而SqlSession用来操作数据库的。
SqlSessionFactoryBean
SqlSessionFactoryBean用来创建SqlSessionFactory对象,读取Mapper XML文件。
SqlSessionTemplate
SqlSessionTemplate是MyBatis-Spring的核心。这个类负责管理MyBatis的SqlSession,调用MyBatis的SQL方法。此外,它管理session的生命周期,包含必要的关闭,提交或回滚操作。
ClassPathMapperScanner
1.设置BeanDefinition的构造函数参数值为当前BeanDefinition的类名,也就是映射接口的类名
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
2.改变BeanDefinition的beanClass为MapperFactoryBean.class
definition.setBeanClass(this.mapperFactoryBean.getClass());
做的事情其实是重写BeanDefinition的BeanClass字段为MapperFactoryBean.class,并且将beanClass其实也就是MapperFactoryBean
的构造器参数设置为实际的标注了@Mapper的接口,之后当Mapper接口注入的时候,实际调用的是MapperFactoryBean中的getObject()获取特定的mapper实例
MapperFactoryBean
用于根据mapper接口生成mapper对象的类。
Mybatis动态代理实现
使用动态代理
@Autowired
private ArticleMapper articleMapper;
@GetMapping("article/list")
public List<ArticleDO> findAll() {
System.out.println("articleMapper = " + articleMapper);
return articleMapper.findAll();
}
不使用动态代理
@Autowired
private SqlSessionFactory factory;
@GetMapping("article/list2")
public List<ArticleDO> findAll2() {
SqlSession sqlSession = factory.openSession();
List<ArticleDO> list = sqlSession.selectList("com.fang.web.persistence.dao.ArticleMapper.findAll");
sqlSession.close();
return list;
}
动态代理中最重要的类:SqlSession、MapperProxy、MapperMethod。
1、通过SqlSession
获取代理对象,实现类为DefaultSqlSession
<T> T getMapper(Class<T> var1);
2、委托Configuration
类的getMapper方法
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
3、委托MapperRegistry
类的getMapper方法,通过MapperProxyFactory
的命名方式我们知道这里将通过这个工厂生成我们所关注的MapperProxy的代理类
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
4、MapperProxyFactory用来创建动态代理对象
protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
5、MapperProxy的invoke是把Method包装成了MapperMethod,MapperMethod处理了Mapper接口方法与xml映射的关系。
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
return this.mapperMethod.execute(sqlSession, args);
}
总结
总结一下,我们公共MyBatis添加的Mapper的操作实际上添加的是MapperProxyFactory,这个是MapperProxy的工厂类,但是MapperProxyFactory生产的也不是MapperProxy,而是Mapper的Proxy代理。使用的InvocationHandler是MapperProxy,MapperProxy的invoke方法实际上是把Mapper接口方法包装为了MapperMethod,并执行的MapperMethod的execute方法。MapperMethod处理的逻辑是Mapper方法与xml中的SQL的一些映射关系。