-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 17 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Why is "session-per-operation" an antipattern!?
PostPosted: Wed Jan 28, 2004 11:44 am 
Pro
Pro

Joined: Wed Oct 08, 2003 10:31 am
Posts: 247
In my project for every business method I'm doing a session = sessionFactory.openSession(); and a session.close(), independantely of the type of operation (simple or not).
Looks to me a good way to go because it scales well with diferent types of clients (web based, class based) and it separates better the middle-tier from the rest.

In http://www.hibernate.org/168.html it says to use session-per-request pattern instead. But this is for web based clients.

Need some opinions on this please.

Thanks in advance.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 28, 2004 9:26 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
The advice is really to utilize a single session instance for a single logical "unit of work". Now the definitions of "unit of work" tend to vary, but the usual strategy is that a unit of work defines a single transaction in terms of database access.

In a web app (and web services also) this almost always implies a one-to-one correlation between a request and a unit of work. I think thats the point the article you mention is trying to make.

And I'm not quite sure how you come up with the statement "separates better the middle-tier from the rest" nor the statement "because it scales well with diferent types of clients"... It really depends how your middle tier is coded and setup. The way my middle tier is setup is that it's really a request into the middle tier which denotes a unit of work (which, again, [u]usually[/] relates to a single web request for web-based clients). But my middle tier supports web services in addition to web clients. And yes I also have java-main and unit-test based java classes which interact with the middle tier. The middle tier should be the middle tier. It should do what it does regardless of whether its client is an axis web-services or a NakedObjects-based UI. If you get bleed from one tier to another, you probably need to re-think the implememntation of your tier seperation.

In the end, if your using a transactional datasource to feed the session's connection, the difference is probably not that big of a deal for smaller apps. However, the solution you propose is that one that will not scale well in fact.

HTH


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 29, 2004 5:40 am 
Pro
Pro

Joined: Wed Oct 08, 2003 10:31 am
Posts: 247
steve wrote:
The advice is really to utilize a single session instance for a single logical "unit of work". Now the definitions of "unit of work" tend to vary, but the usual strategy is that a unit of work defines a single transaction in terms of database access...

In the end, if your using a transactional datasource to feed the session's connection, the difference is probably not that big of a deal for smaller apps. However, the solution you propose is that one that will not scale well in fact.


Thanks for the reply.
But tell me... will the code become more complex if I try to manipulate the session out of the business method? Looks more dificult to follow a set of operations in a transaction if I don't open-close the session per method.
With open-close of the session per method you have compact unit's of work as you said that are simpler to manage.

In fact I'm using a datasource to feed my session.
What would be a better approach please?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 29, 2004 9:32 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
Look at it this way:

This advice is not really Hibernate-specific. Consider a plain-old JDBC app which has a use case to "create a user". Further, say that "creating a user" in terms of the business use-case implies 1) inserting a row into the USER table; 2) setting some defaults (through inserts) for the new user on a USER_PREFERENCE table; as well as 3) creating an entry (again a DB insert) in an admin-queue for approval of the user.


Even further, lets say that the admin piece has worth outside this particualr usecase. So that would be a seperate method on your middle tier which the createUser(...) method would call to delegate some of its work.

So in your set-up, the createUser(...) method would open a connection and the createAdminQueueEntry(...) method would open its own seperate connection. Does that sound reasonable to you? It does not to me, but maybe that's just me.

That the JDBC equivalent of what your approach in Hibernate would look like.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 29, 2004 12:29 pm 
Pro
Pro

Joined: Wed Oct 08, 2003 10:31 am
Posts: 247
steve wrote:
Look at it this way:

This advice is not really Hibernate-specific. Consider a plain-old JDBC app which has a use case to "create a user". Further, say that "creating a user" in terms of the business use-case implies 1) inserting a row into the USER table; 2) setting some defaults (through inserts) for the new user on a USER_PREFERENCE table; as well as 3) creating an entry (again a DB insert) in an admin-queue for approval of the user...


