JPA createQuery和flush / clear

时间:2012-05-29 15:46:44

标签: java jpa

以下代码有效, 但是如果我删除flush()和clear()调用, 然后第二次调用showTable()不会显示更新的名称“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());
        }
    }
}

1 个答案:

答案 0 :(得分:5)

第一个测试不需要刷新或清除,因为实体管理器必须检测到查询结果可能会受到尚未保存的挂起更改的影响。因此,在执行查询之前,您不必刷新(),甚至不需要清除()。

然而,第二次测试是不同的。您正在执行更新查询,并且查询完全绕过第一级缓存。他们在数据库后面进行了更改。这就是您需要清除的原因:如果不这样做,select查询将找到已经在缓存中的客户,并且将返回缓存的(但过时的)实体。