Java JPA createQuery和刷新/清除
下面的代码可以工作, 但是,如果删除flush()和clear()调用, 然后,对showTable()的第二次调用不会显示更新后的名称“joan”,而是“john” 在不调用flush()和clear()的情况下,实现这一点的正确方法是什么Java JPA createQuery和刷新/清除,java,jpa,Java,Jpa,下面的代码可以工作, 但是,如果删除flush()和clear()调用, 然后,对showTable()的第二次调用不会显示更新后的名称“joan”,而是“john” 在不调用flush()和clear()的情况下,实现这一点的正确方法是什么 import java.util.List; 导入javax.persistence.EntityManager; 导入javax.persistence.PersistenceContext; 导入javax.persistence.Query; 导入o
import java.util.List;
导入javax.persistence.EntityManager;
导入javax.persistence.PersistenceContext;
导入javax.persistence.Query;
导入org.junit.Test;
导入org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
导入org.springframework.test.context.ContextConfiguration;
导入org.springframework.test.context.junit4.AbstractTransactionalJUnit4 SpringContextTests;
导入org.springframework.test.context.transaction.TransactionConfiguration;
导入org.springframework.transaction.annotation.Propagation;
导入org.springframework.transaction.annotation.Transactional;
导入com.example.Customer;
@ContextConfiguration(位置={“classpath:spring/test/spring test.xml”})
@TransactionConfiguration(transactionManager=“txManager”)
公共类测试扩展了AbstractTransactionalJUnit4SpringContextTests{
私有最终记录器log=LoggerFactory.getLogger(getClass());
@持久上下文
私人实体管理者实体管理者;
@试验
@事务性(传播=传播。需要\u新建)
public void test()引发异常{
客户=新客户();
customer.setName(“约翰”);
entityManager.persist(客户);
entityManager.flush();
entityManager.clear();
可显示();
final Query Query=entityManager.createQuery(“更新客户c集c.name='joan'”);
int updateCount=query.executeUpdate();
log.debug(“更新计数:”+updateCount);
entityManager.flush();
entityManager.clear();
可显示();
}
公共空间显示表(){
final Query Query=entityManager.createQuery(“从客户c中选择c”);
List=query.getResultList();
用于(客户:列表){
log.info(“客户名称:+customer.getName());
}
}
}
第一个测试不需要刷新或清除,因为实体管理器必须检测到查询结果可能会受到尚未保存的挂起更改的影响。因此,在执行查询之前,不必刷新(),更不用说清除()
然而,第二个测试是不同的。您正在执行更新查询,这些查询完全绕过了一级缓存。他们在数据库背后进行更改。这就是您需要清除的原因:如果不需要,select查询将找到已在缓存中的客户,并返回缓存(但已过时)实体。您需要两个清除/清除调用,还是只需要一个特定的调用对?请检查:正确,不需要第一个清除/清除。然而,问题是什么是不需要刷新/清除而进行更新查询的正确方法,因为刷新/清除非常容易出错。也许有可能以某种方式禁用“一级缓存”?或者以其他方式重写更新查询(在对象上迭代并更新/合并)?这样的DML更新查询应该很少使用。通常通过查找实体(使用
em.find()
或select查询)并修改其状态来更新实体。JPA自动将更改刷新到数据库中。您的查询将数据库中所有客户的名称设置为相同的值,这与典型用例相差甚远。如果一个真正的用例需要这样一个查询,那么您将像您在问题中所做的那样:在大规模更新之后清除缓存。
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());
}
}
}