I get the picture.
Then instead of having each business method create a session of it's own, it's better to have a single Session for a business class that can be instantiated, where each method would get it's connection.
This way all methods won't be responsible for closing the session. The session would be closed by a proper method that could be executed by a client.
Isn't this risky? Leaving it up to the client for closing the session?

Regarding what you said about use-cases having a chain of method executions. Each method in the chain could be another use-case acting by itself.
I don't know if I'm explaining this right... this is just because of the risk of leaving a session open.

PS: Thanks for the opinions Steve.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 29, 2004 5:15 pm 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
I really like the call-depth counting version of the ThreadLocal pattern class for such situations, take a look at it in the wiki design pattern area. Some have mentioned that it is acutally unsafe to use, but I think if you are careful about your exception handling it should work.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 29, 2004 5:40 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
In general, it is faster to have fewer sessions per request, not because sessions are especially heavyweight (though the JDBC connections they own *are*), but because the session is a cache.

Also, I'd say that usually multiple transactions per request is a very bad thing. Think about it: how am I going to report to the user that one txn was successful but the other was not?

I know this stuff has been confusing for some people, but trust me, it is also very powerful. Once you understand it, you can start to do crazy stuff, like storing multiple Sessions in each user's HttpSession - one for each application transaction - in a multiwindow application. (this is /not/ an antipattern!)

I think it will all be much clearer in the book...


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 29, 2004 6:22 pm 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
The Spring Framework's generic transaction management allows to demarcate high-level transactions in a programmatic or declarative fashion on POJOs. This is typically done at the business facade level: Transactions start there, get automatically propagated down to data access methods (arbitrary call depth, of course), and get committed or rolled back when the business method invocation ends.

Hibernate Sessions are automatically associated with such transactions; DAOs simply fetch the current Session and do their work. This will work with both a local HibernateTransactionManager or a JtaTransactionManager that delegates to your J2EE server's JTA subsystem.

Before anyone rolls his own ThreadLocal pattern with call-depth counting, I strongly recommend to check out what Spring can offer in that respect. There's much more sophistication there than any ad-hoc solution can possibly provide. Note that most of those Spring goodies can be used in a library style, even if they work particularly nicely in a Spring IoC container.

Juergen
http://www.springframework.org
http://www.hibernate.org/110.html


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 30, 2004 6:39 am 
Pro
Pro

Joined: Wed Oct 08, 2003 10:31 am
Posts: 247
gavin wrote:
In general, it is faster to have fewer sessions per request, not because sessions are especially heavyweight (though the JDBC connections they own *are*), but because the session is a cache...

Once you understand it, you can start to do crazy stuff, like storing multiple Sessions in each user's HttpSession - one for each application transaction - in a multiwindow application. (this is /not/ an antipattern!)


Thanks for the reply Gavin.
But tell me please, isn't this bad by not separating the persistence tier from the web tier!?

The web tier doesn't need to know that I'm using Hibernate's session's to accomplish my business logic. The only information that a client needs to give is some data to be used to execute a business method.
Second, using the session to store information other than autentication info, is normally a bad thing. And by doing so, it would be harder to close the session's correctly, right?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 30, 2004 8:10 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
nerotnt wrote:
But tell me please, isn't this bad by not separating the persistence tier from the web tier!?


If you close session or/and commit transaction in filter then it does not mean your persistence tier is not separated from the web tier.
Transaction demarcation is not the web tier, this helper just implements interface form servlets API and API is not a tier. Web tier is a parameter parsing, validation, view rendering, ...
Transaction demarcation is the app logic tier, it is not the persistence tier too.
I recommend to separate transaction demarcation and resource management code from persistence tier, It is not persistence in the web tier !


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 30, 2004 11:13 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Huh?? I didn't mention *anything* about tiers here. I don't understand what you are talking about here.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 30, 2004 11:14 am 
Pro
Pro

Joined: Wed Oct 08, 2003 10:31 am
Posts: 247
baliukas wrote:
nerotnt wrote:
But tell me please, isn't this bad by not separating the persistence tier from the web tier!?


