>> 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 >>>>> >>>> >>>> >>> >> >