-->
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.  [ 16 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Using hibernate with lazy instantiation on layered design
PostPosted: Mon Oct 18, 2004 3:27 pm 
Newbie

Joined: Mon Oct 18, 2004 2:27 pm
Posts: 4
Hello,

I know this has been posted over and over but I haven't found a conclusive answer (well, there might not be one, but I wasn't able to find a clear solution). I am designing a system using layers that works the following way:

There is the client side that is any application web, swing or whatever and there is a model layer that is responsible for business logic. That way the model knows nothing of input and output and the clients are pretty blind to the business logic behind the information given or requested.

The model layer itself has the business logic layer and the datasource layer. That way changing the datasource of the application or of a specific model object (for example User) is pretty simple (not only changing between DBMSs but each model object has it's datasource facade that allows it to access data from xml files, remote external systems and so on). We have chosen to use hibernate to link our datasource layer to the DB but since the model shouldn't be aware of what is going on on the DS side it makes no sense that the model opens and close sessions and not to mention the client application.

The problem is that because of too much data we can't have lazy="false" for all collections (for example a Stock can't have a non-lazy collection of Quotes). Since each model request that requires datasource information will be passed to the datasource which will transparently return the result (wherever it comes from) we open and close the Hibernate session for every request made, this way we can't use lazy="true".

The solution we have found so far is not to created the collection of Quotes in Stock and when someone requests a Stock.getQuote() Stock returns a Quote.find(). The problem is that since Quote has a property Stock for every Quote we find (Quote.find actually calls QuoteDataSource.find that will return the requested Quote by running a HQL query) Stock is instatiated again and everything that is connected to it is instantiated by Hibernate.
To avoid that we made Stock lazy="true" which reduced the run time of a simple application 10 times but if a Quote.getStock() is ran we get an exception since Stock is lazy and the Session has been closed.

We thought about removing the getStock method, leaving the stock property private since there is no point in doing a getStock in a Quote anyway, but things are starting to get a little weird and we are deviating from the way things should be.

Does anyone have a suggestion of what we could do? We don't intend to make the model objects see Hibernate directly, only thru the DataSource objects and as DataSource objects don't have the model's business logic they should avoid knowing about other objects.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 03, 2004 2:37 pm 
Newbie

Joined: Mon Oct 18, 2004 2:27 pm
Posts: 4
Since noone replied to my last message maybe I should change the question a bit.
With the above architecture is there a point in using Hibernate or would I have to hack hibernate so much that it would be better to go straight to J2EE?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 04, 2004 6:48 am 
Newbie

Joined: Fri Oct 01, 2004 3:37 am
Posts: 2
Location: France
Hello,
I had the same problem as you... I am developping a Web application and try have separated layers. I use Hibernate (I want to include Spring) for DB access, I have services objects that make the bridge between DAO objetcs and Backing Beans (I used JSF). So my problem was that some properties were lazy and the DAO object don't know if they should get lazy data or not. So what I did is add a method into DAO:

//A is the object which has a lazy bag property of type B.
public void refreshLazy(A obj) throws DataAccessException {
Transaction t = null;
Session s = null;
try {
s = getSession();
t = s.beginTransaction();
refresh(obj, s);
// This is the normal method, auto-generated
// by HibernateSynchronizer for ex
Collection c = obj.getBs();
Iterator it = c.iterator();
// To really get the objets !!
while(it.hasNext()){
String name = ((B)it.next()).getName();
}
t.commit();
} catch (HibernateException e) {
try {
if (null != t)
t.rollback();
} catch (Exception re) { }
throw new DataAccessException(e);
} finally {
try {
if (null != s)
HibernateUtil.closeSession();
} catch (HibernateException he) {
throw new DataAccessException(he);
}
}
}

And in my domain object i also added a method :
A.java:
public List getLazyBs () {
StudyDAO.getInstance().refreshLazy(this);
return new ArrayList(super.getBs());
}

Don't directly redefin getBs() as this method is used in refreshLazy... it will loop :o)

So the only problem (not really a probleme but not really transparent), is that my backing bean should call getLazyBs() and not getBs() ....

That's my sol for now... What do you think of it ? I just tested it but not really improved it... Hope it will help

Regards
Veronique


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 04, 2004 8:11 am 
Senior
Senior

Joined: Wed Aug 27, 2003 4:08 am
Posts: 178
Location: Wiesbaden, Germany
Well, in a web application you will have no problems with
"open session in view" pattern - just keep session open for whole request and you are fine. after your result page is rendered you do not need those objects anymore.

If you have swing app which goes directly to database ( via hibernate ) session management becomes tricky - you have to
be really carefull when you open / close session and when your
"view" beans get their data.

_________________
Got new hibernate xdoclet plugin? http://www.sourceforge.net/projects/xdoclet-plugins/
... Momentan auf der Suche nach neuen Projekt ode Festanstellung....


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 04, 2004 8:57 am 
Expert
Expert

Joined: Thu Jan 29, 2004 2:31 am
Posts: 362
Location: Switzerland, Bern
Hi ko5tik

