🙆
【PHP】トランザクションのネストを回避する
トランザクションのネストについて
調べたところ、RDBの違いによって挙動が異なるため、トランザクションのネストは「好ましく無い」ようです。
自分も同じような場面に差し掛かったので、回避した方法を載せます。
【背景】
funcA()
内で既存の関数funcB()
をどうしても使いたい。
しかし、funcB()
には既にトランザクションが貼ってあるのでfuncA()
でトランザクションを貼ってしまうとトランザクションがネストしてしまう。
修正前
public function funcA(){
$transction = Transaction::begin();
try{
User::create();
funcB();
$transaction->commit();
}catch{
$transaction->rollback();
}
}
public function funcB(){
$transction = Transaction::begin();
try{
UserHistory::create();
UserStatus::create();
$transaction->commit();
}catch{
$transaction->rollback();
}
}
上記の場合、funcB()
でもトランザクションを貼っていて、呼び出し元のfuncA()
でもトランザクションを貼っています。
修正後
public function funcA(){
$transction = Transaction::begin();
$is_user_transaction = false;
try{
User::create();
funcB($is_user_transaction);
$transaction->commit();
}catch{
$transaction->rollback();
}
}
public function funcB(bool $is_user_transaction = true){
if($is_user_transaction){
$transction = Transaction::begin();
}
try{
UserHistory::create();
UserStatus::create();
if($is_user_transaction){
$transaction->commit();
}
}catch{
if($is_user_transaction){
$transaction->rollback();
}
}
}
このようにしてみました。
端的には、funcA()
を実行するときのみfuncB()
のトランザクションを外して、funcA()
にトランザクションを貼っています。これによりトランザクションのネストを防ぐことができます。
funcB()
は、他の箇所でも使われている関数になります。
よって、基本的には$is_user_transaction = true
です。
宣伝
パーソンリンクではエンジニアを募集しています!
Discussion