4

次のコードは機能しますが、flush()とclear()の呼び出しを削除すると、showTable()の2番目の呼び出しでは、更新された名前「joan」ではなく「john」が表示されます。

flush()とclear()を呼び出さずにこれを達成するための適切な方法は何ですか?

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.example.Customer;

@ContextConfiguration(locations = {"classpath:spring/test/spring-test.xml"})
@TransactionConfiguration(transactionManager = "txManager")
public class Test extends AbstractTransactionalJUnit4SpringContextTests {
    private final Logger log = LoggerFactory.getLogger(getClass());

    @PersistenceContext
    private EntityManager entityManager;

    @Test
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void test() throws Exception {
        Customer customer = new Customer();
        customer.setName("john");

        entityManager.persist(customer);
        entityManager.flush();
        entityManager.clear();

        showTable();

        final Query query = entityManager.createQuery("update Customer c set c.name='joan'");
        int updateCount = query.executeUpdate();
        log.debug("Update count: " + updateCount);
        entityManager.flush();
        entityManager.clear();

        showTable();
    }

    public void showTable() {
        final Query query = entityManager.createQuery("select c FROM Customer c");
        List<Customer> list = query.getResultList();
        for (Customer customer: list) {
            log.info("customer name: " + customer.getName());
        }
    }
}
4

1 に答える 1

5

エンティティマネージャは、まだ保存されていない保留中の変更によってクエリ結果が影響を受ける可能性があることを検出する必要があるため、最初のテストはフラッシュまたはクリアする必要はありません。したがって、クエリを実行する前に、flush()を実行する必要はなく、clear()を実行する必要もありません。

ただし、2番目のテストは異なります。更新クエリを実行していて、それらのクエリは第1レベルのキャッシュを完全にバイパスします。彼らはその背後にあるデータベースに変更を加えます。これが、クリアする必要がある理由です。クリアしない場合、selectクエリは、すでにキャッシュにある顧客を検索し、キャッシュされた(ただし廃止された)エンティティが返されます。

于 2012-05-29T17:20:56.737 に答える