上一篇文章《SpringBoot实现多数据源(四)【集成多个 Mybatis 框架】》
在多数据源下,由于涉及到数据库的多个读写。一旦发生异常可能会导致数据不一致的情况,在这种情况希望使用事务进行回退
但是 Spring 的声明式事务在一次请求线程中只能使用一个数据源进行控制
对于多源数据库来讲:
一个方法开启2个事务
1)编程式事务
package com.vinjcent.config.mybatis;import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
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 org.springframework.transaction.support.TransactionTemplate;import javax.sql.DataSource;/*** 读数据源配置* 1. 指定扫描mapper接口包* 2. 指定使用rSqlSessionFactory是哪个*/
@Configuration
@MapperScan(basePackages = "com.vinjcent.mapper.read", sqlSessionFactoryRef = "rSqlSessionFactory")
public class RMybatisConfiguration {// readDataSource(读数据源)@Bean(name = "readDatasource")@ConfigurationProperties(prefix = "spring.datasource.read")public DataSource readDatasource() {// 底层会自动拿到spring.datasource中的配置,创建一个DruidDataSourcereturn DruidDataSourceBuilder.create().build();}// SqlSessionFactory(ibatis会话工厂)@Bean@Primarypublic SqlSessionFactory rSqlSessionFactory(@Qualifier("readDatasource") DataSource dataSource) throws Exception {final SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();sqlSessionFactory.setDataSource(dataSource);sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/vinjcent/mapper/read/*.xml"));/*主库设置sql控制台打印*/org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();configuration.setLogImpl(StdOutImpl.class);sqlSessionFactory.setConfiguration(configuration);sqlSessionFactory.setTypeAliasesPackage("com.vinjcent.pojo");return sqlSessionFactory.getObject();}// TransactionManager(事务管理者)@Beanpublic DataSourceTransactionManager rTransactionManager() {DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();transactionManager.setDataSource(readDatasource());return transactionManager;}// TransactionTemplate(事务模板)@Beanpublic TransactionTemplate rTransactionTemplate() {return new TransactionTemplate(rTransactionManager());}
}
package com.vinjcent.config.mybatis;import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
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 org.springframework.transaction.support.TransactionTemplate;import javax.sql.DataSource;/*** 写数据源配置* 1. 指定扫描mapper接口包* 2. 指定使用wSqlSessionFactory是哪个*/
@Configuration
@MapperScan(basePackages = "com.vinjcent.mapper.write", sqlSessionFactoryRef = "wSqlSessionFactory")
public class WMybatisConfiguration {// writeDataSource(写数据源)@Bean(name = "writeDatasource")@ConfigurationProperties(prefix = "spring.datasource.write")public DataSource writeDatasource() {// 底层会自动拿到spring.datasource中的配置,创建一个DruidDataSourcereturn DruidDataSourceBuilder.create().build();}// SqlSessionFactory(ibatis会话工厂)@Bean@Primarypublic SqlSessionFactory wSqlSessionFactory(@Qualifier("writeDatasource") DataSource dataSource) throws Exception {final SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();sqlSessionFactory.setDataSource(dataSource);sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/vinjcent/mapper/write/*.xml"));/* 主库设置sql控制台打印 */org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();configuration.setLogImpl(StdOutImpl.class);sqlSessionFactory.setConfiguration(configuration);sqlSessionFactory.setTypeAliasesPackage("com.vinjcent.pojo");return sqlSessionFactory.getObject();}// TransactionManager(事务管理者)@Bean@Primarypublic DataSourceTransactionManager wTransactionManager() {DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();transactionManager.setDataSource(writeDatasource());return transactionManager;}// TransactionTemplate(事务模板)@Beanpublic TransactionTemplate wTransactionTemplate() {return new TransactionTemplate(wTransactionManager());}
}
package com.vinjcent.service.impl;import com.vinjcent.mapper.read.RPeopleMapper;
import com.vinjcent.mapper.write.WPeopleMapper;
import com.vinjcent.pojo.People;
import com.vinjcent.service.PeopleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;import java.util.List;@Service
public class PeopleServiceImpl implements PeopleService {// 读mapperprivate final RPeopleMapper rPeopleMapper;// 写mapperprivate final WPeopleMapper wPeopleMapper;// 读事务模板private final TransactionTemplate rTransactionTemplate;// 写事务模板private final TransactionTemplate wTransactionTemplate;@Autowiredpublic PeopleServiceImpl(RPeopleMapper rPeopleMapper, WPeopleMapper wPeopleMapper, TransactionTemplate rTransactionTemplate, TransactionTemplate wTransactionTemplate) {this.rPeopleMapper = rPeopleMapper;this.wPeopleMapper = wPeopleMapper;this.rTransactionTemplate = rTransactionTemplate;this.wTransactionTemplate = wTransactionTemplate;}@Overridepublic List list() {return rPeopleMapper.list();}@Overridepublic boolean save(People people) {return wPeopleMapper.save(people);}// 从库保存public boolean rSave(People people) {return rPeopleMapper.save(people);}// 主库保存public boolean wSave(People people) {return wPeopleMapper.save(people);}// 主从库保存@Overridepublic void saveAll(People people) {// 写事务模板wTransactionTemplate.execute(wStatus -> {// 读事务模板rTransactionTemplate.execute(rStatus -> {try {rSave(people);wSave(people);// 模拟异常int a = 1 /0;} catch (Exception e) {e.printStackTrace();// 出现异常回滚"写"事务wStatus.setRollbackOnly();// 出现异常回滚"读"事务rStatus.setRollbackOnly();return false;}return true;});return true;});}}
package com.vinjcent.controller;import com.vinjcent.pojo.People;
import com.vinjcent.service.PeopleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("people")
public class PeopleController {private final PeopleService peopleService;@Autowiredpublic PeopleController(PeopleService peopleService) {this.peopleService = peopleService;}@GetMapping("/list")public List getAllPeople() {//...}@GetMapping("/insert")public String addPeople() {//...}// 添加位置@GetMapping("/save")public String addPeopleForWriteAndRead() {peopleService.saveAll(new People("ReadAndWrite"));return "读写库添加成功~";}}
2)声明式事务
修改Service层
package com.vinjcent.service.impl;import com.vinjcent.mapper.read.RPeopleMapper;
import com.vinjcent.mapper.write.WPeopleMapper;
import com.vinjcent.pojo.People;
import com.vinjcent.service.PeopleService;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;import java.util.List;@Service
public class PeopleServiceImpl implements PeopleService {// 读mapperprivate final RPeopleMapper rPeopleMapper;// 写mapperprivate final WPeopleMapper wPeopleMapper;// 读事务模板private final TransactionTemplate rTransactionTemplate;// 写事务模板private final TransactionTemplate wTransactionTemplate;@Autowiredpublic PeopleServiceImpl(RPeopleMapper rPeopleMapper, WPeopleMapper wPeopleMapper, TransactionTemplate rTransactionTemplate, TransactionTemplate wTransactionTemplate) {this.rPeopleMapper = rPeopleMapper;this.wPeopleMapper = wPeopleMapper;this.rTransactionTemplate = rTransactionTemplate;this.wTransactionTemplate = wTransactionTemplate;}@Overridepublic List list() {return rPeopleMapper.list();}@Overridepublic boolean save(People people) {return wPeopleMapper.save(people);}// 从库保存public boolean rSave(People people) {return rPeopleMapper.save(people);}// 主库保存public boolean wSave(People people) {return wPeopleMapper.save(people);}// 主从库保存@Transactional("wTransactional")@Overridepublic void saveAll(People people) {// 获取当前的service代理类对象,需要在主启动类开启@EnableAspectJAutoProxy(exposeProxy = true),暴露代理对象PeopleService peopleService = (PeopleService) AopContext.currentProxy();peopleService.saveAllR(people);}@Transactional(value = "rTransactional")@Overridepublic void saveAllR(People people) {wSave(people);rSave(people);int a = 1 / 0;}
}
下一篇文章《SpringBoot实现多数据源(六)【dynamic-datasource 多数据源组件】》
上一篇:形容一个人很贪小便宜的话有哪些
下一篇:适合空间留言的句子