JPA 更新查询:缓存未正确失效

rco*_*len 2 caching jpa eclipselink

为什么它不起作用:

@Test
public void test() {
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("test-pu");
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    String id = "id";
    long value = 1234L;

    entityManager.getTransaction().begin();

    FancyEntity fancyEntity = new FancyEntity(id);
    entityManager.persist(fancyEntity);
    int updateCount = entityManager.createQuery("update FancyEntity item set item.value = ?2 where item.id = ?1").setParameter(1, id).setParameter(2, value).executeUpdate();
    assertEquals(1, updateCount);

    FancyEntity checkResult = entityManager.find(FancyEntity.class, id);
    assertEquals(1234L, checkResult.getValue()); // <- this assert fails

    entityManager.getTransaction().commit();
}
Run Code Online (Sandbox Code Playgroud)

@Entity
public class FancyEntity {
    @Id
    private String id;
    @Column
    private long value;
    public FancyEntity(String id) {
        this.id = id;
        this.value = 0;
    }
    public FancyEntity() {
    }
    public long getValue() {
        return value;
    }
}
Run Code Online (Sandbox Code Playgroud)

<persistence-unit name="test-pu"
                  transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <class>com.fancypackage.FancyEntity</class>

    <properties>
        <property name="eclipselink.logging.level" value="SEVERE"/>
        <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" />
        <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:mem;sql.enforce_strict_size=true;hsqldb.tx=mvcc" />
        <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
        <property name="eclipselink.ddl-generation.output-mode" value="database" />
        <property name="eclipselink.logging.level.sql" value="FINE"/>
        <property name="eclipselink.logging.parameters" value="true"/>
    </properties>
</persistence-unit>
Run Code Online (Sandbox Code Playgroud)

结果是

java.lang.AssertionError: 
Expected :1234
Actual   :0
Run Code Online (Sandbox Code Playgroud)

似乎有一些缓存没有被更新查询失效。checkResult并且fancyEntity是同一个对象。使用 强制刷新entityManager.refresh(checkResult)。最奇怪的是,aselect是为了检索而发出的checkResult(在 eclipselink 日志中看到),它的结果仍然没有被考虑在内。使用 MySQL 而不是 HSQL 的相同行为。

关于什么可能是错误的任何提示?

Ala*_*Hay 5

这是一个批量更新语句,正如 JPQL 语言参考所述:

持久化上下文与批量更新或删除的结果不同步。执行批量更新或删除操作时应谨慎,因为它们可能会导致数据库和活动持久性上下文中的实体之间出现不一致。通常,批量更新和删除操作应该只在单独的事务中或在事务开始时执行(在访问其状态可能受此类操作影响的实体之前)。

https://docs.oracle.com/html/E24396_01/ejb3_langref.html#ejb3_langref_bulk_ops )

所以你所看到的行为是完全有道理的。