-->
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.  [ 11 posts ] 
Author Message
 Post subject: piggyback StatelessSession on normal Session
PostPosted: Wed Jun 18, 2008 2:31 am 
Beginner
Beginner

Joined: Sun Aug 22, 2004 11:00 am
Posts: 21
i have a somewhat unique requirement in that i need to perform some batch processing within a process that also has normal business logic. ive searched the forums countless times for other scenarios using the StatelessSession but i dont see anything particularly helpful..thus im asking in a new thread. i apologize in advance for the long comment but im trying to explain the scenario properly.

so basically the process flow is as follows:

1. start of process
2. do some work
3. do a lot of batch inserts/updates/deletes
4. do some more work
5. end of process

in step 2 i load and persist some entities with relationships and collections.
in step 3 i am persisting millions of POJO value objects.
in step 4 i am working again with entities with relationships and collections

i want the whole process to execute atomically within a transaction (i.e. either all steps 1-5 succeed or they fail)

in order to perform steps 2 and 4 i want to use a regular session and for step 3 i would like to use a StatelessSession

what im trying to do is piggyback a StatelessSession on a Session using the following technique
Code:
//start of process
Session session = sf.getCurrentSession();
session.beginTransaction();

//do work in step 2 using session

StatelessSession statelessSession = sf.openStatelessSession(sf.getCurrentSession().connection());

//do work in step 3 using statelessSession

//do work in step 4 using session

sf.getCurrentSession().getTransaction().commit();
//end of process

unfortunately, this doesnt seem to work. the only way i can get it to work is if i invoke beginTransaction() on the statelessSession before step 3 and then call commit() on the statelessSession after step 3. essentially beginning and committing two transactions on the same jdbc connection. im confused as to why this is needed? when i wrap step 3 in its own transaction using the StatelessSession interface, i get the debug output listed below.....its as if two seperate JDBC connections are being used. is a nested subtransaction actually occurring (i.e. where a committed inner transaction is only permanent if the outer transaction commits)? for me a single flat transaction would be best (which is why i tried to piggyback the connection).

is there some way to properly accomplish what im trying to do in a fully atomic way?

Code:
18 Jun 2008 02:15:33,188 DEBUG TransactionAspect - Beginning Session transaction
18 Jun 2008 02:15:33,668 DEBUG JDBCTransaction - begin
18 Jun 2008 02:15:33,670 DEBUG JDBCTransaction - current autocommit status: false
18 Jun 2008 02:15:33,671 DEBUG HibernateXpressfeedDAO - Openning new StatelessSession on Session connection
18 Jun 2008 02:15:33,787 DEBUG HibernateXpressfeedDAO - Beginning StatelessSession transaction
18 Jun 2008 02:15:33,788 DEBUG JDBCTransaction - begin
18 Jun 2008 02:15:33,788 DEBUG JDBCTransaction - current autocommit status: false
18 Jun 2008 02:15:33,894 DEBUG HibernateXpressfeedDAO - Committing StatelessSession transaction
18 Jun 2008 02:15:33,895 DEBUG JDBCTransaction - commit
18 Jun 2008 02:15:33,902 DEBUG JDBCTransaction - committed JDBC Connection
18 Jun 2008 02:15:33,903 DEBUG TransactionAspect - Committing Session transaction
18 Jun 2008 02:15:33,903 DEBUG JDBCTransaction - commit
18 Jun 2008 02:15:33,905 DEBUG JDBCTransaction - committed JDBC Connection

in case anyone is wondering, the process is executed by a single thread, im using hibernate 3, mysql innodb and the following properties:
hibernate.jdbc.batch_size=80
hibernate.cache.use_second_level_cache=false
hibernate.transaction.factory_class=org.hibernate.transaction.JDBCTransactionFactory
hibernate.current_session_context_class=thread
hibernate.connection.autocommit=false

thanks in advance

_________________
Ive got a Tomcat that Struts then Springs then Hibernates


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 18, 2008 3:39 pm 
Beginner
Beginner

Joined: Sun Aug 22, 2004 11:00 am
Posts: 21
does anyone have any clue why this isnt working?

from what ive gathered, in mysql if you begin a new transaction on a connection that already has a running transaction then it automatically commits the changes up until the point where the 2nd tx begins. so in other words, attempting to call begin transaction on the StatelessSession that was instantiated using the Session's connection is a bad idea.

what i dont understand is why the changes made by the StatelessSession on the piggybacked session arent being executed/commited.

i thought the connection retrieved by Session.connection() is maybe some sort of "fake" object. so i checked out the source and it is indeed a proxy wrapper connection (BorrowedConnectionProxy) but that seems to wrap the real connection.

maybe someone could better explain what one needs to do to properly use a connection hijacked from a Session...?

_________________
Ive got a Tomcat that Struts then Springs then Hibernates


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 18, 2008 11:53 pm 
Beginner
Beginner

Joined: Sun Aug 22, 2004 11:00 am
Posts: 21
ok now im just lost.

if i hijack a connection from a Session object and then perform a manual insert using jdbc and the raw connection, when i commit the Session/transaction (using the Session api), then the changes are persisted fine.

what is so special about creating a StatelessSession using an existing connection? is this a bug?

_________________
Ive got a Tomcat that Struts then Springs then Hibernates


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 19, 2008 2:06 am 
Beginner
Beginner

