EJB 3.0(Public Draft)入門記 Java Persistence API Chapter3 その7
Chapter3 その4に続いて3.2.3 Synchronization to the Databaseのあたりをもう一度やってみます。
リンク先の日記を書いたときはFlushModeアノテーションというものがあるというのは意識していていたのですが、EntityManagerにsetFlushModeメソッドというものがあることをすっかり忘れていました。ということで今回はsetFlushModeメソッドにFlushModeType.AUTO, FlushModeType.COMMIT, FlushModeType.NEVERをそれぞれ渡して挙動を確かめたいと思います。
使うエンティティは1つだけにします。
@Entity(access=AccessType.FIELD) public class Employee { @Id(generate=GeneratorType.AUTO) private int id; private String name; // getter, setter省略 }
クライアント。prepareメソッドでデータを用意しmainメソッド内でsetFlushModeしてからデータのupdateしてます。
@Stateless public class ClientBean implements Client { @PersistenceContext private EntityManager em; public void prepare() { Employee e = new Employee(); e.setName("ゴン"); em.persist(e); } public void main() { //ここで渡す値をFlushModeType.AUTO, FlushModeType.COMMIT, FlushModeType.NEVERに変えて動かします em.setFlushMode(FlushModeType.COMMIT); Employee employee1 = (Employee) em.createQuery("from Employee").getSingleResult(); employee1.setName("うさはな"); Employee employee2 = (Employee) em.createQuery("from Employee").getSingleResult(); System.out.println(employee2.getName()); } public static void main(String[] args) throws Exception { EJB3StandaloneBootstrap.boot(null); EJB3StandaloneBootstrap.deployXmlResource("ejb3-deployment.xml"); InitialContext ctx = new InitialContext(); Client client = (Client) ctx.lookup(Client.class.getName()); client.prepare(); client.main(); EJB3StandaloneBootstrap.shutdown(); } }
使用するFlushModeTypeを変えて実行してみた出力結果です。
1. FlushModeType.AUTOを使った場合。2回目のクエリの前にflushされてます。
Hibernate: insert into Employee (name, id) values (?, null) Hibernate: call identity() Hibernate: select employee0_.id as id0_, employee0_.name as name0_ from Employee employee0_ Hibernate: update Employee set name=? where id=? Hibernate: select employee0_.id as id0_, employee0_.name as name0_ from Employee employee0_ うさはな
2. FlushModeType.COMMITを使った場合。2回目のクエリの後(commit時)にflushされてます。
Hibernate: insert into Employee (name, id) values (?, null) Hibernate: call identity() Hibernate: select employee0_.id as id0_, employee0_.name as name0_ from Employee employee0_ Hibernate: select employee0_.id as id0_, employee0_.name as name0_ from Employee employee0_ うさはな Hibernate: update Employee set name=? where id=?
3. FlushModeType.NEVERを使った場合。java.lang.IllegalStateExceptionがおきて「You cannot set FlushModeType to NEVER for a TRANSACTION persistence context」といわれます。通常の永続コンテキストにはNEVERは指定できないということらしいです(たぶん拡張永続コンテキスト(extended persistent context)ならばOKということですね)。ということは通常の永続コンテキストを使う場合はリードオンリーなトランザクションでもNEVERは駄目なんですね。
FlushModeType.AUTOとFlushModeType.COMMITを使った場合の結果からわかることは、flushのタイミングに関係なく更新されるべき値(例でいうと「うさはな」)がちゃんとクエリで返ってくるということです。おもしろい。JDBCの感覚で考えてしまうと、FlushModeType.COMMITを使った場合のようにupdate前にupdateされるべき値が返ってくるのは不思議に思えてしまいますね。