Using Hibernate detached objects in Tapestry (thread-safety question)

classic Classic list List threaded Threaded
24 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Using Hibernate detached objects in Tapestry (thread-safety question)

Michael Sims
I know this isn't strictly Tapestry related, but since there has been a lot of
discussion here over the years related to integrating Hibernate with Tapestry, I was
hoping I could draw on the community knowledge about this topic and get a little
advice.  My apologies if this has been discussed before, I did extensive searching
before posting but still might have missed something.

My specific dilemma at the moment is how to implement session-per-request with
detached objects in a thread-safe manner.  Chapter 8 of the _Hibernate in Action_
book discusses the issues of detached objects and thread safety.  It gives the
example of a user submitting a form twice, and I can think of several other
scenarios which would cause two or more threads to access the HttpSession
simultaneously.  The book suggests a few solutions to this problem: rejecting
additional requests if one is currently processing, serializing all requests from
the same user by synchronizing on the HttpSession in a servlet filter, and finally
maintaining a map of session information to separate windows in a multi-window
application.

None of these solutions seem to be workable in my situation.  We are making
extensive use of assets for all of our images and CSS files, so there really is no
static content in our application; every request is going to be serviced by the
servlet.  The first two solutions aren't practical as even loading my application's
login page will open at least 4 concurrent requests (two CSS files, several images,
the HTML document, etc.) and if these requests are serialized I am of the opinion
that this will noticeably impact perceived performance of the application and will
impact scalability in the long run.  The final solution (mapping between windows)
doesn't solve the issue of users opening multiple tabs or windows as each window
will have the same name/identifier.

So, I'm struggling to come up with a solution to this that doesn't require me to
abandon detached objects.  I have an idea for a solution, but it seems cumbersome
and I was hoping to get some suggestions or feedback on this.

My idea is to explicitly synchronize only the sections of the code in my request
action handlers that have to work with the potentially shared detached objects.  My
plan is to synchronize either on a mutex object, or one of the detached objects, and
within the synchronized block update() the detached object, perform my model
manipulations, commit the transaction, close the session, then end the lock.  It
would still be possible for more than one thread to share a given detached object,
but this would prevent my code from attempting to attach the object(s) to more than
one session simultaneously.

(As an aside, I looked at the Tapernate code, since it includes persistence
strategies that use Hibernate detached objects.  However, unless I'm missing
something, it doesn't seem to be taking thread safety of detached objects into
account at all, which I find curious.)

Can someone with a little more experience with this sort of thing give me some
advice on this?  Does my approach above sound workable, or is there something better
that some of you are already doing?  Should I just forget about detached objects and
squeeze/unsqueeze my entities down to identifers and retrieve them anew on each
request?  Any help or advice would be greatly appreciated...


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Using Hibernate detached objects in Tapestry (thread-safety question)

Norman Franke-2
I should note that I'm using Tapestry 4.0.x for my application. I'm  
also pretty new to both Hibernate and Tapestry, so this may not be  
the best. It does, however, seem to work well.

My application only uses detached objects that it persists in the  
client page for change detection (to determine if the record they  
were editing changed while they were editing, which I flag as an  
error.) Otherwise, I just re-query as needed for each page. I have a  
single session per page, so if it queries multiple times (say once  
during rewind and once not in rewind), the Hibernate session cache  
prevents excessive queries to the database.

I use HiveMind to inject DAOs for each class, and a SessionManager  
object (of my own design) as needed by each page. The session manager  
uses a threaded model in HiveMind, so I can get a call back when the  
page is done being rendered (implementing  
org.apache.hivemind.Discardable.) The first call to getSession()  
creates a HIbernate session, which is closed when the page is done  
rendering. Each DAO gets its session via HiveMind, so I don't have to  
worry about that either. Each page can inject as many DAOs as needed,  
and they all end up in the same Hibernate session.

I have a "setShouldRollback" function to flag the page's session to  
be rolled back when it finishes, to ensure we don't create two  
Hibernate sessions for a single page. If I want to rollback a page, I  
want it all to be rolled back.

To persist a detached object, I call a clone() function on all of my  
DB objects that converts it back to a normal POJO (from whatever  
Hibernate does to it.) I could, I assume, persist this clone in the  
session via Tapestry as well. One could then re-attach the object to  
Hibernate during the next page render. In my case, my DAO has an  
"assertUnchanged" method that throws an exception if the two objects  
differ, e.g. my detached object and the one read from the database.  
In this case, I tell the user that someone else changed their record  
and their changes have been lost.

The only glitches I noticed is when saving a record (i.e. not rolling  
back) from a listener and returning another page (i.e. a direct  
service.) I don't want them to be in the same session, since cached  
data from the page with the listener gets stuck on the next page. It  
also caused problems when a validator flagged errors. To get around  
these problems, if the validator has errors, I clear the session and  
flag a rollback. In the other case, the listener explicitly closes  
the transaction if everything went well. The next page (as a direct  
service) opens a new session like I want.

This approach uses no locks or mutexes. It allows multiple pages to  
render simultaneously, each in a different Hibernate session to keep  
things consistent.

-Norman

On Jun 15, 2007, at 5:14 PM, Michael Sims wrote:

