【发布时间】:2013-03-26 06:32:42
【问题描述】:
我在使用 Hibernate 时遇到了一种奇怪的行为。一段时间以来,我一直在用头撞墙,并将奖励任何导致 +100 赏金解决方案的答案。
我有一个 JAX-RS (Jersey) REST 服务器,带有一个过滤器,每个请求关联一个 Hibernate 会话。
在一个请求中,客户端使用一个会话(和一个事务)发布一些存储在数据库中的数据。在随后的调用中,客户端尝试获取此实体,但 Hibernate 找不到它。
一些观察:
如果我同时运行多个客户端,我只能重现此问题。我从来没有通过一次运行一个客户端来重现它。)
我可以在数据库中看到实体 ID,如果我重新启动服务器,则 Hibernate 会正常找到该实体。
如果我使用大小为 1 的线程池(无论我同时运行多少个客户端),则不会发生错误。
这是代码,带有一些日志记录:
chargeables.setId(new SecureRandom().nextLong());
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.beginTransaction()");
session.beginTransaction();
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.save(id = "+chargeables.getId()+")");
session.save(chargeables);
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.getTransaction().commit()");
session.getTransaction().commit();
获取实体的代码:
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.get("+id+")");
Chargeables entity = (Chargeables) session.get(Chargeables.class, id);
if (entity == null)
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"ENTITY NOT FOUND!");
现在这里是结果日志的摘录(带有一些额外的打开/关闭会话输出):
Thread[Grizzly(5),5,main], session: 2041842357 [factory.openSession()]
Thread[Grizzly(5),5,main], session: 2041842357 [session.beginTransaction()]
Thread[Grizzly(5),5,main], session: 2041842357 [session.save(id = 7939229356942262438)]
Thread[Grizzly(5),5,main], session: 2041842357 [session.getTransaction().commit()]
Thread[Grizzly(5),5,main], session: 2041842357 [session.close()]
[...]
Thread[Grizzly(7),5,main], session: 1717445911 [factory.openSession()]
Thread[Grizzly(7),5,main], session: 1717445911 [session.get(7939229356942262438)]
Thread[Grizzly(7),5,main], session: 1717445911 [ENTITY NOT FOUND!]
Thread[Grizzly(7),5,main], session: 1717445911 [session.close()]
我到底为什么要联系ENTITY NOT FOUND!?
休眠版本:4.1.9.Final
MySQL 版本:14.14 Distrib 5.5.29
Chargeables 的映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping
default-cascade="all"
package="se.package.common.chargeables"
default-lazy="false">
<class name="Chargeables">
<id name="id" type="long">
<generator class="assigned"/>
</id>
<property name="startTimeStamp" />
<property name="endTimeStamp" />
<list name="chargeables">
<key column="chargeableId" />
<list-index column="pos" />
<many-to-many class="Chargeable"/>
</list>
</class>
<class name="Chargeable">
<id column="id" type="long">
<generator class="native"/>
</id>
<discriminator />
<property name="timestamp" />
</class>
<subclass name="DataTransfer" extends="Chargeable">
<property name="bytesSent" />
<property name="bytesReceived" />
</subclass>
<subclass name="TelephonyChargeable" extends="Chargeable">
<many-to-one name="num" />
</subclass>
<subclass name="Call" extends="TelephonyChargeable">
<property name="duration" />
</subclass>
<subclass name="OutgoingCall" extends="Call" />
<subclass name="IncomingCall" extends="Call" />
<subclass name="Message" extends="TelephonyChargeable" />
<subclass name="Sms" extends="Message" />
<subclass name="IncomingSms" extends="Sms" />
<subclass name="OutgoingSms" extends="Sms" />
<subclass name="Mms" extends="Message" />
<subclass name="IncomingMms" extends="Mms" />
<subclass name="OutgoingMms" extends="Mms" />
</hibernate-mapping>
【问题讨论】:
-
您是否为 Hibernate 开启了 SQL 日志记录?愚蠢的问题:您对该实体的 ID 生成策略是什么?
-
我还没有打开 SQL 日志记录。这显然是个好主意。生成策略是“分配的”。
-
代码看起来不错。请向我们展示您对 Chargeables 的注释或提供映射文件。看看你有什么。
-
由于我的网络限制无法访问,请在此处添加。
-
使用 mapping-xml 更新答案。
标签: multithreading hibernate session concurrency transactions