java JPA createQuery 和刷新/清除

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10802457/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 02:38:45  来源:igfitidea点击:

JPA createQuery and flush/clear

javajpa

提问by David Portabella

The following code works, however if I remove the flush() and clear() calls, then the second call to showTable() does not show the updated name "joan", but "john".

下面的代码有效,但是如果我删除了 flush() 和 clear() 调用,那么对 showTable() 的第二次调用不会显示更新的名称“joan”,而是“john”。

What is the proper way to achieve this, without calling flush() and clear()?

在不调用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());
        }
    }
}

回答by JB Nizet

The first test shouldn't need flush or clear, because the entity manager must detect that the query results could be affected by the pending changes not already saved. So you shouldn't have to flush(), and even less to clear(), before executing the query.

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

The second test, however, is different. You're executing an update query, and thoses queries completely bypass the first level cache. They make changes in the database behind its back. This is the reason why you need to clear: if you don't, the select query will find the customer that is already in the cache, and the cached (but obsolete) entity will be returned.

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