Re: Transaction handling with Oracle DBD
- From: mchase@xxxxxxxxxxxxx (Michael A Chase)
- Date: Sat, 23 Apr 2005 16:52:37 -0700
On 04/23/2005 08:30 AM, RKris said:
Hi, I am getting data corruption when I attempt to run>
several processes in parallel when making changes to
two tables.
DBD version 1.16, DBI version 1.48, Linux 2.6, Oracle 9i.
I am trying to select a counter value from table 1,
insert it into table 2 and update table 1 counter
value. This comprises a transaction. I do this 1000
times in a 'for' loop. Even after I clear out the
counter value in table 1 and run the test with two
processes, I am getting a value of 3000 in the
counter!
I'll restate that to make sure I understand. You are running two processes that read and update the same tables. You expect them to each loop 1000 times which would make the counter 2000, but you get a counter value of 3000 instead.
I included the code below. I moved the connect into the 'for' loop as I read connect automatically starts a transaction. Please let me know if I am doing something wrong! Thanks a lot.
You did not include the code. Your connect would have failed immediately and the loop counter you give below is 100 instead of 1000.
Saying that connect() restarts a transaction understates what it does by a long shot. It establishes an entirely new connection to the database.
The documentation for DBI and DBD::Oracle are available at CPAN.
http://search.cpan.org/dist/DBI/DBI.pm
http://search.cpan.org/~timb/DBD-Oracle/Oracle.pm
#> #!/usr/bin/perl
#!/usr/bin/perl -w use strict;
# It's hard to have too much error checking.
use DBI;
# DB name used by Perl Script $PS_DBNAME = "DBI:Oracle:xyz";
$DB_USERID="abc";
$DB_PASS="def";
# The connect() definitely does not belong inside the loop. # Further, you didn't turn off autocommit in your example, so # each INSERT or UPDATE statement gets committed immediately. my $dbh = DBI -> connect( $PS_DBNAME, $DB_USERID, $DB_PASS, { AutoCommit => 0, RaiseError => 1, PrintError => 0 } ) or die "Couldn't connect to database: $DBI::errstr\n";
# You should also prepare all your statements outside the loop. # I set RaiseError so individual error checks aren't needed. my $sth = $dbh -> prepare( 'SELECT counter FROM count_tab' ); my $sthI = $dbh -> prepare( "INSERT INTO data_tab (counter) VALUES (?)" ); my $sthU = $dbh -> prepare( "UPDATE count_tab SET counter = ?" );
$counterval = 0; $i = 0;
#> for($i=0; $i<100; $i++)
for ( $i = 1; $i < 1000; ++$i )
{
#> my $dbh = DBI->connect(PS_DBNAME, $DB_USERID, #> $DB_PASS) #> or die "Couldn't connect to database: " . #> DBI->errstr; #> $dbh->begin_work;
# begin_work isn't needed in this case.
eval {
#> my $sth = $dbh->prepare('SELECT counter FROM count_tab')
#> or die "Couldn't prepare statement: " . $dbh->errstr;
$sth->execute() or die "Couldn't execute statement: " . $sth->errstr; # there should be only one row
#> while (@data = $sth->fetchrow_array())
#> {
#> $counterval = $data[0];
#> }# If you only want one row, just fetch one. $counterval = $sth -> fetchrow_array(); $sthI -> execute( $counterval );
#> $dbh->do("INSERT INTO data_tab (counter) VALUES($counterval)")
#> or die "Couldn't prepare statement: " . $dbh->errstr;
$counterval = $counterval + 1;
#> $dbh->do("UPDATE count_tab SET counter = $counterval")
#> or die "Couldn't prepare statement: " . $dbh->errstr;$sthU -> execute( $counterval );
$sth -> finish;
# Finish is not needed here since you immediately # reexecute the statement. # It might be useful immediately before the disconnect # to avoid a complaint about an open statement.
};
if ($@) {
$dbh->rollback;
# eval{} keeps error messages from being written to STDOUT, # so pass the error message along. die $@;
}#> $dbh->disconnect;
else {
$dbh->commit;
}
}
# Connecting and disconnecting are both very expensive, # so don't do them inside a data loop. $sth -> finish if $sth; $dbh -> disconnect;
exit 0;
-- Mac :}) ** I usually forward private questions to the appropriate mail list. ** Ask Smarter: http://www.catb.org/~esr/faqs/smart-questions.html Give a hobbit a fish and he eats fish for a day. Give a hobbit a ring and he eats fish for an age. .
- References:
- Transaction handling with Oracle DBD
- From: RKris
- Transaction handling with Oracle DBD
- Prev by Date: select through DBD::CSV
- Next by Date: Re: [cgiapp] Re: cleaning up html?
- Previous by thread: Transaction handling with Oracle DBD
- Next by thread: Re: Transaction handling with Oracle DBD
- Index(es):
Relevant Pages
|