目录
一、概述
多数据源问题是指在一个项目工程中,需要连接多个数据库。前几篇文章我们配置了数据库的主从,在实际开发中可能会有以下几种情况。
① 读写分离 : 项目中使用多数据源
② 项目中只操作主库 (读和写),从库只是起到了备份作用,程序员不需要关心主从结构
二、常见的多数据源技术选型模式
① JDBC
项目是JDBC开发,比较老。编写多个 getConnection 方法,分别连接不同的数据库即可
② Hibernate
项目是 SSH 框架开发,现在项目使用少一些
Spring + Hibernate
Springboot + Hibernate
③ Mybatis
项目是 SSM 框架开发
Spring + Mybatis
Springboot + Mybatis
Spring + JPA
Springboot + JPA
我们这里主要给大家介绍 Spring+Mybatis 和 SpringBoot+Mybatis 开发模式下的多数据源问题。
三、Spring + Mybatis 方案一实现步骤
核心思想 :基于 Mapper 包的隔离,每个 Mapper 包操作不同的数据库,每个 Mapper 包对应一个数据库
A、创建一个普通的 maven 项目
创建 maven 项目名为 :multi-datasource-spring
B、在 pom.xml 文件中添加相关的依赖
<!--Spring相关的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<!--Mybatis相关依赖-->
<!--Mybatis框架依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--Mybatis与Spring整合依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!--MySQL数据库连接驱动 版本不要过高-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.43</version>
</dependency>
<!--JDBC 数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.1</version>
</dependency>
C、在 pom.xml 文件添加 resource,指定编译 MyBatis 映射文件
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
D、创建 MyBatis 整合多数据源的配置文件 applicationContext-mybatis.xml
E、创建 Spring 的核心配置文件 applicationContext.xml,引入 MyBatis 配置文件
F、在 applicationContext-mybatis.xml 配置 3307|3308|3309|3310 这四个数据源
<?xml version="1.0" encoding="UTF-8"?>
<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="dataSource3307" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.160.133:3307/test"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="username" value="root"></property>
<property name="password" value="aszhuo123"></property>
</bean>
<bean id="dataSource3308" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.160.133:3307/test"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="username" value="root"></property>
<property name="password" value="aszhuo123"></property>
</bean>
<bean id="dataSource3309" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.160.133:3307/test"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="username" value="root"></property>
<property name="password" value="aszhuo123"></property>
</bean>
<bean id="dataSource3310" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.160.133:3307/test"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="username" value="root"></property>
<property name="password" value="aszhuo123"></property>
</bean>
</beans>
G、在 applicationContext-mybatis.xml 配置四个 sessionFactory,分别使用 3307|3308|3309|3310 这四个数据源
<!--3307数据库的 sessionFactory-->
<bean id="sessionFactory3307" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource3307"/>
</bean>
<!--3308数据库的 sessionFactory-->
<bean id="sessionFactory3308" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource3308"/>
</bean>
<!--3309数据库的 sessionFactory-->
<bean id="sessionFactory3309" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource3309"/>
</bean>
<!--3310数据库的 sessionFactory-->
<bean id="sessionFactory3310" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource3310"/>
</bean>
H、在 applicationContext-mybatis.xml 配置四个 Mapper 包的扫描,分别扫描 3307|3308|3309|3310
也就是说每个mapper下的接口只能操作一个数据库
<!--扫描3307库对应的mapper包,也就是说该Mapper下的接口操作的是3307数据库-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sessionFactory3307"/>
<property name="basePackage" value="com.bjpowernode.multi.mapper.mapper3307"/>
</bean>
<!--扫描3308库对应的mapper包,也就是说该Mapper下的接口操作的是3308数据库-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sessionFactory3308"/>
<property name="basePackage" value="com.bjpowernode.multi.mapper.mapper3308"/>
</bean>
<!--扫描3309库对应的mapper包,也就是说该Mapper下的接口操作的是3309数据库-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sessionFactory3309"/>
<property name="basePackage" value="com.bjpowernode.multi.mapper.mapper3309"/>
</bean>
<!--扫描3310库对应的mapper包,也就是说该Mapper下的接口操作的是3310数据库-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sessionFactory3310"/>
<property name="basePackage" value="com.bjpowernode.multi.mapper.mapper3310"/>
</bean>
I、在 pom.xml 文件中加入 MyBatis 逆向工程插件
<!--mybatis代码自动生成插件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<!--配置文件的位置-->
<configurationFile>GeneratorMapper.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
J、拷贝配置文件并进行代码反向生成
K、在 mapper 包下,分别创建子包 mapper3307 | mapper3308 | mapper3309 | mapper3310,并将生成的代码拷贝到不同的这几个子包下,然后删除掉 mapper 包下的生成的接口及 xml 文件
L、在 service 包下创建 UserService 接口
在接口中提供 getUserByIdFrom3307|3308|3309|3310 方法
public interface UserService {
User getUserByIdForm3307(Integer id);
User getUserByIdForm3308(Integer id);
User getUserByIdForm3309(Integer id);
User getUserByIdForm3310(Integer id);
}
M、创建 UserServiceImpl 实现类,并实现接口中的方法
因为我们现在4个数据库都是相同的表(实际不会存在这种情况),所以在 service 实现类中注入 Mapper 接口的时候,需要使用全限定名进行区分,并且变量名也不能一样。
@Service
public class UserServiceImpl implements UserService{
@Autowired
private com.fancy.multi.mapper.mapper3307.UserMapper userMapper3307;
@Autowired
private com.fancy.multi.mapper.mapper3308.UserMapper userMapper3308;
@Autowired
private com.fancy.multi.mapper.mapper3309.UserMapper userMapper3309;
@Autowired
private com.fancy.multi.mapper.mapper3310.UserMapper userMapper3310;
public User getUserByIdFrom3307(Integer id) {
return userMapper3307.selectByPrimaryKey(id);
}
public User getUserByIdFrom3308(Integer id) {
return userMapper3308.selectByPrimaryKey(id);
}
public User getUserByIdFrom3309(Integer id) {
return userMapper3309.selectByPrimaryKey(id);
}
public User getUserByIdFrom3310(Integer id) {
return userMapper3310.selectByPrimaryKey(id);
}
}
N、在 mapper 3307 | 3308 | 3309 | 3310 包下接口上的加 @Component(“userMapper3307|3308|3309|3310”)
因为默认情况下,Spring 容器创建的 Mapper 接口的代理对象名是接口名首字母小写,因为我们现在操作相同的表,所以接口名一样,默认生成的代理对象的名字也一样,会冲突,需要我们改一下,名字可以随意取,只要不冲突就行,因为@Autowired 是根据类型注入的。
O、在 applicationContext.xml 文件中扫描 impl 包
<context:component-scan base-package="com.fancy.multi.service.impl"/>
P、创建测试类,在 main 方法获取获取 service,调用方法
为了区分效果,可以讲从库的名字修改一下
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = context.getBean("userServiceImpl",UserService.class);
System.out.println("3307数据库:" +userService.getUserByIdFrom3307(4).getName());
System.out.println("3308数据库:" +userService.getUserByIdFrom3308(3).getName());
System.out.println("3309数据库:" +userService.getUserByIdFrom3309(4).getName());
System.out.println("3310数据库:" +userService.getUserByIdFrom3310(4).getName());
}
}
四、Spring + Mybatis 方案一加事务管理
A、在 applicationContext-mybatis.xml 文件中为每一个数据源加事务管理器,并开启事务注解
<!--事务管理器-->
<bean id="transactionManager3307" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource3307"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager3307"/>
<bean id="transactionManager3308" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource3308"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager3308"/>
<bean id="transactionManager3309" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource3309"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager3309"/>
<bean id="transactionManager3310" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource3310"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager3310"/>
B、在 UserService 接口上加更新用户方法
int updateUserFrom3307(User user);
int updateUserFrom3308(User user);
int updateUserFrom3309(User user);
int updateUserFrom3310(User user);
C、在 UserServiceImpl 实现类中实现更新用户方法,并在该方法上加事务注解
@Transactional(transactionManager = "transactionManager3307")
public int updateUserFrom3307(User user) {
int updateRow = userMapper3307.updateByPrimaryKeySelective(user);
System.out.println(updateRow);
int a = 10/a;
return updateRow;
}
@Transactional(transactionManager = "transactionManager3308")
public int updateUserFrom3308(User user) {
int updateRow = userMapper3308.updateByPrimaryKeySelective(user);
System.out.println(updateRow);
int a = 10/0;
return updateRow;
}
@Transactional(transactionManager = "transactionManager3309")
public int updateUserFrom3309(User user) {
int updateRow = userMapper3309.updateByPrimaryKeySelective(user);
System.out.println(updateRow);
int a = 10/0;
return updateRow;
}
@Transactional(transactionManager = "transactionManager3310")
public int updateUserFrom3310(User user) {
int updateRow = userMapper3310.updateByPrimaryKeySelective(user);
System.out.println(updateRow);
int a = 10/0;
return updateRow;
}
D、在 Test 类中进行测试
为了避免同步,我们这里拿从库进行测试
User user = new User();
user.setId(3);
user.setName("update-3309");
userService.updateUserFrom3309(user);
发生除 0 异常,事务回滚,更新失败。
如果将实现类的方法注解注释,虽然发生异常,依然可以更新成功。
//@Transactional(transactionManager = "transactionManager3309")
五、Spring + MyBatis 方案二实现步骤
核心思想:基于动态数据源,在运行的时候才知道要是用哪个数据源
A、在方案一配置 sessionFactory时,引用动态数据源
动态数据源就是在运行的时候决定采用哪个数据源,在配置文件中不能写死
<!--数据库的sessionFactory-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource"/>
</bean>
注意:我们现在只引用了 dynamicDataSource ,但是这个类里具体内容是什么还不知道
B、在com.fancy.multi.dynamic 包下创建 DynamicDataSource 类
该类继承 AbstractRoutingDataSource
(1) 设计的思路是将所有数据源放到一个 map 集合中,通过指定 map 集合的key,可以动态获取不同的数据源
(2) 该类中有个抽象方法 determineCurrentLookupKey 需要实现
protected Object determineCurrentLookupKey() {
return null;
}
(3) 定义几个常量,作为动态数据源对应的 key
public static final String DATASOURCE_KEY_3307 = "3307";
public static final String DATASOURCE_KEY_3308 = "3308";
public static final String DATASOURCE_KEY_3309 = "3309";
public static final String DATASOURCE_KEY_3310 = "3310";
(4) 如何将指定的 key 和不同的数据源放到 map 集合中呢?
在 applicationContext-mybatis.xml 对动态数据源 DynamicDataSource 类进行配置
<!--动态数据源-->
<bean id="dynamicDataSource" class="com.bjpowernode.multi.dynamic.DynamicDataSource">
<property name="targetDataSources">
<map>
<entry key="3307" value-ref="dataSource3307"/>
<entry key="3308" value-ref="dataSource3308"/>
<entry key="3309" value-ref="dataSource3309"/>
<entry key="3310" value-ref="dataSource3310"/>
</map>
</property>
</bean>
(5) 如何为 determineCurrentLookupKey() 动态的指定 key 呢?
在进行数据库操作前,我们提前设置使用哪个数据库,然后在指定的数据源的时候,会自动调用这个 determineCurrentLookupKey() 方法,得到指定的值。
直观的想法,可能是定义一个静态变量,但是静态变量存在线程安全问题,所以
我们需要为每一个线程都维护一个变量,用于指定连接的数据库是哪个,所以我们这里使用线程的副本ThreadLocal类
(6) 在 com.fancy.multi.dynamic 包下创建 ThreadLocalHolder 类
public class ThreadLocalHolder {
public static final ThreadLocal<String> holder = new ThreadLocal<String>();
/**
* 向当前线程变量的副本中放一个数据源的key
*/
public static void setDataSourceKey(String dataSourceKey){
holder.set(dataSourceKey);
}
/**
* 从当前线程变量的副本中取出放入数据源的key
*/
public static String getDataSourceKey(){
return holder.get();
}
}
(7) 对 DynamicDataSource 类中的方法进行实现
protected Object determineCurrentLookupKey() {
//在操作数据库前要确定是哪个数据源的key返回
return ThreadLocalHolder.getDataSourceKey();
}
C、在 applicationContext-mybatis.xml 配置 Mapper 包扫描器,直接扫描mapper 包即可
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sessionFactory"/>
<property name="basePackage" value="com.fancy.multi.mapper"/>
</bean>
之后进行测试即可
六、Spring + Mybatis 方案二加事务管理
A、在 applicationContext-mybatis.xml 添加事务管理器
并开启事务注解
如果只有一个事务管理器,那么开启事务注解的时候,transaction-manager 属性可以省略
<!--事务管理器 对动态数据源进行管理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource"/>
</bean>
<tx:annotation-driven/>
B、修改 UserServiceImpl 更新用户方法上加的事务注解
@Transactional
public int updateUserFrom3307(User user) {
int updateRow = userMapper3307.updateByPrimaryKeySelective(user);
System.out.println(updateRow);
int a = 10/0;
return updateRow;
}
@Transactional
public int updateUserFrom3308(User user) {
int updateRow = userMapper3308.updateByPrimaryKeySelective(user);
System.out.println(updateRow);
int a = 10/0;
return updateRow;
}
@Transactional
public int updateUserFrom3309(User user) {
int updateRow = userMapper3309.updateByPrimaryKeySelective(user);
System.out.println(updateRow);
int a = 10/0;
return updateRow;
}
@Transactional
public int updateUserFrom3310(User user) {
int updateRow = userMapper3310.updateByPrimaryKeySelective(user);
System.out.println(updateRow);
int a = 10/0;
return updateRow;
}
C、在 Test 类进行测试
进行数据库操作前,需要先指定数据源
七、SpringBoot + Mybatis 方案一实现步骤
核心思想:基于 Mapper 包的隔离,每个 Mapper 包操作不同的数据库,每个 Mapper 包对应一个数据库
A、创建一个 SpringBoot 的 java 项目
名为 multi-datasource-springboot
不需要添加任何依赖就普通 Java 工程即可
C、在 pom.xml 文件中添加 MyBatis 的依赖
<!-- 加载mybatis整合springboot -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<!--在springboot的父工程中没有指定版本,我们需要手动指定-->
<version>1.3.2</version>
</dependency>
<!-- MySQL的jdbc驱动包 -->
<dependency>
<groupId>mysql</groupId>
<!--在springboot的父工程中指定了版本,我们就不需要手动指定了-->
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--JDBC 数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.1</version>
</dependency>
D、在 pom.xml 文件中指定 resource,对 MyBatis 映射文件编译
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
E、在 SpringBoot 的核心配置文件中,配置连接信息
那么这里我们涉及多数据源,所以需要配置多个连接信息,如果配置多个,SpringBoot 会报错,所以我们只能对使用自定义配置,然后在程序中获取。
#3307数据库的连接配置信息
spring.datasource.username3307=root
spring.datasource.password3307=123456
spring.datasource.driver3307=com.mysql.cj.jdbc.Driver
spring.datasource.url3307=jdbc:mysql://192.168.235.128:3307/test?useUnicode=true&characterEncoding=utf8&useSSL=false
#3308数据库的连接配置信息
spring.datasource.username3308=root
spring.datasource.password3308=123456
spring.datasource.driver3308=com.mysql.cj.jdbc.Driver
spring.datasource.url3308=jdbc:mysql://192.168.235.128:3308/test?useUnicode=true&characterEncoding=utf8&useSSL=false
#3309数据库的连接配置信息
spring.datasource.username3309=root
spring.datasource.password3309=123456
spring.datasource.driver3309=com.mysql.cj.jdbc.Driver
spring.datasource.url3309=jdbc:mysql://192.168.235.128:3309/test?useUnicode=true&characterEncoding=utf8&useSSL=false
#3310数据库的连接配置信息
spring.datasource.username3310=root
spring.datasource.password3310=123456
spring.datasource.driver3310=com.mysql.cj.jdbc.Driver
spring.datasource.url3310=jdbc:mysql://192.168.235.128:3310/test?useUnicode=true&characterEncoding=utf8&useSSL=false
F、在 com.fancy.multi.config 包下定义一个映射核心文件中自定义信息的实体类 DataSourceConfigInfo
@Component
@ConfigurationProperties(prefix ="spring.datasource")
public class DataSourceConfigInfo {
private String username3307;
private String password3307;
private String driver3307;
private String url3307;
private String username3308;
private String password3308;
private String driver3308;
private String url3308;
private String username3309;
private String password3309;
private String driver3309;
private String url3309;
private String username3310;
private String password3310;
private String driver3310;
private String url3310;
//省略get|set
}
G、在自定义属性映射文件出现的警告处理
点击红色圈的链接,到 SpringBoot 官网上,拷贝如下依赖到 pom.xml 文件中,这个警告不处理也不会影响程序的运行
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
H、将 Spring + Mybatis 方案一实现中的 applicationContext-mybatis.xml 配置信息用 SpringBoot 注解替换
因为我们这里有多个数据源,所有每个数据源对应一个配置类,在com.fancy.multi.config 下创建 MyDataSource3307 类
注意:
- 在SpringBoot下,不能简单的配置 MapperScannerConfigurer这个 bean
- 在SpringBoot下,需要 SqlSessionTemplate + @MapperScan 注解 配合实现原来 xml 的功能
@Configuration //相当于一个xml文件
@MapperScan(basePackages="com.fancy.multi.mapper.mapper3307"
,sqlSessionTemplateRef = "sqlSessionTemplate3307")
public class MyDataSource3307 {
@Autowired//注入我们自定义属性的映射类
private DataSourceConfigInfo dataSourceConfigInfo;
/**
<bean id="dataSource3307" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.235.128:3307/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
*/
@Bean//相当于xml中的bean
public DruidDataSource dataSource3307(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(dataSourceConfigInfo.getUrl3307());
druidDataSource.setDriverClassName(dataSourceConfigInfo.getDriver3307());
druidDataSource.setUsername(dataSourceConfigInfo.getUsername3307());
druidDataSource.setPassword(dataSourceConfigInfo.getPassword3307());
return druidDataSource;
}
/**
* <!--3307数据库的sessionFactory-->
<bean id="sessionFactory3307" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource3307"/>
</bean>
*/
@Bean
public SqlSessionFactoryBean sessionFactory3307(){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource3307());
return sqlSessionFactoryBean;
}
/**
* <!--扫描3307库对应的mapper包,也就是说该Mapper下的接口操作的是3307数据库-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sessionFactory3307"/>
<property name="basePackage" value="com.bjpowernode.multi.mapper.mapper3307"/>
</bean>
注意:
在SpringBoot下,不能简单的配置MapperScannerConfigurer这个bean
在SpringBoot下,需要SqlSessionTemplate + @MapperScan注解 配合实现原来xml的功能
*/
@Bean
public SqlSessionTemplate sqlSessionTemplate3307() throws Exception{
//sessionFactory3307()方法返回SqlSessionFactoryBean,需要调用getObject返回SqlSessionFactory
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sessionFactory3307().getObject());
return sqlSessionTemplate;
}
}
复制 MyDataSource3307 类为 3308|3309|3310 ,并改变类中的内容为对应的数据源编号
I、从 multi-datasource-spring 中拷贝 model、service 到当前 multi-datasource-springboot 中
J、在 Application 中添加测试代码进行测试
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
UserService userService = context.getBean("userServiceImpl",UserService.class);
System.out.println("3307数据库:" +userService.getUserByIdFrom3307(4).getName());
System.out.println("3308数据库:" +userService.getUserByIdFrom3308(3).getName());
System.out.println("3309数据库:" +userService.getUserByIdFrom3309(4).getName());
System.out.println("3310数据库:" +userService.getUserByIdFrom3310(4).getName());
}
}
八、SpringBoot + Mybatis 方案一加事务管理
A、在 MyDataSource3307 类中添加对事物的处理
/**
* <bean id="transactionManager3307" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource3307"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager3307"/>
*/
@Bean("transactionManager3307")
public DataSourceTransactionManager transactionManager3307(){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource3307());
return dataSourceTransactionManager;
}
B、在 MyDataSource3308|3309|3310 类中同样添加对事物的处理
C、在 UserServiceImpl 实现类中需要控制事务的方法上添加事务注解
例如
D、在 Application 类中编写代码测试
User user = new User();
user.setId(3);
user.setName("boot-3309123");
userService.updateUserFrom3309(user);
九、SpringBoot + Mybatis 方案二实现步骤
核心思想:基于动态数据源,在运行的时候才知道要是用哪个数据源
A、将 Spring + Mybatis 方案二实现中的 applicationContext -mybatis.xml 配置信息用 SpringBoot 注解替换
因为方案二是基于动态数据源的,所以先将我们前面multi-datasource-spring 中定义的动态数据源DynamicDataSource 类以及 ThreadLocal 类拷贝到 multi-datasource-springboot 中
在 com.fancy.multi.config 下创建 MyDataSource 类
@Configuration //相当于一个xml文件
@MapperScan(basePackages="com.fancy.multi.mapper",sqlSessionTemplateRef = "sqlSessionTemplate")
public class MyDataSource {
@Autowired//注入我们自定义属性的映射类
private DataSourceConfigInfo dataSourceConfigInfo;
/**
<bean id="dataSource3307" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.235.128:3307/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
*/
@Bean//相当于xml中的bean
public DruidDataSource dataSource3307(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(dataSourceConfigInfo.getUrl3307());
druidDataSource.setDriverClassName(dataSourceConfigInfo.getDriver3307());
druidDataSource.setUsername(dataSourceConfigInfo.getUsername3307());
druidDataSource.setPassword(dataSourceConfigInfo.getPassword3307());
return druidDataSource;
}
/**
<bean id="dataSource3308" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.235.128:3308/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
*/
@Bean//相当于xml中的bean
public DruidDataSource dataSource3308(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(dataSourceConfigInfo.getUrl3308());
druidDataSource.setDriverClassName(dataSourceConfigInfo.getDriver3308());
druidDataSource.setUsername(dataSourceConfigInfo.getUsername3308());
druidDataSource.setPassword(dataSourceConfigInfo.getPassword3308());
return druidDataSource;
}
/**
<bean id="dataSource3309" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.235.128:3309/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
*/
@Bean//相当于xml中的bean
public DruidDataSource dataSource3309(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(dataSourceConfigInfo.getUrl3309());
druidDataSource.setDriverClassName(dataSourceConfigInfo.getDriver3309());
druidDataSource.setUsername(dataSourceConfigInfo.getUsername3309());
druidDataSource.setPassword(dataSourceConfigInfo.getPassword3309());
return druidDataSource;
}
/**
<bean id="dataSource3310" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://192.168.235.128:3310/test"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
*/
@Bean//相当于xml中的bean
public DruidDataSource dataSource3310(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(dataSourceConfigInfo.getUrl3310());
druidDataSource.setDriverClassName(dataSourceConfigInfo.getDriver3310());
druidDataSource.setUsername(dataSourceConfigInfo.getUsername3310());
druidDataSource.setPassword(dataSourceConfigInfo.getPassword3310());
return druidDataSource;
}
/**
* <!--数据库的sessionFactory-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource"/>
</bean>
*/
@Bean
public SqlSessionFactoryBean sessionFactory(){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource());
return sqlSessionFactoryBean;
}
/**
* <!--动态数据源-->
<bean id="dynamicDataSource" class="com.bjpowernode.multi.dynamic.DynamicDataSource">
<property name="targetDataSources">
<map>
<entry key="3307" value-ref="dataSource3307"/>
<entry key="3308" value-ref="dataSource3308"/>
<entry key="3309" value-ref="dataSource3309"/>
<entry key="3310" value-ref="dataSource3310"/>
</map>
</property>
</bean>
*/
@Bean
public DynamicDataSource dynamicDataSource(){
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> targetDataSources = new ConcurrentHashMap<Object,Object>();
targetDataSources.put(DynamicDataSource.DATASOURCE_KEY_3307,dataSource3307());
targetDataSources.put(DynamicDataSource.DATASOURCE_KEY_3308,dataSource3308());
targetDataSources.put(DynamicDataSource.DATASOURCE_KEY_3309,dataSource3309());
targetDataSources.put(DynamicDataSource.DATASOURCE_KEY_3310,dataSource3310());
dynamicDataSource.setTargetDataSources(targetDataSources);
return dynamicDataSource;
}
/**
* <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sessionFactory"/>
<property name="basePackage" value="com.bjpowernode.multi.mapper"/>
</bean>
注意:
在SpringBoot下,不能简单的配置MapperScannerConfigurer这个bean
在SpringBoot下,需要SqlSessionTemplate + @MapperScan注解 配合实现原来xml的功能
*/
@Bean
public SqlSessionTemplate sqlSessionTemplate() throws Exception{
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sessionFactory().getObject());
return sqlSessionTemplate;
}
}
之后测试同样根据上面的步骤来即可。
十、SpringBoot + Mybatis 方案二加事务管理
A、在 MyDataSource 类中添加如下配置
/**
* <!--事务管理器 对动态数据源进行管理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource"/>
</bean>
<tx:annotation-driven/>
*/
@Bean
public DataSourceTransactionManager transactionManager(){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dynamicDataSource());
return dataSourceTransactionManager;
}
B、在 Application 类上添加事务注解驱动,并测试
注意:操作数据库前需要指定数据源
@SpringBootApplication
@EnableTransactionManagement
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
UserService userService = context.getBean("userServiceImpl",UserService.class);
User user = new User();
user.setId(3);
user.setName("boot-123");
ThreadLocalHolder.setDataSourceKey(DynamicDataSource.DATASOURCE_KEY_3309);
userService.updateUserFrom3309(user);
}
}