Spring内でJPARepositoryを用いて、1リクエスト内に複数DBからデータを取得および書込を行いたいです。
具体的には、以下の通りです。
データ書込用DBに履歴の保存を行い、データ取得用DBからユーザの取得をそれぞれ行う想定です。
取得用DBは書込用DBのレプリケーションであり、秒単位で同期がされます。
該当のソースコード
// コントローラクラス @RestController public class TestController { @Autowired private HistoryService historyService; @Autowired private UserService userService; @RequestMapping("/test") public Object test(Object history) { historyService.register(history); return userService.get(); } } // 履歴サービスクラス @Service public class HistoryServiceImpl implements HistoryService { @Autowired private HistoryRepository historyRepository; @Transactional public void register(Object history) { historyRepository.save(history); } } // ユーザサービスクラス @Service public class UserServiceImpl implements UserService { @Autowired private UserRepository UserRepository; @Transactional(readonly=true) public Object get() { return UserRepository.findAll(); } }
試したこと
①
AbstractRoutingDataSourceを継承したクラスを作成、ThreadLocalを使用してcurrentLookupKeyを設定しました。
@Aspectと専用のアノテーションを作成して、処理前にDataSourceを決定できるようにしました。
参考:) https://monakaice88.hatenablog.com/entry/2018/07/28/172720
ユーザサービスクラス内の@Transactionalの下に専用アノテーションを付与して、取得用DBを参照するようにしましたが、
書込用DBから取得を行ってしまいます。
② ※ 2021/1/18追記
transactionmanagerを複製して、@Transactionalのvalueに明示的に指定しましたが、デフォルトのDBにアクセスしてしまいます。
// DB定義クラス @configuration public class DBconfig { // ①用 @Bean @Primary public RoutingDataSourceResolver multiDataSource() { RoutingDataSourceResolver resolver = new RoutingDataSourceResolver(); // スイッチするデータソースを設定 Map<Object, Object> dataSources = new HashMap<>(); dataSources.put(READ_ONLY_DATA_SOURCE_NAME, DB2()); dataSources.put(UPDATABLE_DATA_SOURCE_NAME, DB1()); resolver.setTargetDataSources(dataSources); resolver.setDefaultTargetDataSource(dataSources.get("UPDATABLE_DATA_SOURCE_NAME")); return resolver; } public DataSource DB1() { HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl(xxx1); dataSource.setUsername(xxx); dataSource.setPassword(xxx); dataSource.setDriverClassName(xxx); return dataSource; } public DataSource DB2() { HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl(xxx2); dataSource.setUsername(xxx); dataSource.setPassword(xxx); dataSource.setDriverClassName(xxx); return dataSource; } // ②用 デフォルトは"transactionManager"を指定 @Bean(name = "transactionManager") pubic PlatformTransactionManager create1() { return new DataSourceTransactionManager(DB1()); @Bean(name = "transactionManagerForReplica") pubic PlatformTransactionManager create2() { return new DataSourceTransactionManager(DB2()); } // サービスクラスでAutowired @Service public class UserServiceImpl implements UserService { @Autowired private UserRepository UserRepository; @Qualifier("transactionManagerForReplica") @Autowired private PlatformTransactionManager transactionManagerForReplica; @Transactional(readonly = true , value = "transactionManagerForReplica") public Object get() { return UserRepository.get(); } }
補足情報
初めて書き込むこともあり、拙い日本語ですが、知見のある方ご教示いただけませんでしょうか。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/01/18 01:07
2021/01/18 02:26
2021/01/18 07:14 編集
2021/01/18 22:59
2021/01/19 07:00
2021/01/19 08:32
2021/01/20 06:25 編集
2021/01/20 04:36
2021/01/21 01:50 編集
2021/01/23 09:15 編集