Sr. Web Developer
mediabistro.com
US-NY-New York

Justtechjobs.com Post A Job | Post A Resume

Best Practices: Database Transactions
And if you're updating a row of data, you should first get a lock on that row so it doesn't change while you're in the middle of a transaction.
A very simple example follows:
BEGIN;

SELECT * FROM users WHERE user_id=1 FOR UPDATE;

--
--do some time-consuming work in here
--
--set up $calculation variable based on work
--

UPDATE users SET field1='$calcultation' WHERE user_id=1;

--send email update to user

COMMIT;
At first glance, you might be tempted to simply wrap the calculations and update inside a transaction, but to be 100% kosher, you should also include the email sending and any other page display code within your transaction.
Why? Well, what if another transaction ran after your update, but before you sent out the email? The email you send could be tainted by the other transaction and the recipient would receive 2 emails reflecting the second transaction.
Sound petty? Well, it might very well be, but we're talking about best practices here and you might as well know the best possible way to do it. Is the world going to end in the extremely rare occasion where the inaccurate email was sent? Probably not, unless you're talking about a financial application and/or a very high-traffic web site.
Here's a piece of code from the Linux Journal article that shows how to handle a transaction in the event it fails:

<?php

function cart_new() {
    
//make the database connection handle available
    
global $conn,$customer_id,$feedback;

    
//start a transaction
    
query("BEGIN WORK");

    
//query postgres for the next value in our sequence
    
$res=query("SELECT nextval('seq_customer_id')");

    
//check for errors
    
if (!$res || pg_numrows($res)<1) {
        
$feedback .= pg_errormessage($conn);
        
$feedback .= ' Error - Database didn\'t return next value ';
        
query("ROLLBACK");
        return
false;
    } else {
        
//set that value in a local var
        
$customer_id=pg_result($res,0,0);

        
//register the id with PHP4
        
session_register('customer_id');

        
//insert the new customer row
        
$res=query("INSERT INTO customers (customer_id) VALUES ('$customer_id')");

        
//check for errors
        
if (!$res || pg_cmdtuples($res)<1) {
            
$feedback .= pg_errormessage($conn);
            
$feedback .= ' Error - couldn\'t insert new customer row ';
            
query("ROLLBACK");
            return
false;
        } else {
            
//commit this transaction
            
query("COMMIT");
            return
true;
        }
    }
}

?>
Here's some basic pseudocode for what's happening there:
1. BEGIN transaction;

2. Do first insert

	--check for errors and rollback if necessary

3. Do second insert

	--check for errors and rollback if necessary

4. Display results after update

5. COMMIT;
I haven't figured out the perfect solution yet to a problem that I've been running into lately. How do you handle the situation where you are inside of a transaction and you want to call a function that has a transaction coded in of its own? Postgres chokes when trying to do a transaction within a transaction, and it's a vexing problem really. Do you just avoid coding begin/commit blocks inside of function calls, or do you pass extra params to the function to skip the transaction code? Or am I missing something obvious?
Also, what do you do when you are mixing database code with file i/o or other code that cannot be rolled back? On SourceForge, we are using LDAP modules and LDAP does not have a rollback feature. So if something screws up, you may be able to rollback changes to the database, but not your LDAP directory, causing inconsistencies. Thoughts and opinions are welcome.
Now you should have the fundamental building blocks for working with transactions. Let me know if you have questions or comments - I'd be interested in knowing how you make use of transactional databases in your PHP applications.
--Tim

[Page 1]  [Page 2]  


Comments:
full theory about database transactions ??Girish Agarwal01/27/05 00:36
RE: excellent articleLance Edusei07/14/04 08:30
RE: MySQL TransactionsRob Limbrey01/21/03 08:45
MySQL TransactionsImtiaz10/16/02 06:22
MULTIPLE TABLES OR HUGE TABLES-BETTER OPTION?Kapil10/06/02 10:48
please found out my code mistakesMary Pei10/04/02 05:44
project work please help usmike smith09/11/02 06:51
RE: Transaction in MySQLPedro Salgado08/13/02 07:12
PostgreSQL nested transactionsLonny L GRanstrom08/09/02 22:36
RE: How to trigger RollbackVinco07/07/02 01:55
How to trigger RollbackIgor04/25/02 23:46
What about batch updates?pedro03/10/02 20:41
LDAP "Rollback"Fraser02/06/02 20:57
nested transactions - my solutionShivers08/17/01 12:57
PHP, MSSQL7 and TransactionsAndrew Prior04/25/01 05:47
XML and pgSQLmoses03/06/01 14:09
RE: transactions...george02/07/01 06:29
transactions...michael kristopeit02/05/01 11:35
RE: MySQL TransactionsRyan Ayers01/30/01 22:41
Clean solution to nested transactionsJeffrey Greer01/28/01 16:43
RE: sessions and DB transactionsKai Meder01/27/01 18:37
RE: MySQL TransactionsKai Meder01/27/01 18:35
sessions and DB transactionsJohn Harnett01/26/01 23:17
nextval/currval in postgresDon Baccus01/26/01 20:54
Transactions in functions vs. PostgresDon Baccus01/26/01 20:46
Re: I hate duplicate functions.Kirk Parker01/24/01 19:20
RE: nested xactionsPeter Moulding01/24/01 17:24
RE: excellent articlePeter Moulding01/24/01 17:18
RE: Transaction in MySQLMattias01/23/01 05:28
RE: nested xactionsJBW01/22/01 23:37
Transaction in MySQLHabibi01/22/01 18:22
MySQL TransactionsRyan Ayers01/22/01 14:30
excellent articleRyan McGeary01/22/01 09:35
nested xactionsJim G01/22/01 08:48
IdeasAndrew Coldham01/22/01 03:49
 

If you are looking for help, please post on the appropriate forum here. Your questions will be answered much more quickly.

Add A Comment:

Name:

Email:

Subject:

Message:

To reduce spam posts, messages are now manually approved

You are not [logged in]. That means your account will not get credit for this post.