在实际项目中,可能需要配置多个数据库,某一段代码需要操作多个数据库时,如何保持事务一致性?
需要说明的是,多数据库的数据一致性不是分布式事务。Spring也提供了ChainedTransactionManager
类来管理我们多数据源。
1. 实现多数据源的配置
以durid
数据源为例子:
配置信息可以参考:SpringBoot2.x实现动态切换数据源(实现读写分离)
@Slf4j
@Configuration
//指定需要扫描的Dao文件
@MapperScan(basePackages="com.xxx.mapper",sqlSessionTemplateRef = "xxxSqlSessionTemplate")
public class XxxDataSourceConfig {
//加载项目中resources中的XxxDao.xml文件
@Value("${xxxsql.mapperLocations}")
private String mapperLocations;
//加载Mybatisde1全局的配置文件
@Value("${mysql.configLocation}")
private String configLocation;
/**
* 数据源配置
*/
@Bean(name = "xxxDataSource")
//读取配置文件的配置信息到DruidDataSource对象中
@ConfigurationProperties(prefix = "xxxsql.datasource")
public DataSource writeDataSource() {
DruidDataSource dataSource = new DruidDataSource();
return dataSource;
}
@Bean(name="xxxSqlSessionFactory")
public SqlSessionFactory sqlSessionFactorys(@Qualifier("xxxDataSource") DataSource dataSource) throws Exception {
try {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
//获取配置文件的dataSource对象
sessionFactoryBean.setDataSource(dataSource);
//设置mybatis-config.xml配置文件位置
sessionFactoryBean.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
//设置mapper.xml文件所在位置
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(mapperLocations);
sessionFactoryBean.setMapperLocations(resources);
return sessionFactoryBean.getObject();
} catch (IOException e) {
log.error("mybatis解析 mapper*xml 失败",e);
return null;
} catch (Exception e) {
log.error("mybatis sqlSessionFactoryBean创建失败",e);
return null;
}
}
@Bean(name = "xxxSqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("xxxSqlSessionFactory")SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
//事务管理
@Bean(name = "xxxTransactionManager")
public PlatformTransactionManager xxxTransactionManager(@Qualifier("xxxDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
配置mybatis的全局配置:目录:resources/mybatis/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>
<settings>
<setting name="cacheEnabled" value="true" />
<setting name="lazyLoadingEnabled" value="true" />
<setting name="multipleResultSetsEnabled" value="true" />
<setting name="useColumnLabel" value="true" />
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="useGeneratedKeys" value="true" />
<setting name="defaultExecutorType" value="SIMPLE" />
<setting name="defaultStatementTimeout" value="25000" />
</settings>
<typeAliases>
<typeAlias alias="Integer" type="java.lang.Integer" />
<typeAlias alias="Long" type="java.lang.Long" />
<typeAlias alias="HashMap" type="java.util.HashMap" />
<typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
<typeAlias alias="ArrayList" type="java.util.ArrayList" />
<typeAlias alias="LinkedList" type="java.util.LinkedList" />
</typeAliases>
</configuration>
yml的配置文件:
xxxsql:
mapperLocations: classpath*:mybatis/xxx/**/*.xml
configLocation: classpath:/mybatis/mybatis-config.xml
doubleWriting: false
datasource:
url: jdbc:mysql://ip地址:端口/数据库名?useSSL=false
username:
password:
driver-class-name: com.mysql.jdbc.Driver
minIdle: 5
maxActive: 100
initialSize: 10
maxWait: 60000
2. 实现链式事务的配置
实现链式事务,是把两个事务管理器都交由ChainedTransactionManager
来统一管理。若A数据源提交,但是B数据源出现异常,那么A,B数据源均要回滚。
引入依赖:
<!-- Spring Data Commons -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>2.0.9.RELEASE</version>
</dependency>
注:platformTransactionManager
事务管理器声明时,因为使用了@Primary
注解,所以不需要使用@Qualifier()
注解来指定名字。
@Configuration
public class ChainedTransactionManagerConfig {
//实现链式事务,
@Bean(name = "chainedTransactionManager")
public ChainedTransactionManager chainedTransactionManager(PlatformTransactionManager platformTransactionManager,
@Qualifier("xxxTransactionManager") PlatformTransactionManager xxxPlatformTransactionManager) {
return new ChainedTransactionManager(platformTransactionManager, xxxPlatformTransactionManager);
}
}