suppose i’ve 2 active record name bank_fund and user_fund
i want to transfer value from bank to user say 10$
i use transaction to make sure that following steps are excuted:
1- check if fund in bank is > 10$ so to withdraw
2- update bank fund with 10$ deduction
3- add 10$ to user_fund
so how to excute that using transaction with active record ?
my second question : if step num 1 and num 2 successed but step 3 failed so rollover the process again .ok is that means another deduction of 10$ will occurs again or what will happend?
If you use db transaction and do rollback then ALL inserts and updates are undone.
There is however one problem - you cannot simply do ‘SELECT FOR UPDATE’ with active record and that is required to lock account record for concurrent reads/updates. Another solution is to add filter ‘AND fund > 10’ on update statement and check if there are updated records after execution.
ok after i had finished testing some senarios ,if you want to use transaction for multiple tables you should use only the following code (not active record)
transaction=$connection->beginTransaction();
try
{
$connection->createCommand($sql1)->execute();
$connection->createCommand($sql2)->execute();
//.... other SQL executions
$transaction->commit();
}
catch(Exception $e) // an exception is raised if a query fails
{
$transaction->rollback();
}
what tests did you run? did you also check returned value from save() functions? it returns false when saving failed…
transaction is created on database level so it is practically impossible for any insert/update statements run between ‘start transaction’ and ‘rollback’ not being undone…
there is another thing: if you use MySQL MyISAM tables - they do not support transaction but MySQL will not throw any errors in such case.
but you confused transactions with error handling. Transactions are to ensure that a set of statements is executed in full or none of the statements. It has nothing to do with error handling. you have to decide by yourself whether you want to commit the transaction or rollback it. When using AR save() method you have to check return value if the saving was successfull or not and handle that information somehow.
try this code with AR and it should do the trick and work like you want:
$model=bank_fund::model();
$model1 = user_bank::model()
$transaction=$model->dbConnection->beginTransaction();
try
{
$bank_fund=$model->findByPk(1);
$bank_fund->fund -= 10 ;
if( !$bank_fund->save() ) {
throw new Exception( 'Bank fund saving error' );
}
$user_bank = $model->findByPk(56) //id of user
$user_bank->fund += 10;
if( !$user_bank->save() ) {
throw new Exception( 'User fund saving error' );
}
$transaction->commit();
}
catch(Exception $e)
{
$transaction->rollback();
}
you are right , i figure out what’s wrong with active record code that make one query successed and the other fail, it was the validation rule that prevent the query from beign excuted ie: no sql query is generated.