更新のメモ(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はテーブルから読み出した値とインスタンスの値を比較し、値が異なる場合だけ更新するようになっているみたい。