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

Reply via email to