JTAの実体はWildFlyを使用してSpringの設定を行う。
環境
- jdk1.8.0_131
- Eclipse 4.6.3
- WildFly Full 10.1.0.Final
- ubuntu 16.04
- Oracle Database 11g Release 2(11.2.0.1.0) Enterprise Edition
- PostgreSQL 9.5.6
- ojdbc6.jar
- postgresql-42.1.1.jar
事前準備
WildFlyにOracleとPostgreSQLのXAデータソースを作成しておく。
pg_hba.confにmax_prepared_transactionsのコメントアウトを外してとりあえず20にしておく。
max_prepared_transactions = 20
これを設定しておかないと以下のようなエラーになる。
Caused by: org.postgresql.util.PSQLException: ERROR: prepared transactions are disabled ヒント: Set max_prepared_transactions to a nonzero value.
コード
動作確認用のspring-mvcとspring-jdbcをpom.xmlに入れる。
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.8.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.8.RELEASE</version> </dependency>
configurationを作る。特にこれといって何の変哲もなく、JTA固有の設定項目としてはtransactionManagerにJtaTransactionManagerを使用している程度。
@Configuration @EnableTransactionManagement @ComponentScan(basePackages={"kagamihoge.springjtasample"}) public class SpringJtaConfig { @Bean public DataSource postgresqlDataSource() { JndiDataSourceLookup l = new JndiDataSourceLookup(); return l.getDataSource("java:/PostgresXADS"); } @Bean public DataSource oracleDataSource() { JndiDataSourceLookup l = new JndiDataSourceLookup(); return l.getDataSource("java:/XAOracleDS"); } @Bean public PlatformTransactionManager transactionManager() { return new JtaTransactionManager(); } @Bean public JdbcTemplate postgresqlJdbcTemplate() { return new JdbcTemplate(postgresqlDataSource()); } @Bean public JdbcTemplate oracleJdbcTemplate() { return new JdbcTemplate(oracleDataSource()); } }
configuration以降はほとんど今まで通りのコードとやることは変わらない。
JdbcTemplateで適当な更新SQLを二つのRDBMSに対して実行してみる。
@Component public class SampleComponent { @Autowired private JdbcTemplate postgresqlJdbcTemplate; @Autowired private JdbcTemplate oracleJdbcTemplate; @Transactional public void execute() { int i1 = oracleJdbcTemplate.queryForObject("select 1 from dual", Integer.class); int i2 = postgresqlJdbcTemplate.queryForObject("select 1", Integer.class); System.out.println(i1 + " " + i2); int j1 = oracleJdbcTemplate.update("insert into t1(c1) values (1)"); int j2 = postgresqlJdbcTemplate.update("insert into t1(c1) values (1)"); System.out.println(j1 + " " + j2); } @Transactional public void executeAndRollback() { int j1 = oracleJdbcTemplate.update("insert into t1(c1) values (1)"); int j2 = postgresqlJdbcTemplate.update("insert into t1(c1) values (1)"); throw new RuntimeException(); } }
これまで通り、@Transactionalアノテーションをつけておけばメソッド実行後にコミットされる。適当な例外をスローすればロールバックが行われる。
メモ
JdbcTemplateは特に何もしなくても動作するが、ORマッパーのライブラリによってはデータソースをTransactionAwareDataSourceProxyでラップする必要がある。