kagamihogeの日記

kagamihogeの日記です。

WildFlyでSpringのJTA設定

JTAの実体はWildFlyを使用してSpringの設定を行う。

環境

事前準備

WildFlyOraclePostgreSQLの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でラップする必要がある。