> I know this isn't strictly Tapestry related, but since there has  
> been a lot of
> discussion here over the years related to integrating Hibernate  
> with Tapestry, I was
> hoping I could draw on the community knowledge about this topic and  
> get a little
> advice.  My apologies if this has been discussed before, I did  
> extensive searching
> before posting but still might have missed something.
>
> My specific dilemma at the moment is how to implement session-per-
> request with
> detached objects in a thread-safe manner.  Chapter 8 of the  
> _Hibernate in Action_
> book discusses the issues of detached objects and thread safety.  
> It gives the
> example of a user submitting a form twice, and I can think of  
> several other
> scenarios which would cause two or more threads to access the  
> HttpSession
> simultaneously.  The book suggests a few solutions to this problem:  
> rejecting
> additional requests if one is currently processing, serializing all  
> requests from
> the same user by synchronizing on the HttpSession in a servlet  
> filter, and finally
> maintaining a map of session information to separate windows in a  
> multi-window
> application.
>
> None of these solutions seem to be workable in my situation.  We  
> are making
> extensive use of assets for all of our images and CSS files, so  
> there really is no
> static content in our application; every request is going to be  
> serviced by the
> servlet.  The first two solutions aren't practical as even loading  
> my application's
> login page will open at least 4 concurrent requests (two CSS files,  
> several images,
> the HTML document, etc.) and if these requests are serialized I am  
> of the opinion
> that this will noticeably impact perceived performance of the  
> application and will
> impact scalability in the long run.  The final solution (mapping  
> between windows)
> doesn't solve the issue of users opening multiple tabs or windows  
> as each window
> will have the same name/identifier.
>
> So, I'm struggling to come up with a solution to this that doesn't  
> require me to
> abandon detached objects.  I have an idea for a solution, but it  
> seems cumbersome
> and I was hoping to get some suggestions or feedback on this.
>
> My idea is to explicitly synchronize only the sections of the code  
> in my request
> action handlers that have to work with the potentially shared  
> detached objects.  My
> plan is to synchronize either on a mutex object, or one of the  
> detached objects, and
> within the synchronized block update() the detached object, perform  
> my model
> manipulations, commit the transaction, close the session, then end  
> the lock.  It
> would still be possible for more than one thread to share a given  
> detached object,
> but this would prevent my code from attempting to attach the object
> (s) to more than
> one session simultaneously.
>
> (As an aside, I looked at the Tapernate code, since it includes  
> persistence
> strategies that use Hibernate detached objects.  However, unless  
> I'm missing
> something, it doesn't seem to be taking thread safety of detached  
> objects into
> account at all, which I find curious.)
>
> Can someone with a little more experience with this sort of thing  
> give me some
> advice on this?  Does my approach above sound workable, or is there  
> something better
> that some of you are already doing?  Should I just forget about  
> detached objects and
> squeeze/unsqueeze my entities down to identifers and retrieve them  
> anew on each
> request?  Any help or advice would be greatly appreciated...
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>



---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Using Hibernate detached objects in Tapestry (thread-safety question)

Geoff Callender-3
Do any of these problems exist if you get a session bean to do the  
work for you?

For example, a page to edit the user, using a session bean called  
OrderService and an entity bean (using Hibernate if you like, as I  
do) called Order.

When you're building the page...

                IOrderServiceLocal orderService = getBusinessServicesLocator
().getOrderServiceLocal();
                Order order = orderService.findOrder(id);
                // order is a detached object.  Put it in the page.
                setOrder(order);

In the listener for the Save button...

                // Get the updated detached object from the page.
                Order order = getOrder();

                try {
                        IOrderServiceLocal orderService = getBusinessServicesLocator
().getOrderServiceLocal();
                        orderService.changeOrder(order);
                }
                catch (Exception e) {
                        handleBusinessServicesException(e);
                }

No threading issues to worry about.  Isn't this simpler than roll-
your-own?

HTH,

Geoff
http://files.doublenegative.com.au/jumpstart/

On 16/06/2007, at 8:16 AM, Norman Franke wrote:

