一.基于spring的声明式事务
项目中配置了多个数据源DaoSupport配置
/**
* 商品daoSupport
* @param jdbcTemplate 商品jdbcTemplate
* @return
*/
@Bean(name = "goodsDaoSupport")
@Primary
public DaoSupport goodsDaoSupport(@Qualifier("goodsJdbcTemplate") JdbcTemplate jdbcTemplate) {
DaoSupport daosupport = new DaoSupportImpl(jdbcTemplate);
return daosupport;
}
/**
* 交易daoSupport
* @param jdbcTemplate 交易jdbcTemplate
* @return
*/
@Bean(name = "tradeDaoSupport")
public DaoSupport tradeDaoSupport(@Qualifier("tradeJdbcTemplate") JdbcTemplate jdbcTemplate) {
DaoSupport daosupport = new DaoSupportImpl(jdbcTemplate);
return daosupport;
}
/**
* 会员daoSupport
* @param jdbcTemplate 会员jdbcTemplate
* @return
*/
@Bean(name = "memberDaoSupport")
public DaoSupport memberDaoSupport(@Qualifier("memberJdbcTemplate") JdbcTemplate jdbcTemplate) {
DaoSupport daosupport = new DaoSupportImpl(jdbcTemplate);
return daosupport;
}
数据源配置
/**
* 商品数据源
* @return
*/
@Bean(name = "goodsDataSource")
@Qualifier("goodsDataSource")
@Primary
@ConfigurationProperties(prefix="spring.datasource.druid.goods")
public DataSource goodsDataSource() {
return DruidDataSourceBuilder.create().build();
}
/**
* 交易数据源
* @return
*/
@Bean(name = "tradeDataSource")
@Qualifier("tradeDataSource")
@ConfigurationProperties(prefix="spring.datasource.druid.trade")
public DataSource tradeDataSource() {
return DruidDataSourceBuilder.create().build();
}
/**
* 会员数据源
* @return
*/
@Bean(name = "memberDataSource")
@Qualifier("memberDataSource")
@ConfigurationProperties(prefix="spring.datasource.druid.member")
public DataSource memberDataSource() {
return DruidDataSourceBuilder.create().build();
}
同时配置了多个事务管理器
/**
* 会员事务
* @param dataSource
* @return
*/
@Bean
public PlatformTransactionManager memberTransactionManager(@Qualifier("memberDataSource")DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/**
* 商品事务
* @param dataSource
* @return
*/
@Bean
@Primary
public PlatformTransactionManager goodsTransactionManager(@Qualifier("goodsDataSource")DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/**
* 交易事务
* @param dataSource
* @return
*/
@Bean
public PlatformTransactionManager tradeTransactionManager(@Qualifier("tradeDataSource")DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
多数据源的声明式事务可以通过TransactionTemplate来完成
@Bean
public TransactionTemplate tradeTransactionTemplate() {
return new TransactionTemplate(tradeTransactionManager(tradeDataSource()));
}
@Bean
public TransactionTemplate memberTransactionTemplate() {
return new TransactionTemplate(memberTransactionManager(memberDataSource()));
}
使用
// 注入对应的TransactionTemplate
@Autowired
private TransactionTemplate memberTransactionTemplate;
//执行数据库操作
memberTransactionTemplate.execute(exe -> {
try {
// 业务逻辑代码
} catch (Exception e) {
exe.setRollbackOnly();
} finally {
return true;
}
});
二.通过自定义注解 + AOP切面实现
首先自定义多数据源事务注解
/**
* 多数据源事务注解
* @author
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MultiTransactional {
/**
* 事务管理器数组
* @return
*/
String[] transactionManagers();
}
编写AOP切面
@Component
@Aspect
public class MultiTransactionAop {
/**
* 采取栈的模式获取事务管理器,事务回滚应遵循后进先出的原则,所以采取栈的数据结构
*/
private static final ThreadLocal<Stack<Map<DataSourceTransactionManager, TransactionStatus>>> THREAD_LOCAL = new ThreadLocal();
/**
* 用于获取事务管理器
*/
@Autowired
private ApplicationContext applicationContext;
/**
* 声明事务
*/
private DefaultTransactionDefinition def = new DefaultTransactionDefinition();
{
// 设置非只读
def.setReadOnly(false);
// 设置事务隔离模式
def.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
// 设置事务传播模式 spring 7种事务传播模式
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
}
/**
* 多数据源事务切点
*/
@Pointcut("@annotation(com.enation.app.javashop.framework.database.annotation.MultiTransactional)")
public void pointcut() {}
/**
* 声明事务
* @param multiTransactional
*/
@Before("pointcut() && @annotation(multiTransactional)")
public void before(MultiTransactional multiTransactional) {
String[] transactionManagers = multiTransactional.transactionManagers();
Stack<Map<DataSourceTransactionManager, TransactionStatus>> stack = new Stack<>();
for (String transActionManager : transactionManagers) {
DataSourceTransactionManager manager = applicationContext.getBean(transActionManager, DataSourceTransactionManager.class);
TransactionStatus transactionStatus = manager.getTransaction(def);
Map<DataSourceTransactionManager, TransactionStatus> transactionStatusMap = new HashMap<>();
transactionStatusMap.put(manager, transactionStatus);
stack.push(transactionStatusMap);
}
THREAD_LOCAL.set(stack);
}
/**
* 业务逻辑没有出错进行事务提交
*/
@AfterReturning("pointcut()")
public void afterReturning() {
Stack<Map<DataSourceTransactionManager, TransactionStatus>> stack = THREAD_LOCAL.get();
while (!stack.empty()) {
Map<DataSourceTransactionManager, TransactionStatus> pop = stack.pop();
pop.forEach((key, value) -> key.commit(value));
}
THREAD_LOCAL.remove();
}
/**
* 业务逻辑异常进行事务回滚
*/
@AfterThrowing("pointcut()")
public void afterThrowing() {
Stack<Map<DataSourceTransactionManager, TransactionStatus>> stack = THREAD_LOCAL.get();
while (!stack.empty()) {
Map<DataSourceTransactionManager, TransactionStatus> pop = stack.pop();
pop.forEach((key, value) -> key.rollback(value));
}
THREAD_LOCAL.remove();
}
}
在业务service层进行使用
@Override
@MultiTransactional(transactionManagers = {"memberTransactionManager", "erpTransactionManager"})
public AskReplyDO updateReply(Integer askId, String replyContent, String anonymous) {
//具体业务逻辑
}
三.使用@DS注解及
首先在pom.xml中引入苞米豆的依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>2.5.4</version>
</dependency>
在service层,可以使用DS注解指定对应的数据源,需要使用事务时,可以使用@DSTransactional完成
@Service
@DS("member")
public class MemberServiceImpl implements MemberService {}
@Override
@DSTransactional
public ArtPass insertArtPassAndNoticeRemind(ArtPass artPass) {}