Joined: Sun Aug 22, 2004 11:00 am
Posts: 21
10 bucks via paypal to anyone that can pull this off?

_________________
Ive got a Tomcat that Struts then Springs then Hibernates


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 20, 2008 5:46 pm 
Beginner
Beginner

Joined: Sun Aug 22, 2004 11:00 am
Posts: 21
ok i finally figured this out. there appears to be a bug in the way StatelessSession behaves.

i finally managed to get this to work by setting the JDBC batch size to 1. originally i was using a batch size of 80.

here is how i discovered the problem.

Code:
SessionFactory sf = ...
Connection conn = dataSource.getConnection();
conn.setAutoCommit(false);

Session session = sf.openSession(conn);
StatelessSession statelessSession = sf.openStatelessSession(conn);

session.save(security1);
statelessSession.insert(security2);
session.flush();

conn.commit();

session.close();
statelessSession.close();


debugging through the statelessSession.insert() call, i realized that if the number of records inserted is less than the JDBC batch size, then the stateless session never actually executes the batch. i think the flaw in the behaviour is due to the fact that Hibernate assumes one will use their Transaction API to initiate and commit the transaction. in that case, the transaction.commit() invocation ends up pushing any "leftover" inserts to the DB. i say "leftover" because this will usually be the case at the very end of a large batch insert when:
( totalNumberOfRecordsToInsert mod jdbcBatchSize ) != 0

by setting the JDBC batch size to 1, each call to statelessSession.insert() actually results in an insert in the DB. of course in this case we lose the benefits of batching entirely.

unfortunately there is no way to force the stateless session to push those "leftover" inserts to the DB as the normal Session offers through the flush() method.

can a hibernate expert perhaps comment on whether this behaviour is intended? at this time the only solution i can see is to cast the StatelessSession to a SessionImplementor, retrieve the batcher via getBatcher() and call executeBatch() when processing the final group of records.

_________________
Ive got a Tomcat that Struts then Springs then Hibernates


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 23, 2008 11:13 am 
Expert
Expert

Joined: Tue May 13, 2008 3:42 pm
Posts: 919
Location: Toronto & Ajax Ontario www.hibernatemadeeasy.com
Thanks for the update.

Although this thread would seem like you're having a conversation with yourself, I've found it interesting. :)

_________________
Cameron McKenzie - Author of "Hibernate Made Easy" and "What is WebSphere?"
http://www.TheBookOnHibernate.com Check out my 'easy to follow' Hibernate & JPA Tutorials


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 02, 2009 10:58 am 
Newbie

Joined: Tue May 20, 2008 9:33 am
Posts: 6
Hi Bennini,

Did you find a proper solution for this flush issue? if not can you post your hacky flush code please?


Regards,
Ced.


Top
 Profile  
 
 Post subject: Re: piggyback StatelessSession on normal Session
PostPosted: Thu Jul 16, 2009 9:35 pm 
Newbie

Joined: Tue Feb 07, 2006 5:55 am
Posts: 1
Location: Lyon, France
I've encountered the same problem and I've created a jira entry about this : http://opensource.atlassian.com/project ... e/HHH-4042


Top
 Profile  
 
 Post subject: Re: piggyback StatelessSession on normal Session
PostPosted: Fri Sep 25, 2009 11:47 am 
Regular
Regular

Joined: Fri May 22, 2009 4:50 am
Posts: 59
Hi Bennini,

I refered to your other threads as well regarding bulk insert. As you rightly said its better use stateless session with hibernate when object is simple and without any collection.

But thats pretty useless to me. what are the faster options that one has when object contains collection maps?

Thanks


Top
 Profile  
 
 Post subject: Re: piggyback StatelessSession on normal Session
PostPosted: Fri Oct 22, 2010 12:15 am 
Regular
Regular

Joined: Tue Feb 19, 2008 6:05 pm
Posts: 82
shagufta wrote:
Hi Bennini,

I refered to your other threads as well regarding bulk insert. As you rightly said its better use stateless session with hibernate when object is simple and without any collection.

But thats pretty useless to me. what are the faster options that one has when object contains collection maps?

Thanks


A session with flush(), jdbc batch_size > 1, disabled second level cache and disabled interceptors... to start with.

Question is, if we are committing 100 records in one commit using the same statelessSession/session, shouldn't it be intelligent enough to automatically commit 100 records in jdbc batch, why even specify the batch_size somewhere in the configuration, may be they should expose it as a runtime rather than a global constant.

Committing 1000 records using statelessSession with a batch size of 500, will commit 500 in a batch and 500 again rather than 500 separate inserts?


Top
 Profile  
 
 Post subject: Re: piggyback StatelessSession on normal Session
PostPosted: Thu Feb 17, 2011 3:42 pm 
Regular
Regular

Joined: Tue Feb 19, 2008 6:05 pm
Posts: 82
http://opensource.atlassian.com/project ... e/HHH-5935

execute(new StatelessHibernateCallback<T>() {
public T doInStatelessSession(StatelessSession statelessSession) {
for(Entity entity : entitiesBatch)
{
statelessSession.insert(entity);
}
return null;
}
});

inserts entity by entity which is completely ABSURD. Should'nt it insert all of them or none, rather it is inserting one by one by default. I have been using this to insert millions of records assuming it is batching, which is a shame.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 11 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.