> I should note that I'm using Tapestry 4.0.x for my application. I'm  
> also pretty new to both Hibernate and Tapestry, so this may not be  
> the best. It does, however, seem to work well.
>
> My application only uses detached objects that it persists in the  
> client page for change detection (to determine if the record they  
> were editing changed while they were editing, which I flag as an  
> error.) Otherwise, I just re-query as needed for each page. I have  
> a single session per page, so if it queries multiple times (say  
> once during rewind and once not in rewind), the Hibernate session  
> cache prevents excessive queries to the database.
>
> I use HiveMind to inject DAOs for each class, and a SessionManager  
> object (of my own design) as needed by each page. The session  
> manager uses a threaded model in HiveMind, so I can get a call back  
> when the page is done being rendered (implementing  
> org.apache.hivemind.Discardable.) The first call to getSession()  
> creates a HIbernate session, which is closed when the page is done  
> rendering. Each DAO gets its session via HiveMind, so I don't have  
> to worry about that either. Each page can inject as many DAOs as  
> needed, and they all end up in the same Hibernate session.
>
> I have a "setShouldRollback" function to flag the page's session to  
> be rolled back when it finishes, to ensure we don't create two  
> Hibernate sessions for a single page. If I want to rollback a page,  
> I want it all to be rolled back.
>
> To persist a detached object, I call a clone() function on all of  
> my DB objects that converts it back to a normal POJO (from whatever  
> Hibernate does to it.) I could, I assume, persist this clone in the  
> session via Tapestry as well. One could then re-attach the object  
> to Hibernate during the next page render. In my case, my DAO has an  
> "assertUnchanged" method that throws an exception if the two  
> objects differ, e.g. my detached object and the one read from the  
> database. In this case, I tell the user that someone else changed  
> their record and their changes have been lost.
>
> The only glitches I noticed is when saving a record (i.e. not  
> rolling back) from a listener and returning another page (i.e. a  
> direct service.) I don't want them to be in the same session, since  
> cached data from the page with the listener gets stuck on the next  
> page. It also caused problems when a validator flagged errors. To  
> get around these problems, if the validator has errors, I clear the  
> session and flag a rollback. In the other case, the listener  
> explicitly closes the transaction if everything went well. The next  
> page (as a direct service) opens a new session like I want.
>
> This approach uses no locks or mutexes. It allows multiple pages to  
> render simultaneously, each in a different Hibernate session to  
> keep things consistent.
>
> -Norman
>
> On Jun 15, 2007, at 5:14 PM, Michael Sims wrote:
>
>> I know this isn't strictly Tapestry related, but since there has  
>> been a lot of
>> discussion here over the years related to integrating Hibernate  
>> with Tapestry, I was
>> hoping I could draw on the community knowledge about this topic  
>> and get a little
>> advice.  My apologies if this has been discussed before, I did  
>> extensive searching
>> before posting but still might have missed something.
>>
>> My specific dilemma at the moment is how to implement session-per-
>> request with
>> detached objects in a thread-safe manner.  Chapter 8 of the  
>> _Hibernate in Action_
>> book discusses the issues of detached objects and thread safety.  
>> It gives the
>> example of a user submitting a form twice, and I can think of  
>> several other
>> scenarios which would cause two or more threads to access the  
>> HttpSession
>> simultaneously.  The book suggests a few solutions to this  
>> problem: rejecting
>> additional requests if one is currently processing, serializing  
>> all requests from
>> the same user by synchronizing on the HttpSession in a servlet  
>> filter, and finally
>> maintaining a map of session information to separate windows in a  
>> multi-window
>> application.
>>
>> None of these solutions seem to be workable in my situation.  We  
>> are making
>> extensive use of assets for all of our images and CSS files, so  
>> there really is no
>> static content in our application; every request is going to be  
>> serviced by the
>> servlet.  The first two solutions aren't practical as even loading  
>> my application's
>> login page will open at least 4 concurrent requests (two CSS  
>> files, several images,
>> the HTML document, etc.) and if these requests are serialized I am  
>> of the opinion
>> that this will noticeably impact perceived performance of the  
>> application and will
>> impact scalability in the long run.  The final solution (mapping  
>> between windows)
>> doesn't solve the issue of users opening multiple tabs or windows  
>> as each window
>> will have the same name/identifier.
>>
>> So, I'm struggling to come up with a solution to this that doesn't  
>> require me to
>> abandon detached objects.  I have an idea for a solution, but it  
>> seems cumbersome
>> and I was hoping to get some suggestions or feedback on this.
>>
>> My idea is to explicitly synchronize only the sections of the code  
>> in my request
>> action handlers that have to work with the potentially shared  
>> detached objects.  My
>> plan is to synchronize either on a mutex object, or one of the  
>> detached objects, and
>> within the synchronized block update() the detached object,  
>> perform my model
>> manipulations, commit the transaction, close the session, then end  
>> the lock.  It
>> would still be possible for more than one thread to share a given  
>> detached object,
>> but this would prevent my code from attempting to attach the object
>> (s) to more than
>> one session simultaneously.
>>
>> (As an aside, I looked at the Tapernate code, since it includes  
>> persistence
>> strategies that use Hibernate detached objects.  However, unless  
>> I'm missing
>> something, it doesn't seem to be taking thread safety of detached  
>> objects into
>> account at all, which I find curious.)
>>
>> Can someone with a little more experience with this sort of thing  
>> give me some
>> advice on this?  Does my approach above sound workable, or is  
>> there something better
>> that some of you are already doing?  Should I just forget about  
>> detached objects and
>> squeeze/unsqueeze my entities down to identifers and retrieve them  
>> anew on each
>> request?  Any help or advice would be greatly appreciated...
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: [hidden email]
>> For additional commands, e-mail: [hidden email]
>>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>

Reply | Threaded
Open this post in threaded view
|

Re: Using Hibernate detached objects in Tapestry (thread-safety question)

Thiago H de Paula Figueiredo
In reply to this post by Norman Franke-2
Em Fri, 15 Jun 2007 19:16:30 -0300, Norman Franke <[hidden email]>  
escreveu:

> The only glitches I noticed is when saving a record (i.e. not rolling  
> back) from a listener and returning another page (i.e. a direct  
> service.) I don't want them to be in the same session, since cached data  
> from the page with the listener gets stuck on the next page.