Did you find a general solution for the Swing case?

At a first glance I'd like to use the session-per-application pattern. But the wiki (at http://www.hibernate.org/168.html) lists this as an antipattern. (Why?)

TIA
Ernst


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 04, 2004 9:40 am 
Expert
Expert

Joined: Tue Oct 05, 2004 9:45 am
Posts: 263
well, in a swing-app i propably would use a Session for each "business-call".
You will then have eg. a "gui-layer", a "business-layer" and a "persistence-layer" ...
the business-layer could use a hibernate-session in a 'transparent' way.
If you call a method of the "business-layer" either the Hibernate-Session or a own Hibernate-Wrapper will be passed in automatically ... the transaction controll would be outside of the business-call ... (just before method-invocation 'beginTransaction' and after 'commit' or 'rollback'). To do this in a generic way, dynamic proxies could be an alternative ...

... the only thing which won't be possible without doing some 'hand work' is lazy-loading due to the fact, that the session is not avail after the business-method-call ... (i'm thinking about how to manage this in a generic way .. perhaps own proxies which will use the business-layer for lazy loading or something like that ... don't know if hibernate let's me use my own InvocationHandler?!)

... propably not the best solution, but it works perfectly for me ...

gtx
curio


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 04, 2004 10:22 am 
Expert
Expert

Joined: Thu Jan 29, 2004 2:31 am
Posts: 362
Location: Switzerland, Bern
Yes, that works, if you use Swing in a request/response way as you would do for a web application.

