gpt4 book ai didi

java - Hibernate @NamedNativeQuery 读取 "normal"实体写入的陈旧数据持久化

转载 作者:行者123 更新时间:2023-11-28 23:33:35 29 4
gpt4 key购买 nike

我在使用 Hibernate 读取和写入 MySQL 的 Java (Dropwizard) Web 服务中遇到了一个有点奇怪的问题。我可以总结的最好方法是,当两个事务都在同一个 session 中时,在第二个事务中执行的 NamedNativeQuery 似乎看不到在一个事务中完成的写入。调试时,写入对外部 MySQL 客户端可见。当每个事务都在其自己的 session 中时,所有读取都会看到一致的世界 View 。这几乎就像写入 MySQL,但 NamedNativeQuery 正在从内存中的缓存版本读取。我会尝试更详细地解释...

为了描述这个问题,应用程序有三个 Hibernate 实体,它们使用相同的两个数据库表,我们只说表 X 和 Y 以及实体 A、B 和 C。其中两个实体(A 和 B)是使用 AbstractDAO (from Dropwizard) 中的方法将表中的行简单地映射到实体以进行读写,还可以使用 HQL 和 Hibernate Query API。因此表 X 中的一行映射到实体 A 的一个实例,表 Y 中的一行映射到实体 B 的一个实例。

第三个实体(实体 C)有点不同。它实际上是只读的,旨在通过连接表 X 和 Y 来收集一些聚合统计信息。它使用 @NamedNativeQuery 来执行单个 native MySQL 查询并映射到实体中的字段。此连接使用表 X 上指向表 Y 的外键。

这是我看到的行为:

Session session = sessionFactory.openSession();
ManagedSessionContext.bind(session);

Transaction tx = session.beginTransaction();

EntityA a = daoA.read(); // reads from table X using HQL query
EntityC c = daoC.read() // reads from X and Y using NamedNativeQuery
a.setFoo(newFoo);
daoA.write(a); // write using AbstractDao.persist. updates table X

tx.commit();

Transaction tx = session.beginTransaction();
c = daoC.read() // reads X and Y using NamedNativeQuery again. does not see write to table X above^
// while the app was paused in the debugger here, a MySQL client running the same native query sees the write when selecting from table X
tx.commit();

session.close();

这个版本有效:

Session session = sessionFactory.openSession();
ManagedSessionContext.bind(session);
Transaction tx = session.beginTransaction();

EntityA a = daoA.read();
EntityC c = daoC.read();
a.setFoo(newFoo);
daoA.write(a);

tx.commit();
session.close(); // Each tx has its own session

session = sessionFactory.openSession(); // new session, before only a new tx
ManagedSessionContext.bind(session);
tx = session.beginTransaction();

c = daoC.read() // reads using NamedNativeQuery again. now it DOES see the write above

tx.commit();
session.close();

抱歉,示例代码比较晦涩……显然,实际的应用程序要复杂得多。我对Hibernate了解不多所以我希望这是一些新手对事务和 session 的误解。如果事实证明这更复杂并且会有帮助,我可以尝试提取一个最小的示例来重现问题并且可以实际编译和运行。

最佳答案

问题是 hibernate persistenceContext 缓存,它短路了行 -> 对象转换,因为它已经看到了对象。

以下将起作用:

Session session = sessionFactory.openSession();
ManagedSessionContext.bind(session);

Transaction tx = session.beginTransaction();

EntityA a = daoA.read();
EntityC c = daoC.read();
a.setFoo(newFoo);
daoA.write(a);
session.flush();
tx.commit();

// This clears the persistenceContext cache and
// the actionQueue so make sure everything is
// done before this point.
session.clear();

Transaction tx = session.beginTransaction();
c = daoC.read();
tx.commit();

session.close();

另一种选择是使用无状态 session ,不过它对批量操作更有用。

关于java - Hibernate @NamedNativeQuery 读取 "normal"实体写入的陈旧数据持久化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36520575/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com