If you're using session per request, just use redirect-after-post e use  
the flash persistence for your object.
See http://howardlewisship.com/tapestry-javaforge/tapestry-flash/ for more  
details. :)

Thiago

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Using Hibernate detached objects in Tapestry (thread-safety question)

Steve Shucker
In reply to this post by Michael Sims
I'm not sure if this will completely solve your problem, but I wrote my
own WebRequestServicerFilter that only applies the session/transaction
wrapping on non-asset requests.

    public void service(WebRequest request, WebResponse response,
WebRequestServicer servicer)
        throws IOException {
        // don't filter asset requests
        if
(Tapestry.ASSET_SERVICE.equals(request.getParameterValue(ServiceConstants.SERVICE)))
{
            servicer.service(request, response);
        } else {
            filterRequest(request, response, servicer);
        }
    }

I actually wrote a generic wrapper and then subclassed it into a
WebRequestSericerFilter for tapestry and a ServletFilter for the rare
occasions when I need a non-tapestry request wrapped.  The reason I have
both versions is specifically so I don't blindly apply the wrapping to
asset requests.  The filterRequest method in the superclass serializes
the requests.

If you're really worried about high throughput and contention issues,
using DAOs for narrower transactions may be your best bet.  If I was
going down that road, I'd be looking at using spring to broker my DAOs
and seeing if I could subclass their base DAO class to build in the
mutex support.

-Steve


Michael Sims wrote:

> I know this isn't strictly Tapestry related, but since there has been a lot of
> discussion here over the years related to integrating Hibernate with Tapestry, I was
> hoping I could draw on the community knowledge about this topic and get a little
> advice.  My apologies if this has been discussed before, I did extensive searching
> before posting but still might have missed something.
>
> My specific dilemma at the moment is how to implement session-per-request with
> detached objects in a thread-safe manner.  Chapter 8 of the _Hibernate in Action_
> book discusses the issues of detached objects and thread safety.  It gives the
> example of a user submitting a form twice, and I can think of several other
> scenarios which would cause two or more threads to access the HttpSession
> simultaneously.  The book suggests a few solutions to this problem: rejecting
> additional requests if one is currently processing, serializing all requests from
> the same user by synchronizing on the HttpSession in a servlet filter, and finally
> maintaining a map of session information to separate windows in a multi-window
> application.
>
> None of these solutions seem to be workable in my situation.  We are making
> extensive use of assets for all of our images and CSS files, so there really is no
> static content in our application; every request is going to be serviced by the
> servlet.  The first two solutions aren't practical as even loading my application's
> login page will open at least 4 concurrent requests (two CSS files, several images,
> the HTML document, etc.) and if these requests are serialized I am of the opinion
> that this will noticeably impact perceived performance of the application and will
> impact scalability in the long run.  The final solution (mapping between windows)
> doesn't solve the issue of users opening multiple tabs or windows as each window
> will have the same name/identifier.
>
> So, I'm struggling to come up with a solution to this that doesn't require me to
> abandon detached objects.  I have an idea for a solution, but it seems cumbersome
> and I was hoping to get some suggestions or feedback on this.
>
> My idea is to explicitly synchronize only the sections of the code in my request
> action handlers that have to work with the potentially shared detached objects.  My
> plan is to synchronize either on a mutex object, or one of the detached objects, and
> within the synchronized block update() the detached object, perform my model
> manipulations, commit the transaction, close the session, then end the lock.  It
> would still be possible for more than one thread to share a given detached object,
> but this would prevent my code from attempting to attach the object(s) to more than
> one session simultaneously.
>
> (As an aside, I looked at the Tapernate code, since it includes persistence
> strategies that use Hibernate detached objects.  However, unless I'm missing
> something, it doesn't seem to be taking thread safety of detached objects into
> account at all, which I find curious.)
>
> Can someone with a little more experience with this sort of thing give me some
> advice on this?  Does my approach above sound workable, or is there something better
> that some of you are already doing?  Should I just forget about detached objects and
> squeeze/unsqueeze my entities down to identifers and retrieve them anew on each
> request?  Any help or advice would be greatly appreciated...
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>
>  

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

RE: Using Hibernate detached objects in Tapestry (thread-safety question)

Michael Sims
In reply to this post by Norman Franke-2
Hi,

Thanks for taking the time to respond, this is really helpful information.

Norman Franke wrote:
> My application only uses detached objects that it persists in the
> client page for change detection (to determine if the record they
> were editing changed while they were editing, which I flag as an
> error.) Otherwise, I just re-query as needed for each page.

Yeah, I've been considering something similar.  My alternative to trying to
reattach a detached object would be to "squeeze" my persistent object into
three bits of info: the persistent class, the ID of the instance, and the
version number.  I'm using Hibernate's support for versioning, so the
version number would be enough to tell me if a conflicting update was made.
This approach would be enough for most purposes, but until I read your
message here I wasn't really sure how I was going to handle persisting
not-yet-committed changes across multiple pages (say, a multi-step form or
wizard) without using a detached object.

