These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 
Author Message
 Post subject: Question about Hibernate Transaction
PostPosted: Wed Jan 03, 2007 6:19 am 
Newbie

Joined: Wed Jan 03, 2007 4:12 am
Posts: 11
Location: Singapore
Dear all,

I have encountered the problem that I have an MDBean that is responsible to invoke a handler to create/update the common info into the DB. However, the modification of the first MDBean instance is not viewable to the second MDBean instance.

The MDBeans will be invoking a handler (in singleton) that deal with the creation/update of the common info. The handler will perform checking whether the common info already existed in the DB. If the info exist, the handler will perform an update, else it will create a new record in db.

The problem occured while the first MDBean already invoke the handler to persist the common info(already invoke the hibernate Transaction's commit method). The second MDBean instance invoke the handler and trying to create/update the common info, but the changes that made by the first MDBean is not visible to the 2nd MDBean instance. Thus, the handler encounter unique key violation constraint since it try to insert the same common info into db.

Such an issue is not always produceable, it happens while the second MDBean instance invoking the handler immediately after the first MDBean instance finished invoking the method in the handler.

The handler is implemented as a singleton and thread safe, so I am pretty sure there will not have concurrent creation of the same common info issue.

The way i obtain the hibernate session factory has been followed the guideline in the url http://docs.jboss.org/jbossas/jboss4gui ... mbean.sect.

I perform a jndi lookup to get the hibernate session given the jndi name and i did follow the session per request pattern.


The following is the snippet of my MDBean
Code:
public void onMessage(Message message)
  {
   
    try
    {
      ObjectMessage objMsg = (ObjectMessage)message;
      TrailData trailData = (TrailData)objMsg.getObject();
      TrailInfoHandler.getInstance().importInfo(trailData);
    }
    catch(Exception ex)
    {
      getLogger().logError("Error in processing the TrailData.", ex);
    }
  }



The following is the partial code of my handler
Code:
public synchronized void importInfo(TrailData trailData) throws AuditTrailTrackingException
  {
    TransactionHelper transHelper = new TransactionHelper();
    Info info = null;
    try
    {
      transHelper.beginTransaction();
     
      InfoHelper helper = InfoHelper .getInstance();
      info = (Info)trailData.getTrailnfo();
     
      String groupName = getGroupName(eventInfo.getID(), helper);

      //creating the common info
      handleCommonInfo(eventInfo, groupName);
     
     //more operations below ......

      transHelper.commitTransaction();
    }
    catch(AuditTrailTrackingException ex)
    {
      transHelper.rollBackTransaction();
      throw ex;
    }


Could I know why the second MDBean instance can't view the data that is inserted by the first MDBean instance? and how should I change my code in order to resolve such a problem?

Thanks in advance.


Last edited by niefeng1983 on Wed Jan 03, 2007 6:30 am, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 03, 2007 6:29 am 
Expert
Expert

Joined: Tue Dec 28, 2004 7:02 am
Posts: 573
Location: Toulouse, France
TransactionHelper class is one of yours? What does it do? Where do you open the session? Where do you close it? Aren't your problem related to the sharing of the session object: maybe you use the cache instead of the inserted data? Try calling session.clear() before querying the data you need? Do this in the code where you don't manage to access the rereshed data.

_________________
Baptiste
PS : please don't forget to give credits below if you found this answer useful :)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 03, 2007 6:51 am 
Newbie

Joined: Wed Jan 03, 2007 4:12 am
Posts: 11
Location: Singapore
batmat wrote:
TransactionHelper class is one of yours? What does it do? Where do you open the session? Where do you close it? Aren't your problem related to the sharing of the session object: maybe you use the cache instead of the inserted data? Try calling session.clear() before querying the data you need? Do this in the code where you don't manage to access the rereshed data.


Thanks for your quick reply, batmat :)

i ) TransactionHelper class is one of yours?
The TransactionHelper class is responsible to lookup the hibernate current session, and it also provide method to begin transaction, commit transaction and rollback transaction. After invoking the beginTransaction method in the TransactionHelper, i will cache the Transaction obj in the helper class. Thus, the subsequence invoke on the method commitTransaction and rollbackTransaction will make use of the cache transaction obj to commit or rollback.

ii) Where do you open the session? Where do you close it?
I didn't use the BMT, so i dun need to explicitly open the session or close it.

iii) Try calling session.clear() before querying the data you need? Do this in the code where you don't manage to access the rereshed data
I will try it.

iv) maybe you use the cache instead of the inserted data?
Could you elaborate more?


Thanks for ur help !


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 03, 2007 8:03 am 
Expert
Expert

