Logging is *the* classic use case for keeping a second transaction.
Open your logging in a second session.
My solution as stated obviously only works with one transaction per
request, though it can probably be adapted to the long-term session
model (filter commits without closing the session, calls clear() on
rollback). FWIW, I don't like long-term sessions either.
Anyway, I was just arguing with this statement:
I really think the whole "we refuse to automatically reconnect to
lazy-load a connection and instead insist on throwing and
exception" is database-purist-arrogance on the part of the
Hibernate team. Most of their library is great, but this behavior
is just *not* web friendly, and their smug assurance that it's "not
a big deal to workaround" turns out not to be true in practice.
That's a little hard on Hibernate. Granted that they could provide
more options, but ... working within the one-transaction-per-request
model that you prefer, it is, in fact, not a big deal to work with --
with, not around.
Cheers,
Paul
On Aug 30, 2005, at 5:39 PM, Patrick Casey wrote:
I don't think that gets you around the lazy initialization problem
though, does it? If the session closes when the servlet returns,
then it's
no longer available in subsequent interactions to load lazy
collections.
Likewise, globally rolling back the transaction isn't necessarily
the right approach either (yet another gripe I have about how
hibernate and
the web fight one another).
This is a slightly contrived example, but for purposes of
explanation it should work:
Lets say I need to log every user interaction to the DB (not that
weird actually, I've had to do this on some security conscious apps).
So whenever A user presses "save" on a web form I have to:
Log an "interaction begun" datum with the IP address, session ID,
etc.
Do the transaction.
Log an "interaction complete" datum with the UP address,
session ID,
etc.
If I roll back globally, I lose not only the user's personal
update
(which I want to roll back), but also the interaction records, which I
*don't* want to roll back.
It's gotten so aggravating I'm seriously considering using two
parallel session. One for "system" data that I have control of and
one for
"user" updates that I might have to roll back. That way I can
always flush
my system session and selectively flush the user session. Of course
that
means twice the number of DB connections, dogs and cats living
together,
etc, etc, etc.
It's frustrating, as you can doubtless discern from my aggravated
tone :(.
--- Pat
-----Original Message-----
From: Paul Cantrell [mailto:[EMAIL PROTECTED]
Sent: Tuesday, August 30, 2005 3:23 PM
To: Tapestry users
Subject: Re: Transaction handling. Where?
If you open & close your ThreadLocal session from a *servlet filter*
instead of trying to finagle it into the tapestry lifecycle,
everything is peachy -- at least in my limited experience.
For rollbacks, implement a preventCommit() method your code can call
on error. In the filter, you either commit or roll back depending on
whether preventCommit() was called.
Cheers,
Paul
On Aug 30, 2005, at 4:22 PM, Patrick Casey wrote:
Yah, I'm familiar with a large variety of ways to initialize
collections. The problem with pre-initializing everything though is
that
most of the time, you *don't* need the whole object graph. So if I
have to
fill out every object graph every time I load a root object on
the off
chance that somewhere, someday, someone might reference a child
object, I
end up wasting a lot of memory and database labour.
As for long sessions being a bad idea; they *definitely* have
their
risks, especially if you aren't careful about evicting things when
they
aren't needed anymore. For web applications though, they really
seem like
the only practical approach in my experience. The threadlocal
pattern can't
solve the initialization problem, and the session-per-transaction
pattern
has performance problems *and* the lazy initialization problem.
I really think the whole "we refuse to automatically
reconnect to
lazy-load a connection and instead insist on throwing and
exception" is
database-purist-arrogance on the part of the Hibernate team. Most
of their
library is great, but this behavior is just *not* web friendly, and
their
smug assurance that it's "not a big deal to workaround" turns out
not to be
true in practice.
--- Pat
-----Original Message-----
From: Tomáš Drenčák [mailto:[EMAIL PROTECTED]
Sent: Tuesday, August 30, 2005 2:16 PM
To: Tapestry users
Subject: Re: Transaction handling. Where?
You can initialize collections with Hibernate.initialize
(collection),
or in query with left join fetch and than use detached objects in
further requests. And btw I've read that long open sessions aren't
good idea at all...
2005/8/30, Patrick Casey <[EMAIL PROTECTED]>:
As I understand it though, with this approach the session
has a
lifespan that doesn't span multiple requests (in fact, its
granularity
is <
1 request). This raises problems in practice with use cases like:
User has a set of roles (lazy collection)
I bring up the User page. It loads from Session #1 which
is then
closed.
I click on the "show roles" button. We go back to Tapestry
which
merrily does a user.getRoles().iterator() and promptly blows up
with a
lazy
initialization exception because Session #1 (the one which
produced the
user) no longer exists.
That and creating a fresh session for each database
interaction,
while not quite as bad a plan as creating a new JDBC connection
for each
query, is still not a great performance idea :(.
--- Pat
-----Original Message-----
From: Tomáš Drenčák [mailto:[EMAIL PROTECTED]
Sent: Tuesday, August 30, 2005 1:58 PM
To: Tapestry users
Subject: Re: Transaction handling. Where?
I use classes described in
http://www.theserverside.com/articles/content/HivemindBuzz/
article.html.
This is perfect approach for DAO pattern. Just declare DAO
object as
service with implementation and property of type
org.hibernate.Session
and setter setSession(Session). Session is then created uppon
your
request to service and always initialized and closed through
ApplicationServlet which cleanups hivemind. There's also
transaction
interceptor...
2005/8/30, Chris Chiappone <[EMAIL PROTECTED]>:
Thanks, if I were to use this helperclass would I still go about
getting the session before a save or update and closing the
session
after complete, as i was before?
Also have you thought about using something like HiveTrans to do
this
for you? I have been thinking about moving to tap 4 and using
hivemind with hivetrans to deal with the hibernate session
management.
Any thoughts??
On 8/30/05, Patrick Casey <[EMAIL PROTECTED]> wrote:
To be honest, I *haven't* completely gotten around this
problem.
I've *sort of* gotten around it by going to a long-session
pattern
so
that
the Hibernate session virtually never flushes. If you want
though
I'll
attach my HibHelper class so you can get a feel for what I did.
Honestly though, it's not a magic bullet and I'm still
struggling to
find one. Still, if it gets you partway there, you're
welcome to
use
it,
modify it, whatever.
To use it effectively you'll need a combination of the
HibHelper
class (above) and the subclassed engine I provided earlier
which
stores and
retrieves the Hibernate session from the user session.
--- Pat
-----Original Message-----
From: Chris Chiappone [mailto:[EMAIL PROTECTED]
Sent: Tuesday, August 30, 2005 1:40 PM
To: Tapestry users
Subject: Re: Transaction handling. Where?
I was search back some threads and noticed your HibHelper
class.
Is
that basically the way you've gotten around this problem,
HibHelper
and the Servlet class you wrote?
On 8/30/05, Patrick Casey <[EMAIL PROTECTED]> wrote:
Not necessarily, but it depends on how you want your
system
to
manage transactions. One area where Hibernate and Tapestry
don't
"play
nice"
is with data binding.
Let's say I have a "user" form that is bound to a
persistent User
object.
Form gets rendered and goes out.
User does some stuff and presses save.
Form comes in, rewinds, and delta is pushed through
into
"user"
object.
*** At this point the user object is flagged by
Hibernate
as
dirty.
The next time the session flushes, it'll write through to the
database,
whether or not you call saveOrUpdate()!
This is problematic if, for example, you want to
cancel
the
update
because of failed validations :(.
One approach that can help is to evict everything from
the
session
on load so that it doesn't auto-flush. If you do this though,
you
will
likely have lazy initialization problems later on.
Another approach is to not directly bind your page to
your
persistent object, but that adds a whole other level of work
to
the page
class.
All in all, I have not been happy with the interaction
between
Hibernate and Tapestry. With a classic servlet engine it's
not
a
biggy
because you can just not push invalid updates into the
persistent
object.
With Tapestry though, the (normally helpful) behavior of
directly
binding
user updates into the underlying persistent object doesn't
allow
the
programmer any control over when updates go through.
Basically it all comes down to Hibernate insisting
that
it
knows
better than the programmer when things ought to be saved to
the DB
:(.
--- Pat
-----Original Message-----
From: Chris Chiappone [mailto:[EMAIL PROTECTED]
Sent: Tuesday, August 30, 2005 1:07 PM
To: Tapestry users
Subject: Re: Transaction handling. Where?
In my DOA i do the following...
public void makePersistentUser(Users user)
throws InfrastructureException {
try {
HibernateUtil.beginTransaction();
HibernateUtil.getSession().saveOrUpdate(user);
HibernateUtil.commitTransaction();
HibernateUtil.closeSession();
} catch (HibernateException ex) {
throw new
InfrastructureException(ex);
}
}
Is this the wrong way to do it??
On 8/30/05, Patrick Casey <[EMAIL PROTECTED]> wrote:
Have you tried subclassing BaseEngine and doing
your
transaction
management in cleanupAfterRequest() and setupForRequest()
e.g.
public class CorinnaEngine extends BaseEngine {
private static final long serialVersionUID =
3257284742721648952L;
protected void cleanupAfterRequest(IRequestCycle
cycle)
{
HibHelper.cleanupSession();
super.cleanupAfterRequest(cycle);
}
protected void setupForRequest(RequestContext
context)
{
HttpSession hs =
MyServlet.getCurrentSession();
HibHelper.attachSession(hs);
HibHelper.getSession();
super.setupForRequest(context);
}
}
-----Original Message-----
From: Koka [mailto:[EMAIL PROTECTED]
Sent: Tuesday, August 30, 2005 12:00 PM
To: tapestry-user@jakarta.apache.org
Subject: Transaction handling. Where?
Well, I have pages that allow to edit some database
data, so
I
have
easy
solution to start transaction at
public void pageBeginRender(PageEvent event)
{
if (event.getRequestCycle().isRewinding())
// start transaction here
}
and at
public void pageEndRender(PageEvent event)
{
if (event.getRequestCycle().isRewinding())
{
// Commit or rollback if errors found
}
}
Hmm, it WORKS fine but, hmmm, page render and
transactions...,
agrrr
sure
there's some other place to handle things.So the
question is
what
is
the
right place to start/end transaction in Tap4
TYA
----------------------------------------------------------
----
------
-
To unsubscribe, e-mail: tapestry-user-
[EMAIL PROTECTED]
For additional commands, e-mail: tapestry-user-
[EMAIL PROTECTED]
--
~chris
------------------------------------------------------------
----
-----
To unsubscribe, e-mail: tapestry-user-
[EMAIL PROTECTED]
For additional commands, e-mail: tapestry-user-
[EMAIL PROTECTED]
-------------------------------------------------------------
-
----
---
To unsubscribe, e-mail: tapestry-user-
[EMAIL PROTECTED]
For additional commands, e-mail: tapestry-user-
[EMAIL PROTECTED]
--
~chris
--------------------------------------------------------------
--
----
-
To unsubscribe, e-mail: tapestry-user-
[EMAIL PROTECTED]
For additional commands, e-mail: tapestry-user-
[EMAIL PROTECTED]
---------------------------------------------------------------
--
-
---
To unsubscribe, e-mail: tapestry-user-
[EMAIL PROTECTED]
For additional commands, e-mail: tapestry-user-
[EMAIL PROTECTED]
--
~chris
----------------------------------------------------------------
--
--
-
To unsubscribe, e-mail: tapestry-user-
[EMAIL PROTECTED]
For additional commands, e-mail: tapestry-user-
[EMAIL PROTECTED]
-----------------------------------------------------------------
--
--
To unsubscribe, e-mail: tapestry-user-
[EMAIL PROTECTED]
For additional commands, e-mail: tapestry-user-
[EMAIL PROTECTED]
------------------------------------------------------------------
--
-
To unsubscribe, e-mail: tapestry-user-
[EMAIL PROTECTED]
For additional commands, e-mail: tapestry-user-
[EMAIL PROTECTED]
--------------------------------------------------------------------
-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: tapestry-user-
[EMAIL PROTECTED]
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: tapestry-user-
[EMAIL PROTECTED]
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]