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