> To persist a detached object, I call a clone() function on all of my
> DB objects that converts it back to a normal POJO (from whatever
> Hibernate does to it.)

That's a good idea, and I might end up doing the same thing.  The only thing
I don't like about it is the overhead of implementing the clone() for each
persistent object, but I could learn to live with that.

> This approach uses no locks or mutexes.

That's definitely an advantage, especially to me, because I don't yet trust
myself enough to write too much code that uses locks and be confident that
I've done it properly and in a way that can scale...

Thanks again for the response.


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

RE: Using Hibernate detached objects in Tapestry (thread-safety question)

Michael Sims
In reply to this post by Geoff Callender-3
Hi Geoff, thanks for the response,

Geoff Callender wrote:
> Do any of these problems exist if you get a session bean to do the
> work for you?
>
> For example, a page to edit the user, using a session bean called
> OrderService and an entity bean (using Hibernate if you like, as I
> do) called Order.
[...]
> No threading issues to worry about.  Isn't this simpler than roll-
> your-own?

You'll have to forgive my ignorance, I'm still rather a newbie when it comes
to Java web apps.  I'm afraid I'm not familiar with what a Session Bean is
as a proper term (if that is the way you are using it).  Some Googling shows
me that it appears to be an EJB concept.  This is my first real Java
application, and I'm trying to keep it as simple as possible, so I haven't
yet gotten into JEE, EJB, etc.  I'm just doing a plain servlet on Tomcat.

Can you tell me what is is about session beans that avoids my problem, or
give me some pointers to documentation?  If I place a detached object in the
session bean, how is this any different from placing it in the HttpSession?
Isn't it still possible that two concurrent threads will be given that same
detached object?  What am I missing?  Thanks. ;)


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

RE: Using Hibernate detached objects in Tapestry (thread-safety question)

Michael Sims
In reply to this post by Steve Shucker
Hi Steve,

Steve Shucker wrote:
> I'm not sure if this will completely solve your problem, but I wrote
> my own WebRequestServicerFilter that only applies the
> session/transaction wrapping on non-asset requests.

Interesting!  Thanks for that.  There will still be some non-asset requests
in my application that won't hit the Hibernate stuff, but this will take
care of a good bit of unnecessary locking if I ultimately go that route.

> I actually wrote a generic wrapper and then subclassed it into a
> WebRequestSericerFilter for tapestry and a ServletFilter for the rare
> occasions when I need a non-tapestry request wrapped.  The reason I
> have both versions is specifically so I don't blindly apply the
> wrapping to asset requests.  The filterRequest method in the
> superclass serializes the requests.

So, just curious, are you serializing your requests for the same reason as I
(i.e. Hibernate detached objects)?  Or are you doing it just in general so
that you can place non-thread safe objects in your HttpSession?  Have you
noticed any performance impact from the serialization?

> If you're really worried about high throughput and contention issues,
> using DAOs for narrower transactions may be your best bet.  If I was
> going down that road, I'd be looking at using spring to broker my DAOs
> and seeing if I could subclass their base DAO class to build in the
> mutex support.

I'm using Hivemind as my app-wide DI container, and it is injecting my DAOs
into the classes that need them.  The problem with locking within the DAO is
that I need to lock starting from the point that I reattach (via
Session#update(), merge(), or lock()), to the point that I detach (via
evict() or closing the Session), and this will span many calls to various
DAOs.

Thanks for taking the time to respond...


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Using Hibernate detached objects in Tapestry (thread-safety question)

Norman Franke-2
In reply to this post by Michael Sims
On Jun 18, 2007, at 11:48 AM, Michael Sims wrote:

>> To persist a detached object, I call a clone() function on all of my
>> DB objects that converts it back to a normal POJO (from whatever
>> Hibernate does to it.)
>
> That's a good idea, and I might end up doing the same thing.  The  
> only thing
> I don't like about it is the overhead of implementing the clone()  
> for each
> persistent object, but I could learn to live with that.

I used Hibernate Tools to auto generate my POJOs, and I modified the  
template to create the clone() function automatically. I'm sure one  
could also do this via reflection via the DAO (look for all  
properties and copy them to a newly instantiated object.)

>> This approach uses no locks or mutexes.
>
> That's definitely an advantage, especially to me, because I don't  
> yet trust
> myself enough to write too much code that uses locks and be  
> confident that
> I've done it properly and in a way that can scale...

I always expect bad things when using locks, especially in an  
environment as random as the web.

-Norman




---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Using Hibernate detached objects in Tapestry (thread-safety question)

Norman Franke-2
In reply to this post by Thiago H de Paula Figueiredo
The main issue with that is getPageService().getLink(false,  
getPageName()) will return URLs too long for IE for my pages. Other  
browsers like Safari grind to a near halt with really, really long  
URLs, too.

-Norman

On Jun 16, 2007, at 10:03 AM, Thiago H de Paula Figueiredo wrote:

> Em Fri, 15 Jun 2007 19:16:30 -0300, Norman Franke  
> <[hidden email]> escreveu:
>
>> The only glitches I noticed is when saving a record (i.e. not  
>> rolling back) from a listener and returning another page (i.e. a  
>> direct service.) I don't want them to be in the same session,  
>> since cached data from the page with the listener gets stuck on  
>> the next page.
>
> If you're using session per request, just use redirect-after-post e  
> use the flash persistence for your object.
> See http://howardlewisship.com/tapestry-javaforge/tapestry-flash/ 
> for more details. :)
>
> Thiago
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>



