如何解决使用spring @Transactional和AbstractRoutingDataSource在只读数据库和读写数据库之间切换
我需要使用带有Spring的@Transactional
批注的只读和读写数据源。我有以下设置:
public class DataSourceRouter extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DatabaseContextHolder.getEnvironment();
}
}
@Aspect
public class DataSourceSwitch {
@Around("@annotation(transactional)")
public Object proceed(ProceedingJoinPoint pjp,Transactional transactional) throws Throwable {
DatabaseEnvironment newEnv = transactional.readOnly() ?
DatabaseEnvironment.READ_ONLY : DatabaseEnvironment.READ_WRITE;
DatabaseContextHolder.setEnvironment(newEnv);
return pjp.proceed();
}
}
@Configuration
@EnableTransactionManagement
@EnableAspectJAutoproxy
public class JpaConfig {
@Bean
@Primary
public DataSource getDataSource() throws Exception {
DataSourceRouter router = new DataSourceRouter();
Map<Object,Object> dataSources = new HashMap<>();
dataSources.put(DatabaseEnvironment.READ_ONLY,<readOnlyDb>);
dataSources.put(DatabaseEnvironment.READ_WRITE,<readWriteDb>);
router.setTargetDataSources(dataSources);
return router;
}
}
类DatabaseContextHolder
将应使用的DB保存到ThreadLocal
。带有@Transactional
批注的方法具有相应设置的readOnly
标志。
我面临的问题是,路由器的方法determineCurrentLookupKey
仅在调用第一个@Transactional
方法时被调用一次,而在随后的事务方法中不会再次被调用不同的数据源。因此,例如,如果调用的第一个方法需要只读数据源,而后来的另一个方法需要读写数据源,则数据库上下文确实会更改,但是determineCurrentLookupKey
不会再被调用,因此它将尝试写入只读数据库,并且失败。每次调用事务方法时都不应该调用determineCurrentLookupKey
方法吗?
方法之间不能相互调用,也不能从同一类调用。将propagation = Propagation.REQUIRES_NEW
添加到@Transactional
批注也无济于事。使其运作的最佳方法是什么?
解决方法
解决方案是将其添加到application.yaml
:
spring:
jpa:
open-in-view: false
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。