トランザクションのネスト数=必要なコネクション数だっけ???
マルチスレッドなバッチ処理のコネクションプールのプールサイズを見積もった際、トランザクションのネストが発生するので 当然ネストする分のコネクションも必要 ということで、スレッド数
× トランザクションのネスト数
でプールサイズを設定しました。
あとになって、「ほんとにそう(ネスト分も必要)だっけ?」と自分の中の 当たり前 に漠然とした不安を覚え、ググってみても そのものズバリの回答にたどり着けなかった ので、サンプルコードを組んで確認することにしました。
結論
いきなり身も蓋もないですが、
トランザクションのネスト数=必要なコネクション数
でした。
ということで、結果だけを知りたかった場合は、以下はスルーして構いません。
検証環境
- Oracle JDK 8 u161
- spring-boot 1.4.3
- Tomcat JDBC Connection Pool 8.5.6
サンプルコード(抜粋)
# ConnectionPool
spring.datasource.tomcat.maxActive=1
spring.datasource.tomcat.maxIdle=1
spring.datasource.tomcat.minIdle=0
spring.datasource.tomcat.initialSize=0
@SpringBootApplication
public class App {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(App.class, args);
Main bean = context.getBean(Main.class);
bean.doNestedTransaction();
}
}
@Component
public class Main {
@Autowired
private MainTarnsaction mainTransaction;
public void doNestedTransaction() {
mainTransaction.beginTransaction();
}
}
@Component
public class MainTarnsaction {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private NestedTransaction nestedTransaction;
@Transactional
public void beginTransaction() {
jdbcTemplate.execute("update Hoge set val = 'aaa' where id = '1'");
nestedTransaction.beginTransaction();
}
}
@Component
public class NestedTarnsaction {
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void beginTransaction() {
jdbcTemplate.execute("update Hoge set val = 'bbb' where id = '2'");
}
}
実行結果
(1) プールサイズを 1
(spring.datasource.tomcat.maxActive=1
)に設定して実行した場合
org.springframework.transaction.CannnotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is org.apache.tomcat.jdbc.pool.PoolExhaustedException: [main] Timeout: Pool empty. Unable to fetch a connection in 30 seconds. none available[size:1; busy:1; idel:0; lastwait:30000].
...
at xxx.NestedTransaction$$EnhancerBySpringCGLib$$xxx.beginTransaction(<generated>)
...
at xxx.MainTransaction$$EnhancerBySpringCGLib$$xxx.beginTransaction(<generated>)
at xxx.Main.doNestedTransaction(Main.java:xx)
...
上記の通り、ネスト側のトランザクションのためのコネクションをプールから割り当ることができず、例外が発生しました。
(2) プールサイズを 2
(spring.datasource.tomcat.maxActive=2
)に設定して実行した場合
(予想通りですが)正常終了しました。
おわりに
自分の中のモヤモヤはこれでスッキリしました。
同じ疑問にぶつかった人の参考になれば幸いです。