---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Using Hibernate detached objects in Tapestry (thread-safety question)

Steve Shucker
In reply to this post by Michael Sims
I'm serializing the requests to prevent hibernate from trying to
associate an entity with more than one session.  Most of the research
that led to this approach was done in the hibernate2/tapestry3 days, so
some of it may be outdated.  I believe the rest of my state is
sufficiently thread-safe that I wouldn't need this if it weren't for
hibernate.

Generally, it's not a performance problem, but my production code is
only making light use of ajax.  That's going to change soon.  Some older
code does use pre-ajax iframe swapping though, and that performs well.  
The only problem I've seen is if a user tries one of a few long
operations and then changes their mind and clicks on something else.  My
filter still waits for the long operation to complete or timeout
(configured to 20 seconds) before beginning the user's new request.

I got hooked on spring before tap4, so I never gained mastery over
hivemind.  I can't really tell you how to craft hivemind-based DAOs.  If
you're using a DAO setup, you probably need to explicitly reattach in
the DAO methods rather than using tapernate to do it automatically.  
Personally, I'm moving towards tapernate-style re-enlistment and away
from a kludgy aspect.

-Steve


Michael Sims wrote:

> Hi Steve,
>
> Steve Shucker wrote:
>  
>> I'm not sure if this will completely solve your problem, but I wrote
>> my own WebRequestServicerFilter that only applies the
>> session/transaction wrapping on non-asset requests.
>>    
>
> Interesting!  Thanks for that.  There will still be some non-asset requests
> in my application that won't hit the Hibernate stuff, but this will take
> care of a good bit of unnecessary locking if I ultimately go that route.
>
>  
>> I actually wrote a generic wrapper and then subclassed it into a
>> WebRequestSericerFilter for tapestry and a ServletFilter for the rare
>> occasions when I need a non-tapestry request wrapped.  The reason I
>> have both versions is specifically so I don't blindly apply the
>> wrapping to asset requests.  The filterRequest method in the
>> superclass serializes the requests.
>>    
>
> So, just curious, are you serializing your requests for the same reason as I
> (i.e. Hibernate detached objects)?  Or are you doing it just in general so
> that you can place non-thread safe objects in your HttpSession?  Have you
> noticed any performance impact from the serialization?
>
>  
>> If you're really worried about high throughput and contention issues,
>> using DAOs for narrower transactions may be your best bet.  If I was
>> going down that road, I'd be looking at using spring to broker my DAOs
>> and seeing if I could subclass their base DAO class to build in the
>> mutex support.
>>    
>
> I'm using Hivemind as my app-wide DI container, and it is injecting my DAOs
> into the classes that need them.  The problem with locking within the DAO is
> that I need to lock starting from the point that I reattach (via
> Session#update(), merge(), or lock()), to the point that I detach (via
> evict() or closing the Session), and this will span many calls to various
> DAOs.
>
> Thanks for taking the time to respond...
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>
>  

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

RE: Using Hibernate detached objects in Tapestry (thread-safety question)

Michael Sims
Steve Shucker wrote:
> The only problem I've seen is if a user tries one of a
> few long operations and then changes their mind and clicks on
> something else.  My filter still waits for the long operation to
> complete or timeout (configured to 20 seconds) before beginning the
> user's new request.

Ok, thanks for this info and your help, now I have an idea of what to
expect...


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Using Hibernate detached objects in Tapestry (thread-safety question)

Geoff Callender-3
In reply to this post by Michael Sims
Hi Michael,

You are right, it's a type of EJB.  Your question is all about  
plumbing, and what I like about EJB 3 is that it does the plumbing  
for you, so only have to think about pages, business services, and  
entities.  In other words, I suspect you'll find it easier than where  
you're currently heading.

When you invoke a session bean it starts a transaction for you in its  
own thread.  If you have multiple simultaneous invocations of session  
beans it's no problem - each one acts independently in its own  
thread.  If you concurrent requests to save your detached object,  
they will operate in two separate transactions, and one of them will  
succeed and the other will be rejected with an  
OptimisticLockException (that's just Hibernate, or in fact the Java  
Persistence Architecture spec, at work).  That's correct behaviour.

Here's an example of some things you might like a session bean to do:

public interface IOrderServiceLocal {
        Order findOrder(Order order);
        void changeOrder(Order order);
        List<Order> findOrders();
}

And here's an example of the bean itself - you can see it's very simple:

