【发布时间】:2020-11-20 00:29:25
【问题描述】:
我需要使用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方法时只调用一次,并且在以下事务方法中不会再次调用,这可能需要不同的数据源.例如,如果调用的第一个方法需要一个只读数据源,然后另一个方法需要一个读写数据源,则 DB 上下文确实会发生变化,但不会再次调用 determineCurrentLookupKey,因此它会尝试写入 read-只有数据库,并且失败。每次调用事务方法时不应该调用determineCurrentLookupKey方法吗?
这些方法不是相互调用的,也不是从同一个类调用的。将propagation = Propagation.REQUIRES_NEW 添加到@Transactional 注释也没有帮助。让它发挥作用的最佳方法是什么?
【问题讨论】:
标签: java spring-data-jpa spring-transactions