I'm thinking of a Swing application which directly uses the business layer as its model. This can be achieved in a generic way by implementing clever models.
The corix 4i Framework (http://www.corix.ch) does this in a very nice way. I'm thinking about doing something simmilar for SWT.

This way you don't have a big business call per Panel, but you can easyly several 100 tiny business calls to your business objects (which are persisted with Hibernate). IMHO creating some 100 sessions and transactions dosen't look very performant.

An other problem is, that this approach requires object identity throughout the JVM live cycle. AFAIK with Hibernate object identity is only guaranteed within a session. That's why the session-per-application (anti?)-pattern would be fine for me.
But there's this wiki entry and I can remember gavin writing something similar in the forum.

TIA
Ernst


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 04, 2004 10:58 am 
Expert
Expert

Joined: Tue Oct 05, 2004 9:45 am
Posts: 263
hmmm ... yes, you're right ...
but you only need a hibernate-session for those business-calls where you really want to do something with the database ... so perhaps my approach should be modified, that there could be some business-methods without using a hibernate-session and therefore no access to the database.

I'm not sure if i've understood you right (and i don't know the corix 4i FW), but setting a property (hand coded or directly by associating a textfield with a property) isn't something i would call a 'business-call' ... with business-call i've meant for example things like 'save object XY' (DB-Access) or 'calculate the next number' (without DB-Access) ... (stupid examples i know :) )

Trying it better :)
After taking a short look to corix 4i ... could it be, that it works a little bit like: Assigning eg. a Textfield to a property of my Bean? Everything i will write into this Textfield automatically will be set to my bean (nevertheless corix will create the bean automatically or i have to ... )?
If yes, there must be a 'save'-button somewhere ... activating this button would end in a 'business-call' (the business-call is perhaps something like a Use-Case) ...

gtx
curio


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 04, 2004 1:33 pm 
Newbie

Joined: Mon Oct 18, 2004 2:27 pm
Posts: 4
Well, but isn't that bending the layers a little bit?
I mean, I am developing the business layer and persistance/datasource layers, not the client/view layers.
Having the client call a persistant layer open session method is bypassing the business layer, so not a very good approach. If the client calls a method from the business layer that opens the session (the method will only call the open session from the persistance layer) then I will have a method in my business layer that is not business related, it is a completely persistance related method in the business layer. Maybe the first business method called from the business layer by the client will be in charge of opening the session but the who will close it and worse, the business layer will need a session control to know it the session is already open or not. That is not business logic.
I know I can tweak hibernate to work but my question is, can I keep the layers really independent and only responsible for it's task (there is no point in a client opening a session with the business layer or the persistance layer unless it knows there is a database that needs to open sessions because the properties are lazy and so on)? Am I not deviating from the objectives of Hibernate too much by doing so that maybe other kind of tool should be better suitted for me?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 04, 2004 3:44 pm 
Expert
Expert

Joined: Thu Jan 29, 2004 2:31 am
Posts: 362
Location: Switzerland, Bern
Hi curio

Thanks a lot for posting your thoughts.

After thinking about it for a while I still think that it only works with the session-per-application approach.
  1. 4i considers everything between 2 clicks on the save button (which does a commit) to be in the same transaction. AFAIK hibernate cannot have several sessions accross one DB transaction.
  2. 4i acts as an object browser which is able to navigate just every object reference in a generic way. This means every get on a property potentially leads to a lazy initialization of a proxy or a collection which of course requires the session.
  3. Throughout the livetime of a JVM process 4i requires object identity. AFAIK hibernate suports obejct identity only within one session.

I think I need either a clever idea to avoid the session-per-application approach or a explanation of what kind of problems I might face using it even if it's considered an antipattern.

TIA
Ernst


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 04, 2004 5:49 pm 
Expert
Expert

Joined: Tue Oct 05, 2004 9:45 am
Posts: 263
@electricb
I think it depends on what you need ... if it's okay for you to have a single transaction per persistence-layer-method call, hide the handling behind the interface ... if you need a transaction per business-case, you have to embed it in a transaction ... i think that's independet from hibernate ... you will stick to this problem which every approach i think ... in each case it's possible to hide this handling perfectly from business-logic ...
by the way ... perhaps lazy-loading initiated by the gui is not a good idea, because you never know if the gui is running on the same computer ... (just a thought of mine) ... therefore it could be better to initialize the complete object before passing it to the gui ...

@ernst
thanx for explaining 4i! ... the big thing i don't like is the reallly long transaction (point a) ... this transaction might exists over several minutes ... i (personally) like more the approach of using 'short transactions' ... Therefore i would collect the data entered in the gui in a bean and save it after clicking the 'save'-button in a short transaction and using 'session.disconnect()' after that ... In HiA chapter 8.2 is an explanation about some implementation-possibilities and how to handle a session ... perhaps that could help?
And yes, i think hibernate supports object identity only within one session ... i've read something in HiA about it but don't now exactly where and my book is at work ... but you could reattach your object to a new session? Could this be a possibility?

gtx
curio


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 3:39 am 
Expert
Expert

Joined: Thu Jan 29, 2004 2:31 am
Posts: 362
Location: Switzerland, Bern
Hi curio

Thanks for pointing me to HIA 8.2 I must have missed this!

About the long transactions:
I think this depends a lot on your application? I see two possibilities
  1. Have short technical transactions spawning a long business transaction and write everything at the end. Use versioning for optimistic locking.
  2. Have a long technical transaction which maps 1:1 to the long business transaction. If you want set the session flush mode to never.


For a struts based webapplication I'd probably go for the first one because the technical transaction handling is easier to do per Request than per HttpSession. For a Swing based Application (done in the corix 4i style) I'd probably go for the second one because there's no real request/response livecycle, but the clicks on the save button do give a clear application transaction demarcation.

HTH
Ernst


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 5:26 am 
Expert
Expert

Joined: Tue Oct 05, 2004 9:45 am
Posts: 263
hi ernst,

i'm besetting (hope that's the word i'm looking for 'hartn


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 2:09 pm 
Newbie

Joined: Mon Oct 18, 2004 2:27 pm
Posts: 4
I am looking for a more generallistic solution since I have no idea who and how my model will be used. There WILL be web applications probably in struts reading and writing information from the model as there WILL be command-line and swing clients doing the same.
It is not my intention to have the developer responsible for the web based client or the one responsible for the swing app open and close hibernate sessions.They should be far from even knowing that the model uses hibernate.
What I am doing ATM is not loading the lazy information and when the model receives a request for it a hibernate find is made and the information is returned. One problem is that I have no caching for that thus multiple requests for the same object will result in multiple db queries and different instances in memory.

Say I have Rabbit which has sons, since there are so many sons loading the Rabbit with a Set of sons is not feasible. So the idea is when I request a son from a rabbit I also give some criteria such as age. So Rabbit.getSon(1) will return a Set or List of 1 year-old sons of that rabbit by calling return RabbitSon.find(1, this) (this is the calling Rabbit).
RabbitSon.find wil actually run a HQL query with the given criteria and thus return the information for the calling Rabbit.
Since I am running a hibernate find the Rabbit father of the resulting sons will be instanciated AGAIN and if I call Rabbit.getSon(1) all sons will be instanciated again.
I gain performance by not loading all the sons but on the other hand besides also losing some performance I allow for the same object to have more than one different instances in the same application.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 5:30 pm 
Expert
Expert

Joined: Thu Jan 29, 2004 2:31 am
Posts: 362
Location: Switzerland, Bern
@curio
If handling the request takes a long time, yes why not doing it like that. But I think it's easier to stick to the "open session in view" pattern mentioned by
ko5tik.

About the session-per-application pattern:
  1. You are of course right that the session isn't thread save. IMHO SwingWorkers are most often used to keep the GUI responsive while doing some lengthy work. If only one SwingWorker deals with the session this is fine. Of course multiple concurrent SwingWorkers on the same session won't work.
  2. The exception handling is really a pain. This means if I catch a HibernateException the only thing I can do is show a nice message and stop the application.

@electricb
I see two approaches to you requirements:
  1. Take a J2EE server or another lightweight container if you perfer and set up a service oriented architecture. This way the only thing your clients will ever need to know is how to call a service.
  2. If your model is more a library used in different environments I'd say, pick the one which is best suited for the environment. This has of course the disadvantage, that the web/swing/batch developer will see a litle bit of hibernate.

HTH
Ernst
[/list]


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 16 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.