@Stateless
@Local(IOrderServiceLocal.class)
public class OrderService extends BaseService implements  
IOrderServiceLocal {

        @PersistenceContext
        protected EntityManager _em;

        public Order findOrder(Long id) {
                Order obj = (Order) _em.find(Order.class, id);
                return obj;
        }

        public void changeOrder(Order order) {
                order = _em.merge(order);
        }

        public List<Order> findOrders() {
                Query q = _em.createQuery("select o from Order o order by  
o.customerName");
                List l = q.getResultList();
                return l;
        }

}

As for the Order entity bean, it will be exactly the same as the  
Hibernate entity you were going to code up anyway, because Hibernate  
follows the Java Persistence Architecture spec which EJB 3 also follows.

As you can tell, I am almost as enthusiastic about EJB 3 as I am  
about Tapestry, and for very similar reasons.  If you'd like to see  
them together in action, you can be up and running in about 20  
minutes with Tapestry JumpStart:  http://files.doublenegative.com.au/ 
jumpstart/

I hope this helps,

Geoff

On 19/06/2007, at 1:48 AM, Michael Sims wrote:

> Hi Geoff, thanks for the response,
>
> Geoff Callender wrote:
>> Do any of these problems exist if you get a session bean to do the
>> work for you?
>>
>> For example, a page to edit the user, using a session bean called
>> OrderService and an entity bean (using Hibernate if you like, as I
>> do) called Order.
> [...]
>> No threading issues to worry about.  Isn't this simpler than roll-
>> your-own?
>
> You'll have to forgive my ignorance, I'm still rather a newbie when  
> it comes
> to Java web apps.  I'm afraid I'm not familiar with what a Session  
> Bean is
> as a proper term (if that is the way you are using it).  Some  
> Googling shows
> me that it appears to be an EJB concept.  This is my first real Java
> application, and I'm trying to keep it as simple as possible, so I  
> haven't
> yet gotten into JEE, EJB, etc.  I'm just doing a plain servlet on  
> Tomcat.
>
> Can you tell me what is is about session beans that avoids my  
> problem, or
> give me some pointers to documentation?  If I place a detached  
> object in the
> session bean, how is this any different from placing it in the  
> HttpSession?
> Isn't it still possible that two concurrent threads will be given  
> that same
> detached object?  What am I missing?  Thanks. ;)
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>

Reply | Threaded
Open this post in threaded view
|

Re: Using Hibernate detached objects in Tapestry (thread-safety question)

carlos f
In reply to this post by Norman Franke-2
Sorry, my questions have nothing to do with Tapestry - put a few things you mentioned piqued my interest.

Norman Franke wrote
In my case, my DAO has an  
"assertUnchanged" method that throws an exception if the two objects  
differ, e.g. my detached object and the one read from the database.  
In this case, I tell the user that someone else changed their record  
and their changes have been lost.
Why not rely on Hibernate's version support for detached objects and versioning?

Norman Franke wrote
To persist a detached object, I call a clone() function on all of my  
DB objects that converts it back to a normal POJO (from whatever  
Hibernate does to it.)
Why clone the detached object graph?  Why not have the DAO reattach it to the session and save it -- assuming it passes your version check?

Carlos
Reply | Threaded
Open this post in threaded view
|

RE: Using Hibernate detached objects in Tapestry (thread-safety question)

Michael Sims
In reply to this post by Geoff Callender-3
Geoff Callender wrote:
> You are right, it's a type of EJB.  Your question is all about
> plumbing, and what I like about EJB 3 is that it does the plumbing
> for you, so only have to think about pages, business services, and
> entities.
[...]
> As you can tell, I am almost as enthusiastic about EJB 3 as I am
> about Tapestry, and for very similar reasons.  If you'd like to see
> them together in action, you can be up and running in about 20
> minutes with Tapestry JumpStart:  http://files.doublenegative.com.au/
> jumpstart/
>
> I hope this helps,

It does, thanks very much.  It definitely sounds interesting.  And I actually have
used your JumpStart project in the past to get inspiration and ideas, so thanks for
making that available too.  At this point we are a bit too late in the project to
introduce EJB's, but it's definitely something I'll check out for the next one.


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

RE: Using Hibernate detached objects in Tapestry (thread-safety question)

Michael Sims
In reply to this post by carlos f
carlos f wrote:
> Why not rely on Hibernate's version support for detached objects and
> versioning?
[...]
> Why clone the detached object graph?  Why not have the DAO reattach
> it to
> the session and save it -- assuming it passes your version check?

I don't mean to speak for Norman, but the point of this thread has been that
detached objects are not thread safe, so if you are going to store them in the
HttpSession, you have to serialize access to it in order to avoid potentially trying
to re-attach the same object to two different Sessions.  Norman's approach avoids
this problem and doesn't require any mutexes or locks...


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

RE: Using Hibernate detached objects in Tapestry (thread-safety question)

carlos f
Michael Sims wrote
I don't mean to speak for Norman, but the point of this thread has been that
detached objects are not thread safe, so if you are going to store them in the
HttpSession, you have to serialize access to it in order to avoid potentially trying
to re-attach the same object to two different Sessions.  Norman's approach avoids
this problem and doesn't require any mutexes or locks...
Unless I am mistaken, which happens all the time, but it appears that the crux of his "thread safety" is, 1) storing detached instances on the client side -- I am assuming that "persists in the client page" is a reference to the ClientPropertyPersistenceStrategy -- 2) creating new hibernate sessions per page request and 3) closing the hibernate session as soon the the page is done processing the request.

Norman Franke wrote
My application only uses detached objects that it persists in the client page for change detection (to determine if the record they were editing changed while they were editing, which I flag as an  
error.)

