文章目录
- 1. 整合思路
- 2. 最简单的整合步骤
- 1. 导入依赖
- 2. 准备基础类
- User
- UserMapper
- userMapper.xml
- MybatisConfig
- 3. 测试
- TestMybatisSpring
- 3. 整合多个mybatis配置
- 1. 修改MybatisConfig
- 2. 测试
- TestMybatisSpring
- 4. AbstractRoutingDataSource实现源切换
- 1. 准备基础类
- Person
- PersonMapper
- CustomizeRoutingDataSource
- 2. 修改MyBatisConfig
- 3. 测试
- TestMybatisSpring
- 5. mybatis插件实现切换数据源
- 1. DsPlugin
- 2. 修改MybatisConfig
- 3.测试
- TestMybatisSpring
1. 整合思路
@MapperScan注解 -> 引入了MapperScannerRegistrar注册器 -> 该注册器向容器中MapperScannerConfigurer这个configurer是个BeanDefinitionRegistryPostProcessor,它在重写的postProcessBeanDefinitionRegistry方法中使用了ClassPathMapperScanner来扫描指定的包中的mapper接口 -> ClassPathMapperScanner(如果未指定sqlSessionTemplateBeanName,也没有指定sqlSessionFactoryBeanName,将会设置按类型自动注入SqlSessionFactory和SqlSessionTemplate(实现了SqlSession接口,委托给SqlSessionInterceptor,即每次调用SqlSession中的任何方法都会走SqlSessionInterceptor#invoke方法,这是为了控制事务),仅须其中一个即可) -> 扫包中的每一个beanDefinition都会设置beanClass为MapperFactoryBean,而MapperFactoryBean#getObject方法就会获取sqlSessionTemplate(它实现了SqlSession接口),并调用sqlSessionTemplate.getMapper(接口类)方法,来获取动态代理 -> 而每次使用动态代理的方法都会调用sqlSessionTemplate -> 而sqlSessionTemplate则也会委托给SqlSessionInterceptor-> 此时去从SqlSessionFactory获取sqlSession
2. 最简单的整合步骤
1. 导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zzhua</groupId>
<artifactId>mybatis-spring-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 准备基础类
User
@Data
public class User {
private String userAccount;
}
UserMapper
public interface UserMapper {
List<User> findAll();
@Select("select * from `user` u where u.user_account = #{userAccount}")
User findOne(String userAccount);
}
userMapper.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.zzhua.mapper.UserMapper">
<select id="findAll" resultType="user">
select * from `user`
</select>
</mapper>
MybatisConfig
package com.zzhua.config;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import java.io.IOException;
@Configuration
@MapperScan(basePackages = "com.zzhua.mapper")
public class MybatisConfig {
@Bean // 如果不配置该bean,将会抛出Caused by: java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required异常
public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException { // 代码写法可参考SqlSessionFactoryBean#afterPropertiesSet
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 设置数据源
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUrl("jdbc:mysql://127.0.0.1/user?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true");
driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("root");
sqlSessionFactoryBean.setDataSource(driverManagerDataSource);
// 自定义Configuration
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(true);
configuration.getTypeAliasRegistry().registerAliases("com.zzhua.pojo");
sqlSessionFactoryBean.setConfiguration(configuration);
// 指定mapper.xml文件
PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resourcePatternResolver.getResources("classpath:com/zzhua/mapper/**.xml"));
return sqlSessionFactoryBean; // # 之后会调用SqlSessionFactoryBean#afterPropertiesSet()方法
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
}
}
3. 测试
TestMybatisSpring
public class TestMybatisSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MybatisConfig.class);
UserMapper userMapper = context.getBean(UserMapper.class);
List<User> userList = userMapper.findAll();
System.out.println(userList);
User user = userMapper.findOne("zzhua");
System.out.println(user);
}
}
3. 整合多个mybatis配置
创建2个数据库,一个user库(里面有一张user表)和user2库(里面有一张user2表)。现在需要使用mybatis来操作这2个库中的表。
1. 修改MybatisConfig
@Configuration
@MapperScan(basePackages = "com.zzhua.dao.mapper", sqlSessionFactoryRef = "sqlSessionFactoryBean")
public class MybatisConfig {
@Bean // 如果不配置该bean,将会抛出Caused by: java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required异常
public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException { // 代码写法可参考SqlSessionFactoryBean#afterPropertiesSet
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 设置数据源
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUrl("jdbc:mysql://127.0.0.1/user?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true");
driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("root");
sqlSessionFactoryBean.setDataSource(driverManagerDataSource);
// 自定义Configuration
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(true);
configuration.getTypeAliasRegistry().registerAliases("com.zzhua.pojo");
sqlSessionFactoryBean.setConfiguration(configuration);
// 指定mapper.xml文件
PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resourcePatternResolver.getResources("classpath:com/zzhua/mapper/**.xml"));
return sqlSessionFactoryBean; // # 之后会调用SqlSessionFactoryBean#afterPropertiesSet()方法
}
@Configuration
@MapperScan(basePackages = "com.zzhua.dao.mapper2", sqlSessionFactoryRef = "sqlSessionFactoryBean2")
public static class MybatisConfig2 {
@Bean
// 如果不配置该bean,将会抛出Caused by: java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required异常
public SqlSessionFactoryBean sqlSessionFactoryBean2() throws IOException { // 代码写法可参考SqlSessionFactoryBean#afterPropertiesSet
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 设置数据源
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUrl("jdbc:mysql://127.0.0.1/user2?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true");
driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("root");
sqlSessionFactoryBean.setDataSource(driverManagerDataSource);
// 自定义Configuration
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(true);
configuration.getTypeAliasRegistry().registerAliases("com.zzhua.pojo");
sqlSessionFactoryBean.setConfiguration(configuration);
// 指定mapper.xml文件
PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resourcePatternResolver.getResources("classpath:com/zzhua/mapper2/**.xml"));
return sqlSessionFactoryBean; // # 之后会调用SqlSessionFactoryBean#afterPropertiesSet()方法
}
}
}
2. 测试
TestMybatisSpring
public class TestMybatisSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MybatisConfig.class);
UserMapper userMapper = context.getBean(UserMapper.class);
List<User> userList = userMapper.findAll();
System.out.println(userList);
User user = userMapper.findOne("zzhua");
System.out.println(user);
System.out.println("--------------");
UserMapper2 userMapper2 = context.getBean(UserMapper2.class);
List<User2> userList2 = userMapper2.findAll2();
System.out.println(userList2);
User2 user2 = userMapper2.findOne2("zzhua2");
System.out.println(user2);
}
}
4. AbstractRoutingDataSource实现源切换
在user库中新建一张person表
1. 准备基础类
Person
@Data
public class Person {
private String name;
}
PersonMapper
public interface PersonMapper {
@Insert("insert into person values(#{name} )")
void addPerson(String name);
@Select("select * from person")
List<Person> getPersons();
}
CustomizeRoutingDataSource
public class CustomizeRoutingDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> DS_KEY = new ThreadLocal<>();
@Override
protected Object determineCurrentLookupKey() {
return DS_KEY.get();
}
public static void setDsKey(String dsKey) {
DS_KEY.set(dsKey);
}
public static void clearDsKey() {
DS_KEY.remove();
}
}
2. 修改MyBatisConfig
@Configuration
@MapperScan(basePackages = "com.zzhua.dao.mapper", sqlSessionFactoryRef = "sqlSessionFactoryBean")
public class MybatisConfig {
@Bean
public DataSource userDataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUrl("jdbc:mysql://127.0.0.1/user?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true");
driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("root");
return driverManagerDataSource;
}
@Bean
public DataSource user2DataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUrl("jdbc:mysql://127.0.0.1/user2?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true");
driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("root");
return driverManagerDataSource;
}
@Primary
@Bean
public DataSource primaryDataSource() {
CustomizeRoutingDataSource routingDataSource = new CustomizeRoutingDataSource();
// 指定默认数据源
routingDataSource.setDefaultTargetDataSource(userDataSource());
// 指定 标识->数据源 的map
HashMap<Object, Object> dsMap = new HashMap<>();
dsMap.put("user", userDataSource());
dsMap.put("user2", user2DataSource());
routingDataSource.setTargetDataSources(dsMap);
return routingDataSource;
}
@Bean // 如果不配置该bean,将会抛出Caused by: java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required异常
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource primaryDataSource) throws IOException { // 代码写法可参考SqlSessionFactoryBean#afterPropertiesSet
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 设置数据源
sqlSessionFactoryBean.setDataSource(primaryDataSource);
// 自定义Configuration
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(true);
configuration.getTypeAliasRegistry().registerAliases("com.zzhua.pojo");
sqlSessionFactoryBean.setConfiguration(configuration);
// 指定mapper.xml文件
PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resourcePatternResolver.getResources("classpath:com/zzhua/mapper/**.xml"));
return sqlSessionFactoryBean; // # 之后会调用SqlSessionFactoryBean#afterPropertiesSet()方法
}
}
3. 测试
TestMybatisSpring
public class TestMybatisSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MybatisConfig.class);
PersonMapper personMapper = context.getBean(PersonMapper.class);
// 可使用注解 + AOP的方式简化代码, 在执行数据库操作之前设置所要操作的数据源标识
CustomizeRoutingDataSource.setDsKey("user");
personMapper.addPerson("zzhua");
personMapper.addPerson("zj");
List<Person> persons = personMapper.getPersons();
System.out.println(persons);
CustomizeRoutingDataSource.clearDsKey();
CustomizeRoutingDataSource.setDsKey("user2");
personMapper.addPerson("zzhua2");
personMapper.addPerson("zj2");
List<Person> persons2 = personMapper.getPersons();
System.out.println(persons2);
CustomizeRoutingDataSource.clearDsKey();
}
}
5. mybatis插件实现切换数据源
1. DsPlugin
// Interceptor可拦截mybatis的四大对象中的方法
// 四大对象包括: Executor、StatementHandler、ParameterHandler、ResultSetHandler
@Intercepts({
@Signature(
type = Executor.class,
method = "update",
args = {MappedStatement.class, Object.class}
),
@Signature(
type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
)
})
public class DsPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
MappedStatement ms = ((MappedStatement) args[0]);
if (SqlCommandType.SELECT.equals(ms.getSqlCommandType())) {
CustomizeRoutingDataSource.setDsKey("user");
} else {
CustomizeRoutingDataSource.setDsKey("user2");
}
Object result = invocation.proceed();
CustomizeRoutingDataSource.clearDsKey();
return result;
}
}
2. 修改MybatisConfig
@Configuration
@MapperScan(basePackages = "com.zzhua.dao.mapper", sqlSessionFactoryRef = "sqlSessionFactoryBean")
public class MybatisConfig {
@Bean
public DataSource userDataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUrl("jdbc:mysql://127.0.0.1/user?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true");
driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("root");
return driverManagerDataSource;
}
@Bean
public DataSource user2DataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUrl("jdbc:mysql://127.0.0.1/user2?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true");
driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("root");
return driverManagerDataSource;
}
@Primary
@Bean
public DataSource primaryDataSource() {
CustomizeRoutingDataSource routingDataSource = new CustomizeRoutingDataSource();
// 指定默认数据源
routingDataSource.setDefaultTargetDataSource(userDataSource());
// 指定 标识->数据源 的map
HashMap<Object, Object> dsMap = new HashMap<>();
dsMap.put("user", userDataSource());
dsMap.put("user2", user2DataSource());
routingDataSource.setTargetDataSources(dsMap);
return routingDataSource;
}
@Bean // 如果不配置该bean,将会抛出Caused by: java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required异常
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource primaryDataSource) throws IOException { // 代码写法可参考SqlSessionFactoryBean#afterPropertiesSet
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 设置数据源
sqlSessionFactoryBean.setDataSource(primaryDataSource);
// 自定义Configuration
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(true);
configuration.getTypeAliasRegistry().registerAliases("com.zzhua.pojo");
// 添加插件
configuration.addInterceptor(new DsPlugin());
sqlSessionFactoryBean.setConfiguration(configuration);
// 指定mapper.xml文件
PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resourcePatternResolver.getResources("classpath:com/zzhua/mapper/**.xml"));
return sqlSessionFactoryBean; // # 之后会调用SqlSessionFactoryBean#afterPropertiesSet()方法
}
}
3.测试
TestMybatisSpring
public class TestMybatisSpring {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MybatisConfig.class);
PersonMapper personMapper = context.getBean(PersonMapper.class);
personMapper.addPerson("zzhua11");
personMapper.addPerson("zj11");
List<Person> persons = personMapper.getPersons();
System.out.println(persons);
}
}