更新のメモ(2)
Hibernateの実装は、デフォルトでは全ての列に対して更新を行なってしまう。
サンプル
package sample; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; public class UpdateExample3 { public static void main(String[] args) { int id = -1; EntityManagerFactory emf = Persistence .createEntityManagerFactory("hibernate"); { EntityManager em = emf.createEntityManager(); final EntityTransaction tx = em.getTransaction(); tx.begin(); User user = new User(); user.setName("Brad Pitt"); em.persist(user); id = user.getId(); tx.commit(); em.close(); } { EntityManager em = emf.createEntityManager(); final EntityTransaction tx = em.getTransaction(); tx.begin(); User user = em.find(User.class, id); // 名前だけ変更 user.setName("Orlando Bloom"); tx.commit(); em.close(); } emf.close(); } }
実行結果
Hibernate: insert into user (id, mail_address, name, version) values (null, ?, ?, ?) Hibernate: select user0_.id as id2_0_, user0_.mail_address as mail2_2_0_, user0_.name as name2_0_, user0_.version as version2_0_ from user user0_ where user0_.id=? Hibernate: update user set mail_address=?, name=?, version=? where id=? and version=?
org.hibernate.annotations.Entity(dynamicInsert = true, dynamicUpdate = true)
これは、Hibernate独自のアノテーションを使用することで変更された列だけ更新することができる。
@Entity @org.hibernate.annotations.Entity(dynamicInsert = true, dynamicUpdate = true) public class User {
実行結果
Hibernate: insert into user (name, version, id) values (?, ?, null) Hibernate: select user0_.id as id2_0_, user0_.mail_address as mail2_2_0_, user0_.name as name2_0_, user0_.version as version2_0_ from user user0_ where user0_.id=? Hibernate: update user set name=?, version=? where id=? and version=?
次のように値が変更されない場合はUPDATE自体が実行されない。
サンプル
package sample; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; public class UpdateExample3 { public static void main(String[] args) { int id = -1; EntityManagerFactory emf = Persistence .createEntityManagerFactory("hibernate"); { EntityManager em = emf.createEntityManager(); final EntityTransaction tx = em.getTransaction(); tx.begin(); User user = new User(); user.setName("Brad Pitt"); em.persist(user); id = user.getId(); tx.commit(); em.close(); } { EntityManager em = emf.createEntityManager(); final EntityTransaction tx = em.getTransaction(); tx.begin(); User user = em.find(User.class, id); // setterを呼び出すが値は変更しない user.setName("Brad Pitt"); tx.commit(); em.close(); } emf.close(); } }
実行結果
Hibernate: insert into user (name, version, id) values (?, ?, null) Hibernate: select user0_.id as id2_0_, user0_.mail_address as mail2_2_0_, user0_.name as name2_0_, user0_.version as version2_0_ from user user0_ where user0_.id=?
EntityManager.merge()を使用した場合
package sample; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; public class UpdateExample3 { public static void main(String[] args) { int id = -1; EntityManagerFactory emf = Persistence .createEntityManagerFactory("hibernate"); { EntityManager em = emf.createEntityManager(); final EntityTransaction tx = em.getTransaction(); tx.begin(); User user = new User(); user.setName("Brad Pitt"); user.setMailAddress("aaa@bbb.ccc.ddd"); em.persist(user); id = user.getId(); tx.commit(); em.close(); } { EntityManager em = emf.createEntityManager(); final EntityTransaction tx = em.getTransaction(); tx.begin(); User user = new User(); user.setId(id); user.setName("Brad Pitt"); user.setMailAddress("aaa@bbb.ccc.ddd"); em.merge(user); tx.commit(); em.close(); } emf.close(); } }
実行結果
Hibernate: insert into user (mail_address, name, version, id) values (?, ?, ?, null) Hibernate: select user0_.id as id2_0_, user0_.mail_address as mail2_2_0_, user0_.name as name2_0_, user0_.version as version2_0_ from user user0_ where user0_.id=?
へ〜・・・EntityManager.merge()を呼び出した場合も一度SELECTするんだ・・・
EntityManager.find()の後にsetterを呼び出しただけの場合とEntityManager.merge()を使用した場合とでテーブルの値を読み込むタイミングは違うけど、dynamicUpdateはテーブルから読み出した値とインスタンスの値を比較し、値が異なる場合だけ更新するようになっているみたい。