Play Frameworkで動くプログラムでDDL(データ操作でなく、CREATE TABLEなどスキーマを操作するSQL命令文)を発行しようとするとなぜかDB側に全然反映されなくて悩むことがあります。
悩まされた方、例えばこんな記事とか。
http://netmark.jp/2012/12/play-framework-isucon2-8.html
Ebean.execute(Ebean.createCallableSql("commit;"));
Ebean.commitTransaction();
なお、↑のコードでは EBean.createCallableSql("commit;") と Ebean.commitTransaction で2回コミットしてます。
本当は2回もいらないような気がするのですが、なんか試してるうちにこうじゃないと動かなかったのでこうしてます。
この問題は、DDL命令もロールバック可能なDB製品との組み合わせで発生します。PostgreSQLとSQLServerが該当します。EBeanはDBアクセスの最適化として「UPDATE/INSERT/DELETEの発行されなかったトランザクションではcommit()を呼ばれても実際にはROLLBACKを発行する」という動作をしているためです。
トランザクションを明示的に作らなかった場合も暗黙の単命令トランザクションですからやはりROLLBACK。
引用したブログ記事の、手動でCOMMITを生発行するという対策はそういう意味で効いているわけですが、これはやはりこう、もう少しフレームワークにちゃんと乗っかった対策がやりたくなります。
方法は2つ。
- 設定で最適化をオフにすること。application.conf にtransaction.onqueryonly=COMMITと設定します。
- 設定の影響を受けないコードを書きたい場合、コード中で**transaction.getConnection()**を呼ぶ。
これはJDBCの生オブジェクトを引っ張り出すメソッドで低レベルな操作の入口となるものなのですが、これを呼ばれた時点でEBeanは「何か変更が入れられたことだろう」と判断して必ずCOMMITしてくれるようになります。