点击上方蓝色我们家Java,选择“关注”
MyBatis多数据源


还是先来配置application.yml文件:
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
datasource:
family:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/Family?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
family2:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/Family2?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
将FamilyDemoApplication中的@MapperScan注解注释掉。
我们要在config文件夹下添加两个数据源配置:
第一个数据源配置:
package com.javafamily.familydemo.config;
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.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "com.javafamily.familydemo.generator.db",
sqlSessionTemplateRef = "familySqlSessionTemplate")
public class FamilyDataSourceConfig {
@Bean(name = "familyDataSource")
@ConfigurationProperties(prefix = "spring.datasource.family")
@Primary
public DataSource familyDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "familySqlSessionFactory")
@Primary
public SqlSessionFactory primarySqlSessionFactory(
@Qualifier("familyDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
//设置XML文件存放位置
bean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:generator/db/*.xml"));
return bean.getObject();
}
@Bean(name = "familyTransactionManager")
@Primary
public DataSourceTransactionManager familyTransactionManager(
@Qualifier("familyDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "familySqlSessionTemplate")
@Primary
public SqlSessionTemplate familySqlSessionTemplate(
@Qualifier("familySqlSessionFactory") SqlSessionFactory sqlSessionFactory)
throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
第二个数据源配置:
package com.javafamily.familydemo.config;
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.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "com.javafamily.familydemo.generator.db2",
sqlSessionTemplateRef = "family2SqlSessionTemplate")
public class Family2DataSourceConfig {
@Bean(name = "family2DataSource")
@ConfigurationProperties(prefix = "spring.datasource.family2")
public DataSource family2DataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "family2SqlSessionFactory")
public SqlSessionFactory family2SqlSessionFactory(
@Qualifier("family2DataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:generator/db2/*.xml"));
return bean.getObject();
}
@Bean(name = "family2TransactionManager")
public DataSourceTransactionManager family2TransactionManager(
@Qualifier("family2DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "family2SqlSessionTemplate")
public SqlSessionTemplate family2SqlSessionTemplate(
@Qualifier("family2SqlSessionFactory") SqlSessionFactory sqlSessionFactory)
throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
完成数据源的配置后,PetsServiceImpl进行改写,向两个数据库中添加数据。
@Resource
protected Mapper dozerMapper;
@Resource
private PetsDao petsDao;
@Resource
private DoctorDao doctorDao;
@Override
public PetsVO savePets(PetsVO pets) {
Pets petsPO = dozerMapper.map(pets, Pets.class);
petsDao.insert(petsPO);
Doctor doctor = new Doctor();
doctor.setName("Java");
doctor.setTitle("实习");
doctorDao.insert(doctor);
return pets;
}
完成代码改写后,执行代码,并在postman中进行测试:

数据分别传入两个数据库中:


MyBatis+atomikos分布式事务
与之前讲解的分布式事务一样,在PetsServiceImpl.java中的savePets方法中添加@Transactional注解和异常代码。
@Resource
protected Mapper dozerMapper;
@Resource
private PetsDao petsDao;
@Resource
private DoctorDao doctorDao;
@Override
@Transactional
public PetsVO savePets(PetsVO pets) {
Pets petsPO = dozerMapper.map(pets, Pets.class);
petsDao.insert(petsPO);
Doctor doctor = new Doctor();
doctor.setName("Java");
doctor.setTitle("实习");
doctorDao.insert(doctor);
// 添加异常
int num = 1 / 0;
return pets;
}
由于没有添加分布式事务,所以在执行代码报错后,第一个数据库不会被插入数据,第二个数据库的数据会正常插入。
maven依赖已经在之前讲解的分布式事务文章中导入了,这里不再重复导入。
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
datasource:
family:
xaDataSourceClassName: com.mysql.cj.jdbc.MysqlXADataSource
xaProperties:
url: jdbc:mysql://localhost:3306/Family?useUnicode=true&characterEncoding=utf-8&useSSL=false
user: root
password: 123456
exclusiveConnectionMode: true
minPoolSize: 2
maxPoolSize: 10
testQuery: SELECT 1 from dual
family2:
xaDataSourceClassName: com.mysql.cj.jdbc.MysqlXADataSource
xaProperties:
url: jdbc:mysql://localhost:3306/Family2?useUnicode=true&characterEncoding=utf-8&useSSL=false
user: root
password: 123456
exclusiveConnectionMode: true
minPoolSize: 2
maxPoolSize: 10
testQuery: SELECT 1 from dual
更改两个数据源配置:
第一个数据源配置:
package com.javafamily.familydemo.config;
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.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "com.javafamily.familydemo.generator.db",
sqlSessionTemplateRef = "familySqlSessionTemplate")
public class FamilyDataSourceConfig {
@Bean(name = "familyDataSource")
@ConfigurationProperties(prefix = "spring.datasource.family")
@Primary
public DataSource familyDataSource() {
return new AtomikosDataSourceBean();
}
@Bean(name = "familySqlSessionFactory")
@Primary
public SqlSessionFactory primarySqlSessionFactory(
@Qualifier("familyDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
//设置XML文件存放位置
bean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("com/javafamily/familydemo/generator/db/*.xml"));
return bean.getObject();
}
// @Bean(name = "familyTransactionManager")
// @Primary
// public DataSourceTransactionManager familyTransactionManager(
// @Qualifier("familyDataSource") DataSource dataSource) {
// return new DataSourceTransactionManager(dataSource);
// }
@Bean(name = "familySqlSessionTemplate")
@Primary
public SqlSessionTemplate familySqlSessionTemplate(
@Qualifier("familySqlSessionFactory") SqlSessionFactory sqlSessionFactory)
throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
第二个数据源配置:
package com.javafamily.familydemo.config;
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.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "com.javafamily.familydemo.generator.db2",
sqlSessionTemplateRef = "family2SqlSessionTemplate")
public class Family2DataSourceConfig {
@Bean(name = "family2DataSource")
@ConfigurationProperties(prefix = "spring.datasource.family2")
public DataSource family2DataSource() {
return new AtomikosDataSourceBean();
}
@Bean(name = "family2SqlSessionFactory")
public SqlSessionFactory family2SqlSessionFactory(
@Qualifier("family2DataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("com/javafamily/familydemo/generator/db2/*.xml"));
return bean.getObject();
}
// @Bean(name = "family2TransactionManager")
// public DataSourceTransactionManager family2TransactionManager(
// @Qualifier("family2DataSource") DataSource dataSource) {
// return new DataSourceTransactionManager(dataSource);
// }
@Bean(name = "family2SqlSessionTemplate")
public SqlSessionTemplate family2SqlSessionTemplate(
@Qualifier("family2SqlSessionFactory") SqlSessionFactory sqlSessionFactory)
throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
自动生成的代码,分别存放于db和db2两个文件夹:

由于更改了XML文件的存放位置所以移动文件目录后启动项目,如果发现target目录下没有加载到.xml文件时,需要在pom.xml下的<bulid></build>中加入以下配置:
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
在config文件夹中添加统一事务管理器:
package com.javafamily.familydemo.config;
import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.jta.JtaTransactionManager;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
@Configuration
@EnableTransactionManagement
public class XATransactionManagerConfig {
// User事务
@Bean(name = "userTransaction")
public UserTransaction userTransaction() throws Throwable {
UserTransactionImp userTransactionImp = new UserTransactionImp();
userTransactionImp.setTransactionTimeout(10000);
return userTransactionImp;
}
// 分布式事务
@Bean
public TransactionManager atomikosTransactionManager() throws Throwable {
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(false);
return userTransactionManager;
}
// 事务管理器
@Bean(name = "transactionManager")
@DependsOn({"userTransaction", "atomikosTransactionManager"})
public PlatformTransactionManager transactionManager() throws Throwable {
return new JtaTransactionManager(userTransaction(), atomikosTransactionManager());
}
}
执行代码,向两个数据库中添加数据后,postman测试:

再查看数据库:


两个数据库均没有数据被插入,至此分布式事务完成。
点击下方阅读原文,查看上一篇
文章转载自我们家Java,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