Joined: Tue Dec 28, 2004 7:02 am
Posts: 573
Location: Toulouse, France
niefeng1983 wrote:
ii) Where do you open the session? Where do you close it?
I didn't use the BMT, so i dun need to explicitly open the session or close it.

Do you run in an appserver? If so, maybe have a look at the session management, so as to see for example how it's configured and if the threads are not sharing the same session...

niefeng1983 wrote:
iii) Try calling session.clear() before querying the data you need? Do this in the code where you don't manage to access the refreshed data
I will try it.

iv) maybe you use the cache instead of the inserted data?
Could you elaborate more?

It has to do with the iii) point. If your threads use a session in which they already retrieved data, the only way to force Hibernate to refresh() it to clear() the session, then ask for the data (well, not the only way, you can also call refresh() on a specific object that you know is not up to date, or even trash the session and create a new one, but anyway).

Also, verify that the session object is closed at commit. Depending on your conf, it might not be the case.

_________________
Baptiste
PS : please don't forget to give credits below if you found this answer useful :)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 03, 2007 8:54 am 
Newbie

Joined: Wed Jan 03, 2007 4:12 am
Posts: 11
Location: Singapore
batmat wrote:
Do you run in an appserver? If so, maybe have a look at the session management, so as to see for example how it's configured and if the threads are not sharing the same session...


Yah, I am running it within an appserver.

The follow is the configuration of the SessionFactory which defined in the hibernate-service.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE server>
<server>
<mbean code="org.jboss.hibernate.jmx.Hibernate" name="jboss.har:service=ISAT-Hibernate">
<attribute name="DatasourceName">java:/myDS</attribute>
<attribute name="Dialect">org.hibernate.dialect.PostgreSQLDialect</attribute>
<attribute name="SessionFactoryName">
java:/hibernate/TrailSessionFactory
</attribute>

<attribute name="DefaultSchema">trail</attribute>
<attribute name="ShowSqlEnabled">true</attribute>
<attribute name="Username">trail</attribute>
<attribute name="Password">trail</attribute>
</mbean>
</server>

The way I obtain the SessionFactory
Code:
public class HibernateUtil
{
  //the name is the jndi name as define in the above config file 
  public static SessionFactory getSessionFactory(String name) throws NamingException
  {
    JndiFinder finder = new JndiFinder(null);
    return (SessionFactory)finder.lookup(name, SessionFactory.class);
  }

}


The way i obtain the CurrentSession
Code:
public void beginTransaction()
  {
    _currTx = getCurrentSession().beginTransaction();
  }

public Session getCurrentSession()
{
  //the sessionFactory is obtained through the HibernateUtil
  return _sessionFactory.getCurrentSession();
}


I have compared the hashcode of the currentSession that obtained by the two MDBean, and they are different.


The following is the debug msg generated by the Hibernate.

//Note: the first MDBean instance
[03:01:07-19:15:13,645] [DEBUG:org.hibernate.jdbc.AbstractBatcher] [JMS SessionPool Worker-106] about to close PreparedStatement (open PreparedStatements: 1, globally: 38)
[03:01:07-19:15:13,645] [DEBUG:org.hibernate.jdbc.AbstractBatcher] [JMS SessionPool Worker-106] closing statement
[03:01:07-19:15:13,661] [DEBUG:org.hibernate.jdbc.AbstractBatcher] [JMS SessionPool Worker-106] closing JDBC connection (open PreparedStatements: 0, globally: 37) (open ResultSets: 0, globally: 0)
[03:01:07-19:15:13,661] [DEBUG:org.hibernate.event.def.AbstractFlushingEventListener] [JMS SessionPool Worker-106] post flush
[03:01:07-19:15:13,661] [DEBUG:org.hibernate.transaction.JTATransaction] [JMS SessionPool Worker-106] commit
//The first MDBean instance finsihed invoking the handler
[03:01:07-19:15:13,661] [ INFO:STDOUT] [JMS SessionPool Worker-106] 19:15:13,661 INFO [ISAT] [TrailInfoHandler.processTrailInfo()] End Process TrailInfo
[03:01:07-19:15:13,661] [ INFO:STDOUT] [JMS SessionPool Worker-106] End Process TrailInfo



//Second MDBean start accessing the handler, the first transaction seem like not yet completed.
[03:01:07-19:15:13,661] [ INFO:STDOUT] [JMS SessionPool Worker-107] 19:15:13,661 INFO [ISAT] [TrailInfoHandler.processTrailInfo()] Start processing TrailInfo
]
[03:01:07-19:15:13,661] [DEBUG:org.hibernate.transaction.CacheSynchronization] [JMS SessionPool Worker-106] transaction before completion callback
[03:01:07-19:15:13,661] [DEBUG:org.hibernate.transaction.CacheSynchronization] [JMS SessionPool Worker-106] automatically flushing session
[03:01:07-19:15:13,661] [DEBUG:org.hibernate.impl.SessionImpl] [JMS SessionPool Worker-106] automatically flushing session
[03:01:07-19:15:13,661] [DEBUG:org.hibernate.jdbc.JDBCContext] [JMS SessionPool Worker-106] before transaction completion
[03:01:07-19:15:13,661] [DEBUG:org.hibernate.impl.SessionImpl] [JMS SessionPool Worker-106] before transaction completion