If you close session or/and commit transaction in filter then it does not mean your persistence tier is not separated from the web tier.
Transaction demarcation is not the web tier, this helper just implements interface form servlets API and API is not a tier. Web tier is a parameter parsing, validation, view rendering, ...
Transaction demarcation is the app logic tier, it is not the persistence tier too.
I recommend to separate transaction demarcation and resource management code from persistence tier, It is not persistence in the web tier !



What do mean by "Transaction demarcation"?
Do you mean this by having an intermediary that receives the clients requests and executes the business methods accordingly? This intermediary would be responsible for opening and closing the session?
How would save the clients session's? By putting them in the HttpSession of a user, it could get a little risky if we start forgetting to close the session's, right?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 30, 2004 11:15 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
P.S. The word "request" does NOT necessarily mean a HttpRequest. It could be a request to the business tier. And "servlet filter" coiuld be any kind of interceptor.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 30, 2004 8:07 pm 
Expert
Expert

Joined: Thu Jan 08, 2004 6:17 pm
Posts: 278
Being slightly behind the times, we are using the plain old Session Facade pattern, where we have stateless session beans as our service layer. The UI tier calls SLSB methods. Each SLSB method, of course, gets its own transaction from the container. Each also has its own ThreadLocalSession. Then all the DAO methods, helper methods, etc. called from the SLSB automatically get rolled into that single Session.

So the boundary is clear: each SLSB invocation is a single transaction, and a single Hibernate session.

Works for us... so far :-) At least it's simple to understand for J2EE newbies such as us. Maybe in a year or so we'll be banging our heads against it and will be ready for Spring. (It's already somewhat painful to not have centralized exception handling.)

But right now we've been climbing such a steep learning curve, with JOnAS and Hibernate and Joram and XSLT (oh my!), that we honestly can't handle learning another whole system!

Cheers!
Rob


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jan 31, 2004 1:40 pm 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
nerotnt wrote:
baliukas wrote:
nerotnt wrote:
But tell me please, isn't this bad by not separating the persistence tier from the web tier!?


If you close session or/and commit transaction in filter then it does not mean your persistence tier is not separated from the web tier.
Transaction demarcation is not the web tier, this helper just implements interface form servlets API and API is not a tier. Web tier is a parameter parsing, validation, view rendering, ...
Transaction demarcation is the app logic tier, it is not the persistence tier too.
I recommend to separate transaction demarcation and resource management code from persistence tier, It is not persistence in the web tier !



What do mean by "Transaction demarcation"?
Do you mean this by having an intermediary that receives the clients requests and executes the business methods accordingly? This intermediary would be responsible for opening and closing the session?
How would save the clients session's? By putting them in the HttpSession of a user, it could get a little risky if we start forgetting to close the session's, right?


Put session to ThreadLocal or use session as method parameter. It maps transaction to thread, I have never used this way but I think it is not a good idea to map connection to httpsession.
There are a lot of ways to demarcate transaction (base class, interceptor, callback), but transaction per data access operation makes data access code not reusable and it is code dublication is not it ?



User create(String id,String psw){
//code dublication:
Session session = factory.getSession();
try{

Object obj = new User(id,psw);
session.save(obj);
session.flush();
session.getConnection().commit();

}finally{
session.close();
}


}


User create( Session session, String id,String psw){
// it is not very transparent, but "better" than the first way
Object obj = new User(id,psw);
session.save(obj);


}

User create(String id,String psw){
//it is dangerous, but no so bad too
Object obj = new User(id,psw);
this.session.save(obj);


}

User create(String id,String psw){

//current session is ThreadLocal. it "transparent" and "safe"
Session session = factory.currentSession();
Object obj = new User(id,psw);
session.save(obj);


}

abstract class AbstractAction{

abstract void doExecute();

final void execute(){

factory.enter();
try{

doExecute();

}catch(Trowable t){

factory.error(t);

}finally{

factory.exit();

}

}

}

class CreateUserAction{

void doExecute(){

this.user = userFactory.create(this.id,this.psw);

}


}


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 17 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.