多資料來源導致事務不生效
阿新 • • 發佈:2021-10-14
@Autowired @Qualifier("writeDataSource") private DataSource writeDataSource; @Bean("txManager") public DataSourceTransactionManager txManager(@Qualifier("roundRobinDataSouceProxy") DataSource roundRobinDataSouceProxy) { return new DataSourceTransactionManager(roundRobinDataSouceProxy); }
讀寫路由
/** * 把所有資料庫都放在路由中 * * @return */ @Bean(name = "roundRobinDataSouceProxy") public AbstractRoutingDataSource roundRobinDataSouceProxy() { Map<Object, Object> targetDataSources = new HashMap<Object, Object>(); //把所有資料庫都放在targetDataSources中,注意key值要和determineCurrentLookupKey()中程式碼寫的一至, //否則切換資料來源時找不到正確的資料來源 targetDataSources.put(DataSourceType.write.getType(), writeDataSource); targetDataSources.put(DataSourceType.read.getType(), readDataSource); //路由類,尋找對應的資料來源 AbstractRoutingDataSource proxy = new AbstractRoutingDataSource() { /** * 這是AbstractRoutingDataSource類中的一個抽象方法, * 而它的返回值是你所要用的資料來源dataSource的key值,有了這個key值, * targetDataSources就從中取出對應的DataSource,如果找不到,就用配置預設的資料來源。 */ @Override protected Object determineCurrentLookupKey() { String typeKey = DataSourceContextHolder.getReadOrWrite(); if (typeKey == null) { System.err.println("使用資料庫write............."); return DataSourceType.write.getType(); } if (typeKey.equals(DataSourceType.write.getType())) { System.err.println("使用資料庫write............."); return DataSourceType.write.getType(); } //讀庫, 簡單負載均衡 System.err.println("使用資料庫read"); return DataSourceType.read.getType(); } }; //預設庫 proxy.setDefaultTargetDataSource(writeDataSource); proxy.setTargetDataSources(targetDataSources); return proxy; }
/** * 在service層覺得資料來源 * * 必須在事務AOP之前執行,所以實現Ordered,order的值越小,越先執行 * 如果一旦開始切換到寫庫,則之後的讀都會走寫庫 * */ @Aspect @EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true) @Component public class DataSourceAopInService implements PriorityOrdered{ //private static Logger log = LoggerFactory.getLogger(DataSourceAopInService.class); @Before("execution(* net.vipmro.hades.boss.service..*.find*(..)) " + " or execution(* net.vipmro.hades.boss..*.get*(..)) " + " or execution(* net.vipmro.hades.boss..*.select*(..)) " + " or execution(* net.vipmro.hades.boss..*.search*(..)) " + " or execution(* net.vipmro.hades.boss..*.query*(..))") public void setReadDataSourceType() { //如果已經開啟寫事務了,那之後的所有讀都從寫庫讀 if(!DataSourceType.write.getType().equals(DataSourceContextHolder.getReadOrWrite())){ DataSourceContextHolder.setRead(); } } @Before("execution(* net.vipmro.hades.boss..*.insert*(..)) " + " or execution(* net.vipmro.hades.boss..*.update*(..))" + " or execution(* net.vipmro.hades.boss..*.save*(..))" + " or execution(* net.vipmro.hades.boss..*.del*(..))" + " or execution(* net.vipmro.hades.boss..*.add*(..))") public void setWriteDataSourceType() { DataSourceContextHolder.setWrite(); } @Override public int getOrder() { /** * 值越小,越優先執行 * 要優於事務的執行 * 在啟動類中加上了@EnableTransactionManagement(order = 10) */ return 1; } }