Thanks Martin, if I understood you correctly, you are still Injecting the Session. Will this cause any issues where I'm still using @CommitAfter? Also in the batch job, do you typically put an additional commit outside the loop to pickup up the remaining values when they don't reach the count, say % 250 == 0 mark or do you just put an additional condition in there to commit when you hit the last record?
so something like this, if(count % 250 == 0 || count == size) On Fri, Oct 25, 2013 at 10:03 AM, Martin Kersten < martin.kersten...@gmail.com> wrote: > well you are decorating the session not the session source of cause... . > > > 2013/10/25 Martin Kersten <martin.kersten...@gmail.com> > > > >> Perhaps you want a @MaybeCommitAfter ;) > > > > What about simply having @WriteTransaction (und @ReadTransaction, since > > lacking support for read transactions is the biggest performance issue > when > > dealing with databases). If you are inside a method annotated with > > @WriteTransaction it is ignored. If nesting write within a read > transaction > > fails (there is something wrong with your service methods / thinking). > And > > also wrapping the session source (decorate) and checking on any > > save+/update/delete + query if a transaction was set makes it crystal > > clear if you messed up the transactional thingy. Also using @CommitAfter > > inside a @XxxxTransaction fails, since you can not commit inside it > without > > breaking the meaning. > > > > This would make it possible to have a good implementation which is self > > explaining, would only cost two hours to build and test (at least I > havent > > spent an hour in total I think). And it wont break the backward > > compatibility with @CommitAfter. > > > > > > 2013/10/25 Martin Kersten <martin.kersten...@gmail.com> > > > >> And George, read this one: > >> > http://stackoverflow.com/questions/10143880/hibernate-queries-much-slower-with-flushmode-auto-until-clear-is-called > . > >> It explains why you experience the slow downs and what is it causing it. > >> > >> > >> 2013/10/25 Martin Kersten <martin.kersten...@gmail.com> > >> > >>> You might also want to use such kind of a utility that allows you to > run > >>> in transaction: > >>> > >>> public interface InTransaction<T> { > >>> public T run(Session session); > >>> } > >>> > >>> public static <T> T DatabaseUtil.process(InTransaction<T> > >>> transactionalRunnable) { > >>> try { > >>> Session session = currentSession(); //or newSession() > >>> if(!session.getTransaction().isActive()) > >>> session.beginTransaction(); > >>> T result = transactionalRunnable.run(session); > >>> if(!session.getTransaction.isActive()) { > >>> session.getTransaction().commit(); > >>> session.clear(); > >>> } > >>> } > >>> catch(RuntimeException e) { > >>> if(session.getTransaction().isActive()) { > >>> session.getTransaction().rollback(); > >>> session.clear(), > >>> } > >>> } > >>> finally { > >>> //session.close(); //if you created a new one > >>> } > >>> } > >>> > >>> > >>> This way you can control the whole transactional process while only > >>> doing: > >>> > >>> List<Product> product = DatabaseUtil.process(new > >>> InTransaction<List<Product>>() { > >>> List<Product> run(Session session) { > >>> //getUser etc are all static methods fetching from a > >>> ThreadLocal RequestContext object so you dont need > >>> //to inject / pass along parts of your model in every > >>> component/page > >>> UserInfo user = getUser(); > >>> userStats.countUserRequest(user); //changes the database; > >>> return queryProductsForUser(user, session); //returning a > list > >>> } > >>> } > >>> > >>> This example is just made up to demonstrate that you can return a > >>> List<Product> or Integer or if you have nothing to return > >>> a Void instance. > >>> > >>> The DatabaseUtil class I use for everything that happends outside of a > >>> request therefore when I have to control the sessions > >>> being opened, closed and manage the transaction. This way you even not > >>> run into any difficult with nesting (you can not > >>> leave the transaction (since it is an enclosed try catch block), > >>> > >>> I have set my session to automatically clear the persistence context on > >>> commit. > >>> You can do this by ((SessionImpl)session).setAutoClear(true). > >>> > >>> And of cause checking if a transaction is active can be extracted to a > >>> private method to value the DRY principle. > >>> > >>> > >>> > >>> > >>> 2013/10/25 Martin Kersten <martin.kersten...@gmail.com> > >>> > >>>> > session.flush(); > >>>> > session.clear(); > >>>> > hibernateSessionManager.commit(); > >>>> > >>>> This is wrong. > >>>> First on commit you will do the flush automatically (flush means all > >>>> changes are written to the database (performing outstanding updates, > >>>> inserts, deletes)) > >>>> Clear clears the persistence context of all entities not taking part > on > >>>> any outstanding flush event (as far as I remember) therefore > Hibernate does > >>>> a deep > >>>> inspection of the active entities and removes all entities that were > >>>> not encountered during that process. > >>>> Commit commits the entities. > >>>> > >>>> So the correct usage is: > >>>> session.getTransaction().commit(); > >>>> session.clear(); > >>>> session.beginTransaction(); > >>>> > >>>> (without the clear its what HibernateSessionManager is doing with the > >>>> session bound to the current thread). > >>>> > >>>> > >>>> > >>>> > >>>> 2013/10/25 Martin Kersten <martin.kersten...@gmail.com> > >>>> > >>>>> Use: > >>>>> > >>>>> @Inject > >>>>> Session session; //current session bound to the current thread > >>>>> > >>>>> > >>>>> or > >>>>> > >>>>> @Inject > >>>>> HibernateSessionSource source; + source.create() for a really new > >>>>> session (CommitAfter would not work with newly created one); > >>>>> > >>>>> Using the Manager does give you only the session associated with the > >>>>> current thread as would @Inject Session session; would do. > >>>>> > >>>>> > >>>>> > >>>>> > >>>>> 2013/10/25 George Christman <gchrist...@cardaddy.com> > >>>>> > >>>>>> So I guess I'm still a little confused as to what is the best to do > >>>>>> it. > >>>>>> @CommitAfter seems to work fine for individual transactions but does > >>>>>> not > >>>>>> work well with batch jobs do to it holding on to the object in > memory. > >>>>>> Anyhow, I could not figure out how to get Martins > >>>>>> session.getTransaction() > >>>>>> to work, however I did end up getting the following code to work. > >>>>>> Could > >>>>>> someone tell me if I'm doing this correctly? Also should I be > closing > >>>>>> and > >>>>>> rolling back the transaction? > >>>>>> > >>>>>> //Mock scenario > >>>>>> > >>>>>> @Inject > >>>>>> private HibernateSessionManager hibernateSessionManager; > >>>>>> > >>>>>> public void onActionFromTest() { > >>>>>> Session session = hibernateSessionManager.getSession(); > >>>>>> > >>>>>> for (int i = 0; i < 100000; i++) { > >>>>>> employee = new Employee("George " + i); > >>>>>> > >>>>>> session.save(employee); > >>>>>> > >>>>>> if (i % 250 == 0) { > >>>>>> session.flush(); > >>>>>> session.clear(); > >>>>>> hibernateSessionManager.commit(); > >>>>>> } > >>>>>> } > >>>>>> > >>>>>> session.flush(); > >>>>>> session.clear(); > >>>>>> hibernateSessionManager.commit(); > >>>>>> > >>>>>> > >>>>>> > >>>>>> On Fri, Oct 25, 2013 at 9:07 AM, Thiago H. de Paula Figueiredo < > >>>>>> thiag...@gmail.com> wrote: > >>>>>> > >>>>>> > On Fri, Oct 25, 2013 at 10:53 AM, Barry Books <trs...@gmail.com> > >>>>>> wrote: > >>>>>> > > >>>>>> > While it's true you can run into problems by nesting @CommitAfter > >>>>>> the same > >>>>>> > > can be said about nesting any commits. The Tapestry database > >>>>>> model is > >>>>>> > > simple. There is one connection per request and when you call > >>>>>> commit it > >>>>>> > > does a commit. > >>>>>> > > > >>>>>> > > >>>>>> > <pedantic> > >>>>>> > Tapestry itself doesn't have any database model. It's a web > >>>>>> framework and > >>>>>> > nothing else. You can use it with any database, including none. > >>>>>> > Tapestry-Hibernate is a package that provides *simple* support for > >>>>>> > Hibernate and should be used in *simple* scenarios. If you need > >>>>>> something > >>>>>> > that's not simple, like any transaction handling not supported by > >>>>>> > @CommitAfter, use Tapestry and some transaction handler (EJB, > >>>>>> Spring-TX, > >>>>>> > etc) but not Tapestry-Hibernate. > >>>>>> > </pedantic> > >>>>>> > > >>>>>> > > >>>>>> > > >>>>>> > > > >>>>>> > > > >>>>>> > > On Fri, Oct 25, 2013 at 7:31 AM, Lance Java < > >>>>>> lance.j...@googlemail.com > >>>>>> > > >wrote: > >>>>>> > > > >>>>>> > > > I'm assuming a fork is broken too because it's no good for > >>>>>> eating soup? > >>>>>> > > > Sounds like you need a spoon, it's easy to write your own > >>>>>> annotation... > >>>>>> > > > Perhaps you want a @MaybeCommitAfter ;) > >>>>>> > > > > >>>>>> > > > >>>>>> > > >>>>>> > > >>>>>> > > >>>>>> > -- > >>>>>> > Thiago > >>>>>> > > >>>>>> > >>>>>> > >>>>>> > >>>>>> -- > >>>>>> George Christman > >>>>>> www.CarDaddy.com > >>>>>> P.O. Box 735 > >>>>>> Johnstown, New York > >>>>>> > >>>>> > >>>>> > >>>> > >>> > >> > > > -- George Christman www.CarDaddy.com P.O. Box 735 Johnstown, New York