Hibernate的线程问题 [英] Threading issues with Hibernate

查看:120
本文介绍了Hibernate的线程问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个奇怪的行为与Hibernate。我已经把我的头撞在墙上了一段时间,并将奖励任何答案,导致一个+100奖金的解决方案。



我有一个JAX -RS(Jersey)REST服务器,带有一个过滤器,用于关联每个请求的一个Hibernate会话。



在一个请求中,客户端POST存储在数据库中的一些数据一个会话(和一个事务)。在后续调用中,客户端尝试获取此实体,但Hibernate找不到它。



一些观察结果:


  • 如果我同时运行多个客户端,我只能重现这个。 )


  • 在实体ID中查看实体ID。数据库,如果我重新启动服务器,实体被Hibernate找到它应该。


  • 如果我使用线程池大小的错误不会发生




这是代码,有一些日志记录:

  chargeables.setId(new SecureRandom()。nextLong()); 

System.out.printf(%s,session:%s [%s]%n,
Thread.currentThread(),
System.identityHashCode ,
session.beginTransaction());

session.beginTransaction();


System.out.printf(%s,session:%s [%s]%n,
Thread.currentThread(),
系统。 identityHashCode(session),
session.save(id =+ chargeables.getId()+));

session.save(chargeables);


System.out.printf(%s,session:%s [%s]%n,
Thread.currentThread(),
系统。 identityHashCode(session),
session.getTransaction()。commit());

session.getTransaction()。commit();

获取实体的代码:

  System.out.printf(%s,session:%s [%s]%n,
Thread.currentThread(),
System.identityHashCode会话),
session.get(+ id +));

Chargeables entity =(Chargables)session.get(Chargables.class,id);

if(entity == null)
System.out.printf(%s,session:%s [%s]%n,
Thread.currentThread ,
System.identityHashCode(session),
ENTITY NOT FOUND!);

现在这里是一个摘录的结果日志(与一些额外的打开/关闭会话输出):

 线程[Grizzly(5),5,main],session:2041842357 [factory.openSession()] 
[Grizzly(5),5,main],session:2041842357 [session.save(id = 7939229356942262438)] [session.beginTransaction()]

线程[Grizzly(5),5,main],session:2041842357 [session.getTransaction()。commit()会话:1717445911 [factory.openSession()]
线程[Grizzly(7),5,main] ),session:1717445911 [session.get(7939229356942262438)]
线程[Grizzly(7),5,main],session:1717445911 [ENTITY NOT FOUND!]
Thread [Grizzly (7),5,main],session:1717445911 [session.close()]

地球到达 ENTITY未找到






Hibernate版本:4.1.9.Final├
MySQL verison:14.14 Distrib 5.5.29






映射文件费用

 <?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.chargables
default-lazy =false >


< class name =Chargables>

< id name =idtype =long>
< generator class =assigned/>
< / id>

< property name =startTimeStamp/>
< property name =endTimeStamp/>

< list name =feeables>
< key column =chargeableId/>
< list-index column =pos/>
< many-to-many class =Chargeable/>
< / list>

< / class>


< class name =Chargeable>

< id column =idtype =long>
< generator class =native/>
< / id>

< discriminator />

< property name =timestamp/>

< / class>


< subclass name =DataTransferextends =Chargeable>
< property name =bytesSent/>
< property name =bytesReceived/>
< / subclass>


< subclass name =TelephonyChargeableextends =Chargeable>
< many-to-one name =num/>
< / subclass>

< subclass name =Callextends =TelephonyChargeable>
< property name =duration/>
< / subclass>

< subclass name =OutgoingCallextends =Call/>
< subclass name =IncomingCallextends =Call/>

< subclass name =Messageextends =TelephonyChargeable/>

< subclass name =Smsextend =Message/>
< subclass name =IncomingSmsextends =Sms/>
< subclass name =OutgoingSmsextends =Sms/>

< subclass name =Mmsextends =Message/>
< subclass name =IncomingMmsextends =Mms/>
< subclass name =OutgoingMmsextends =Mms/>


< / hibernate-mapping>


解决方案

如果您可以在数据库中看到提交不能是MySQL级别的隔离问题:控制台操作也是客户端操作,运行它们时不会获得特殊权限,因此它们符合您选择的隔离策略。



寻找解决方案,我发现:实际上有2级缓存实现。也许你的hibernate安装捆绑了一个缓存机制?



第一级在每个会话的基础上工作,这与你在一个代码上运行时的行为是一致的线程,似乎恰好是默认激活。我不是Hibernate精通,我不能说肯定,但我的意见是,你的设置有这个第一级的缓存设置为只读模式,而你希望它处于读写模式。 p>

I'm experiencing a strange behaviour with Hibernate. I've been banging my head against the wall for a while now, and will award any answer which leads to a solution with a +100 bounty.

I have a JAX-RS (Jersey) REST server, with a filter that associates one Hibernate-session per request.

In one request a client POSTs some data which is stored in the database using one session (and one transaction). In a subsequent call, the client tries to GET this entity, but Hibernate can't find it.

Some observations:

  • I can only reproduce this if I run multiple simultaneous clients. I've never managed to reproduce it by running one client at a time.)

  • I can see the entity ID in the database, and if I restart the server, the entity is found by Hibernate as it should.

  • The error does not occur if I use a thread pool of size 1 (regardless of how many clients I run simultaneously).

Here's the code, with some logging:

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();

The code for getting the entity:

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!");

Now here is an excerpt of the resulting log (with some additional open/close session output):

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()]

Why on earth do I reach ENTITY NOT FOUND!?


Hibernate version: 4.1.9.Final
MySQL verison: 14.14 Distrib 5.5.29


Mapping file for 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>

解决方案

If you can see the commit in the database, it cannot be an isolation issue at the MySQL level: console operations are also client operations, you don't get special powers when running them, so they conform to the isolation policy you selected.

Looking out for solution, I discovered that Hibernate provide some facilities to cache DB results: there are actually 2 levels of cache implemented there. Perhaps your hibernate installation comes bundled with a cache mechanism?

The first level works on a per session basis, which is consistent with the behaviour you observe when running the code on one thread, and seemingly happens to be activated by default. I am not Hibernate proficient, I can't say that for sure, but my opinion is that your setup has this first level of cache set in read-only mode, while you would like it to be in read-write mode.

这篇关于Hibernate的线程问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