[Dbix-class] ROLLBACK seems to be skipped on 0.08
Louis Erickson
lerickson at rdwarf.net
Fri Nov 2 00:55:14 GMT 2007
Sorry to wake up a slightly old thread, but I've just been bit by this in
an 0.07 to 0.08 upgrade, and found this thread. (This bit me as soon as I
started using 0.08. I just started using it or I'd have asked earlier.)
One difference between what I'm reading here and what I'm seeing in my own
app is that I always do a txn_begin/txn_commit, and it does not work as
I'd expect, either.
(It starts at a transaction level of 1, which is incremented by the begin,
and decremented by the commit, so that it never actually commits to the
DB. To either comment out the begin or add an extra commit works around
it, despite being extremely goofy looking.)
I do have a question regarding txn_do, though, for I don't understand how
it can work properly with AutoCommit => 1.
On Sun, 21 Oct 2007, Jesper Krogh wrote:
> Ok.. maybe I didnt make it clear. The problem is that we "serialize"
> object into several records (over 20 mostly) and this serialization
> process should be done atomically, so I don't get any "half-objects" in
> the database. It wasn't the individual record I was talking about.
>
> This dataset is conceptually "inconsistent" to the application if this
> happens. But the database is of course not aware of this.
This is the primary reason I was using manual txn_begin/txn_commit calls,
and AutoCommit=>0.
> txn_begin/commit and txn_do solves this.
How does txn_do solve this? This is the part I don't understand. Perhaps
one of the experts here can explain it.
Let's consider the following sequence:
txn_begin
Add one
add two
add three
Fail!
txn_rollback
I don't see a significant difference between txn_do and this case, at
least for the purposes of my discussion. If I'm wrong about that, please
let me know why!
With AutoCommit=>0, other connections to the DB will see none of one, two
or three. Only when the commit occurs will that entire operation be made
visible to other database connections. Since it is rolled back, they are
never made visible.
(Yes, I have tested this with my database. I don't know about SQLite or
mysql, but there are databases that get this right.)
With AutoCommit=>1, one, two and three will exist in the DB, leaving it in
a state which other running queries may find and use that data. Even if
txn_rollback is smart enough to unwind every change it made (I presume it
is) there will be a window where there is partially defined information
visible in the database.
At all times the DB maintains relational integrity. This will be data
that isn't consistent from the business rules I'm trying to build in the
application.
What of the case where the app segfaults or the connection fails during or
before the app-implemented rollback? With AutoCommit=>1 the DB will never
get cleaned up. (Actually, DBIC might be smart enough to handle a
reconnect, but a segfault or other app shutdown is still a killer.) With
AutoCommit=>0, the changes should roll back when the connection is lost.
What am I misunderstanding to think that these are not risks? (I almost
can't believe that someone from this group didn't think of this, so I'm
assuming I missed something.)
One solution would be to drive the multiple-step operations in to stored
procedures. That means I'm suddenly incredibly DB specific, whereas right
now it's all in Perl, using proper transactions. I'd rather not move to
SPs if I don't have to.
It may be that DBIC makes all these changes as quickly as possible so that
the window for error is minimized. The window is still there, though.
The solution there is just to not care so much, and let DBIC get on with
things, which is probably fine for most apps, but I wouldn't want my bank
or the air traffic control people to do it. If there is such a hole, it
should be documented so high-risk applications know about it.
As far as trying to solve this for DBIC goes, there may not be a good
solution. I just read the long thread from late October, and I do
understand that it's complicated.
I have a possible suggestion. I don't think it was proposed before,
although I might have missed it.
With AutoCommit=>1, do the things it does to make transactions work now
that seems to be acceptable.
With AutoCommit=>0, add an implicit txn_begin() and txn_end() call, with
the txn_begin on connect and txn_end on disconnect, forcing a disconnect
in an END block. Code which did not use any transactions would still
work, and people who expected to do their own would still work. Their
commit would just be delayed until disconnect. Make an extra commit do
the commit, with a warning, so code with no begin works but is fixed
eventually. Perhaps add a warning that this mode may be inconsistent,
error-prone, etc. Also document this risk.
It might then be possible to add a new flag, something like
ManualTransactions or ExplicitTransactions or AnalDBA or something to make
the txn_begin/commit/rollback work at the DB level and let the developer
do it themselves, if this was something you wanted to even consider
supporting. (It would die if AutoCommit=>1, and would suppress the
warning mentioned above.)
If the use of txn_do/AutoCommit=>1 does address the possible
inconsistencies across multiple operations, then the support for
AutoCommit=>0 is really not important. If it does leave the opportunity
for other processes to find partial operations in the DB, I think the
ability to use the database's atomic multi-operation commits is more
important.
Any explanation of what I might be misunderstanding would be welcome!
--
Louis Erickson - lerickson at rdwarf.net - http://www.rdwarf.com/~wwonko/
I am so optimistic about beef prices that I've just leased a pot roast
with an option to buy.
More information about the DBIx-Class
mailing list