Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Nested (sql) transactions

by clueless newbie (Curate)
on Feb 03, 2012 at 22:26 UTC ( [id://951722]=perlquestion: print w/replies, xml ) Need Help??

clueless newbie has asked for the wisdom of the Perl Monks concerning the following question:

Nested transactions - thoughts, suggestions and comments requested.

Microsoft's SQL-Server supports nested transactions something that seem "natural" to Perl's notion of modules. Yet many databases do not support nested transactions - MySQL comes to mind. Perhaps the very nature of my being somewhat of a "clueless newbie" incited me to wonder if it's feasible to implement what amounts to nested transactions for those databases that don't support it.

I've been experimenting with "code" that looks like

### Transaction starts my $dbh=DBI->connect(...); transactionalize { # Code to be run as a transaction here #- no begin_work, commit, rollback, START TRAN, COMMIT TRAN, ROL +LBACK TRAN ... } using ($dbh); ### Transaction ends

and implemented transactionalize/using (along the lines of Try::Tiny's try/catch) with

{ # This code implement the transactionalize { ... } using ( dbh ); my (@dbh_AO,$dbh_HRef,$error_E); sub transactionalize(&;$) { my ($body_CRef,$dbh_CRef)=@_; eval { ### Setting dbh_O ... push(@dbh_AO,(defined $dbh_CRef) ? $dbh_CRef->() : $Defa +ultdbh_O); local $dbh_AO[-1]->{RaiseError}=1; warn "@dbh_AO "; ### BEGIN TRANSACTION ... unless (exists $dbh_HRef->{$dbh_AO[-1]}) { $dbh_AO[-1]->begin_work; $dbh_HRef->{$dbh_AO[-1]}=$dbh_AO[-1]; }; ### Do the stuff here ... $body_CRef->(); ### COMMIT TRANSACTION ... if (@dbh_AO == 1) { for my $dbh_s (keys %$dbh_HRef) { ### $dbh_s $dbh_HRef->{$dbh_s}->commit(); }; }; pop(@dbh_AO); }; if ($@) { $error_E||=$@; ### ROLLBACK TRANSACTION ... if (@dbh_AO == 1) { for my $dbh_s (keys %$dbh_HRef) { ### $dbh_s eval { $dbh_HRef->{$dbh_s}->rollback(); }; }; }; pop(@dbh_AO); Carp::confess $error_E; }; } # transactionalize {}: sub using($) { my $dbh_O=shift; ### <where>: $dbh_O return sub { return $dbh_O; }; }; };

Initial trials give me hope. Much more testing remains.

There are no doubt bugs that remain and enhancements that are needed.

Thoughts, suggestions, comments appreciated.

added: RaiseError

Replies are listed 'Best First'.
Re: Nested (sql) transactions
by tobyink (Canon) on Feb 04, 2012 at 00:38 UTC

    No, most databases don't support nested transactions, but many provide savepoints which allow roughly equivalent functionality. PostgreSQL and MySQL do; even recent releases of SQLite. Indeed, so does Microsoft SQL Server.

    So if you want to write decent cross-database code, use savepoints instead of nesting transactions. Of course, as is often the case in SQL land, syntax for establishing a savepoint, rolling back to a savepoint, or releasing (kinda like committing) a savepoint vary from database to database. But not too badly.

    Your code, as I understand it, when it wants a nested transaction, opens a new database connection, runs the nested transaction there, and holds the transaction open until it's sure the outer transaction is ready to commit. It's a reasonable solution in the case where you're on a database that does transactions but not savepoints.

    However, I think it probably has some flaws. You'd typically want code running in an inner transaction to be able to "see" database changes already made in the outer transaction. But if your database is doing ACID properly, then an independent transaction on a second database connection will not be able to see the changes made in the initial transaction until that initial transaction has been committed.

    Nested transactions do indeed have some advantages over savepoints. Savepoints need to be given names. That means that Perl code that is executing an SQL transaction, and calling other Perl modules to execute inner transactions, needs some co-ordination between modules to ensure that savepoint names are unique. Nested transactions are anonymous so don't have this problem.

      tobyink:Your code, as I understand it, when it wants a nested transaction, opens a new database connection, runs the nested transaction there, and holds the transaction open until it's sure the outer transaction is ready to commit. It's a reasonable solution in the case where you're on a database that does transactions but not savepoints.

      However, I think it probably has some flaws. You'd typically want code running in an inner transaction to be able to "see" database changes already made in the outer transaction. But if your database is doing ACID properly, then an independent transaction on a second database connection will not be able to see the changes made in the initial transaction until that initial transaction has been committed.

      clueless:Thank you for those thoughts. It doesn't require opening a new database connection. No doubt my example was somewhat misleading.

      It leaves a lot to be desired as far as ACID is concerned.

Re: Nested (sql) transactions
by CountZero (Bishop) on Feb 04, 2012 at 09:32 UTC
    I do not think it is possible to implement nested transactions that remain fully ACID compliant outside of the database engine itself as outside of your connection to the database may be many other connections you do not control and who knows what these other connections have done to the database.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: Nested (sql) transactions
by mbethke (Hermit) on Feb 04, 2012 at 05:16 UTC

    First of all, your code doesn't look noobish at all! The variable naming isn't my taste and would probably be considered un-perlish by most, but well, that's taste :)

    One problem that I can see apart from what tobyink spotted (he obviously has much more of a clue there than me, I've used simple transactions but never even heard of savepoints) is that you're rolling back transactions in random order if several DB handles were used. Why someone would want a single transaction to span things done on different connections I don't know but I guess if it does happen this could cause problems. Easy enough to fix though.

Re: Nested (sql) transactions
by repellent (Priest) on Feb 05, 2012 at 02:40 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://951722]
Approved by Eliya
Front-paged by Tanktalus
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (6)
As of 2024-04-19 10:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found