You need to decide on 2 things:
- Your session management strategy
- Your associated fetching strategy
There is good post by Gavin King that explains some of the options for handling sessions (the post is about performance, but is generally applicable too).
As for fetching, one thing to consider is increasing the number of primitives made available by your Hibernate layer. E.g. imagine you have a entity Foo that has a 1-N relationship to Bar and some circumstances you need just the Foo objects, but in others you need both the Foos and the child Bar objects. You could those represented as separate calls to the Hibernate layer.
class HibernateLayer {
public List<Foo> findFoo(String someCriteria) {
Query q = new Query("from Foo f where f.someCriteria = :1");
//...
}
public List<Foo> findFooWithBars(String someCriteria) {
Query q = new Query("from Foo f left join fetch Bar b where f.someCriteria = :1");
//...
}
This has 2 benefits, 1 you won't deal with lazy loaded proxy objects, you'll have all the data that you need and it will perform better as the SQL generated will be more appropriate to the situation. However it will have the drawback that you will need to know before calling the Hibernate layer whether or not you will need the deeper level of data. To ensure that your data remains consistent (the main purpose of transactions) make sure you use optimistic locking at the very least.