2012-05-29 59 views
4

下面的代码工作, 但是,如果我删除flush()和clear()调用, 然后第二次调用showTable()不显示更新名称“joan”,但“约翰”。JPA createQuery和清除/清除

什么是正确的方式来实现这一点,而不调用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()); 
     } 
    } 
} 
+0

你需要_both_清空/清除呼叫,或只有一个特定的对? – jtahlborn

+0

看看这个:http://stackoverflow.com/q/4415211/738746 –

回答

5

第一个测试不应该需要刷新或清除,因为实体管理器必须检测查询结果可以通过尚未保存未决的改变而受到影响。因此,在执行查询之前,您不必flush(),甚至不需要clear()。

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

+1

正确,第一次冲洗/清除是不需要的。然而,问题是关于什么是更新查询而不需要刷新/清除的正确方法,这非常容易出错。也许有可能以某种方式禁用“第一级缓存”?或以其他方式重写更新查询(迭代对象和更新/合并)? –

+1

这种DML更新查询应该很少使用。您通常通过查找它们(使用'em.find()'或select查询)来更新实体,并修改它们的状态。 JPA自动将更改刷新到数据库。您的查询将数据库中所有客户的名称设置为相同的值,这与典型用例非常相似。如果一个真正的用例需要这样的查询,那么你会做你在你的问题中做的事情:在大规模更新后清除缓存。 –