. . .

The first call to getSession()  creates a HIbernate session, which is closed when the page is done  
rendering.
Since the detached object appears to be persisted on the client side, the hibernate sessions only exist for the rendering of a single page and the session is closed when the page is done processing, it appears as if the detached object should be isolated to a single hibernate session at a time.  If that is true, I was interested in his method/motivation for optimistic locking and cloning the detached object graphs for update.  If it isn't, how?

Norman Franke wrote
my DAO has an "assertUnchanged" method that throws an exception if the two objects differ, e.g. my detached object and the one read from the database.  In this case, I tell the user that someone else changed their record  and their changes have been lost.
I was interested in knowing more about the implementation of "assertUnchanged"  - for all I know his entities could have mapped version attributes and "assertUnchanged" could be calling hibernateSession.lock(detachedInstance, LockMode.READ).  If it isn't, I just want to know why.  The question about cloning is along similar lines.

Carlos
Reply | Threaded
Open this post in threaded view
|

Re: Using Hibernate detached objects in Tapestry (thread-safety question)

Norman Franke-2
In reply to this post by carlos f
On Jun 19, 2007, at 12:08 PM, carlos f wrote:

> Norman Franke wrote:
>> In my case, my DAO has an
>> "assertUnchanged" method that throws an exception if the two objects
>> differ, e.g. my detached object and the one read from the database.
>> In this case, I tell the user that someone else changed their record
>> and their changes have been lost.
>
> Why not rely on Hibernate's version support for detached objects and
> versioning?

Several reasons.

1. As Michael noted, they aren't thread safe.
2. This really gets to a bigger issue, in that these objects aren't  
valid outside of a session. Once the session closes, they are  
technically invalid according to what I read in "Hibernate in  
Action". This is because Hibernate may want to lazy fetch things,  
e.g. relationships. It leave us with a proxy object or somesuch,  
which is likely larger than my object and not as serializable  
friendly. My detached object is serialized into the client's web  
page, so size matters.
3. I can't use versioning since I'm using a legacy schema without  
support for versions.

> Norman Franke wrote:
>> To persist a detached object, I call a clone() function on all of my
>> DB objects that converts it back to a normal POJO (from whatever
>> Hibernate does to it.)
>
> Why clone the detached object graph?  Why not have the DAO reattach  
> it to
> the session and save it -- assuming it passes your version check?

I don't clone the graph, just the properties (i.e. not  
relationships.) If I need the relationships, I do then reattach. This  
clone is stored in the client page (or it could be stored in the  
session, if desired. I store it in the client page to save memory.)

-Norman



---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

RE: Using Hibernate detached objects in Tapestry (thread-safety question)

Michael Sims
In reply to this post by carlos f
carlos f wrote:
> Unless I am mistaken, which happens all the time, but it appears that the
> crux of his "thread safety" is, 1) storing detached instances on the client
> side -- I am assuming that "persists in the client page" is a reference to
> the ClientPropertyPersistenceStrategy

Sorry for my lack of reading comprehension, I totally missed that he was using
client persistence.  I just assumed he was using the HttpSession...


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Using Hibernate detached objects in Tapestry (thread-safety question)

Norman Franke-2
In reply to this post by carlos f
On Jun 19, 2007, at 4:21 PM, carlos f wrote:

> Norman Franke wrote:
>>
>> My application only uses detached objects that it persists in the  
>> client
>> page for change detection (to determine if the record they were  
>> editing
>> changed while they were editing, which I flag as an
>> error.)
>>
>> . . .
>>
>> The first call to getSession()  creates a HIbernate session, which is
>> closed when the page is done
>> rendering.
>>
>
> Since the detached object appears to be persisted on the client  
> side, the
> hibernate sessions only exist for the rendering of a single page  
> and the
> session is closed when the page is done processing, it appears as  
> if the
> detached object should be isolated to a single hibernate session at  
> a time.
> If that is true, I was interested in his method/motivation for  
> optimistic
> locking and cloning the detached object graphs for update.  If it  
> isn't,
> how?

I can't lock the object between requests, so I just verify the data  
didn't change. So, once the user submits their changes, I verify that  
the current record as stored in the DB is the same as the one  
persisted in the client. If so, I allow the save to happen. If not, I  
display an error.

> Norman Franke wrote:
>>
>> my DAO has an "assertUnchanged" method that throws an exception if  
>> the two
>> objects differ, e.g. my detached object and the one read from the
>> database.  In this case, I tell the user that someone else changed  
>> their
>> record  and their changes have been lost.
>>
>
> I was interested in knowing more about the implementation of
> "assertUnchanged"  - for all I know his entities could have mapped  
> version
> attributes and "assertUnchanged" could be calling
> hibernateSession.lock(detachedInstance, LockMode.READ).  If it  
> isn't, I just
> want to know why.  The question about cloning is along similar lines.

assertUnchanged takes two objects, and compares them via the equals()  
method. My POJOs have an equals method that compares the fields I'm  
interested in (i.e. not auto generated data or relationships.) This  
method was auto generated by Hibernate Tools. It does throw an  
exception if they are not the same.

-Norman



---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

12