You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Michael Sims <mi...@crye-leike.com> on 2007/06/15 23:14:41 UTC

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

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: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Thiago H de Paula Figueiredo <th...@gmail.com>.
On Wed, 20 Jun 2007 12:17:32 -0300, Michael Sims <mi...@crye-leike.com>  
wrote:

> Unless I'm mistaken, merge()'ing the same object into two different  
> Sessions isn't any more safe than using update() or lock(), so you still  
> have to deal with thread safety issues when using it.

I was just talking about the lazy loading part. :)
Anyways, merge() would at least return different objects for different  
o.h.Sessions.

Thiago

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Michael Sims <mi...@crye-leike.com>.
Thiago H de Paula Figueiredo wrote:
> On Tue, 19 Jun 2007 18:24:10 -0300, Norman Franke <no...@myasd.com>
> wrote:
>
>> 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.
>
> In a second request and therefore a second session, you can merge your
> your detached instance using the Object merge(Object o) method of
> Session. The returned object has the same values as yours detached
> one, but it is associated with the session.

Unless I'm mistaken, merge()'ing the same object into two different Sessions isn't
any more safe than using update() or lock(), so you still have to deal with thread
safety issues when using it.  Do you have reason to believe otherwise (or maybe I
completely misunderstood your point)?


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Thiago H de Paula Figueiredo <th...@gmail.com>.
On Tue, 19 Jun 2007 18:24:10 -0300, Norman Franke <no...@myasd.com> wrote:

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

In a second request and therefore a second session, you can merge your  
your detached instance using the Object merge(Object o) method of Session.  
The returned object has the same values as yours detached one, but it is  
associated with the session. More details here:  
http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html#merge(java.lang.Object)

Thiago

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Norman Franke <no...@myasd.com>.
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: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Norman Franke <no...@myasd.com>.
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: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Norman Franke <no...@myasd.com>.
Either should work, however.

On Jun 19, 2007, at 5:32 PM, Michael Sims wrote:

> 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: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Michael Sims <mi...@crye-leike.com>.
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: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by carlos f <ca...@yahoo.com>.

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
-- 
View this message in context: http://www.nabble.com/Using-Hibernate-detached-objects-in-Tapestry-%28thread-safety-question%29-tf3930468.html#a11202178
Sent from the Tapestry - User mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Michael Sims <mi...@crye-leike.com>.
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: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by carlos f <ca...@yahoo.com>.
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
-- 
View this message in context: http://www.nabble.com/Using-Hibernate-detached-objects-in-Tapestry-%28thread-safety-question%29-tf3930468.html#a11197907
Sent from the Tapestry - User mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Norman Franke <no...@myasd.com>.
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  
> <no...@myasd.com> 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: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Thiago H de Paula Figueiredo <th...@gmail.com>.
Em Fri, 15 Jun 2007 19:16:30 -0300, Norman Franke <no...@myasd.com>  
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: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Michael Sims <mi...@crye-leike.com>.
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: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Geoff Callender <ge...@mac.com>.
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: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>


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

Posted by Michael Sims <mi...@crye-leike.com>.
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: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Geoff Callender <ge...@mac.com>.
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: users-unsubscribe@tapestry.apache.org
>> For additional commands, e-mail: users-help@tapestry.apache.org
>>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>


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

Posted by Norman Franke <no...@myasd.com>.
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: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Michael Sims <mi...@crye-leike.com>.
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: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Norman Franke <no...@myasd.com>.
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: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Michael Sims <mi...@crye-leike.com>.
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: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Steve Shucker <ss...@vmsinfo.com>.
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: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>   

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Michael Sims <mi...@crye-leike.com>.
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: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


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

Posted by Steve Shucker <ss...@vmsinfo.com>.
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: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>   

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org