-----
[03:01:07-19:15:13,661] [DEBUG:org.hibernate.transaction.JTATransaction] [JMS SessionPool Worker-107] begin
[03:01:07-19:15:13,661] [DEBUG:org.hibernate.transaction.JTATransaction] [JMS SessionPool Worker-107] Looking for UserTransaction under: UserTransaction
[03:01:07-19:15:13,661] [DEBUG:org.hibernate.transaction.JTATransaction] [JMS SessionPool Worker-107] Obtained UserTransaction


//
The second MDBean instance go and retrieve the commonInfo, but it can't find it


-----

[03:01:07-19:15:13,707] [DEBUG:org.hibernate.transaction.CacheSynchronization] [JMS SessionPool Worker-106] transaction after completion callback, status: 3
[03:01:07-19:15:13,707] [DEBUG:org.hibernate.jdbc.JDBCContext] [JMS SessionPool Worker-106] after transaction completion
[03:01:07-19:15:13,707] [DEBUG:org.hibernate.impl.SessionImpl] [JMS SessionPool Worker-106] after transaction completion
[03:01:07-19:15:13,707] [DEBUG:org.hibernate.transaction.CacheSynchronization] [JMS SessionPool Worker-106] automatically closing session
[03:01:07-19:15:13,707] [DEBUG:org.hibernate.impl.SessionImpl] [JMS SessionPool Worker-106] automatically closing session


[03:01:07-19:15:13,707] [DEBUG:org.hibernate.impl.SessionImpl] [JMS SessionPool Worker-106] closing session


Is it true that after the executed the above method, the changes made by the first MDBean instance will be written to the DB ?

How we ensure that the first transaction is completed prior we start the second transaction?

Many Thanks


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 03, 2007 9:19 am 
Expert
Expert

Joined: Tue Dec 28, 2004 7:02 am
Posts: 573
Location: Toulouse, France
I'm not sure, because I never used it yet, but I've got the impression that you're using second level cache. Are you? Maybe the sync pb comes from here.

niefeng1983 wrote:
Is it true that after the executed the above method, the changes made by the first MDBean instance will be written to the DB ?

Any changes will be in the db only if a commit appeared. So if the query of the second MDBean is executed before the first transaction is committed, it's totally normal it does not see the data (cf. transaction isolation level).

niefeng1983 wrote:
How we ensure that the first transaction is completed prior we start the second transaction?

I can't see a simple way to do it. You can try and synchronize both objects on a same resource, but since you run in an appserver that could be replicated on many machines, I don't think this approach would scale.

Maybe first try using a classical synchronization way to debug your code. If it works, then I guess you'll have to read some articles about syncing objects in a cluster.

_________________
Baptiste
PS : please don't forget to give credits below if you found this answer useful :)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 04, 2007 1:00 pm 
Newbie

Joined: Wed Jan 03, 2007 4:12 am
Posts: 11
Location: Singapore
Thanks batmat,

I followed your suggestion on synchronizing the MDBean instance. I have added a stateless session bean which on behalf the MDBean instance to invoke the handler.

The stateless session bean has been configured to use the bean managed transaction. Thus, I manually commit the transaction in the session bean instead of delay the commit in the MDBean.

As i synchronized the MDBean instance, the info/data that the first transaction has commited are viewable to the second transaction.

But it seem like this way will not be scalable in the future.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 05, 2007 3:29 am 
Expert
Expert

Joined: Tue Dec 28, 2004 7:02 am
Posts: 573
Location: Toulouse, France
niefeng1983 wrote:
The stateless session bean has been configured to use the bean managed transaction. Thus, I manually commit the transaction in the session bean instead of delay the commit in the MDBean.

As i synchronized the MDBean instance, the info/data that the first transaction has commited are viewable to the second transaction.

But it seem like this way will not be scalable in the future.

I'm sorry but I don't know what you speak about very well (is it EJB2?). But maybe try and explain why the second MDBean begins its transaction before the first one is finished.

Then, if your second one depends on the first, it seems to me like it's bizarre to make them "parallelizable", since they're typically sequential treatment isnt' it?

So, insteaf of doing two MDBeans, why can't you do only one why performs both processes, one after the other?

_________________
Baptiste
PS : please don't forget to give credits below if you found this answer useful :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.