#作業環境
PHP5.3 + Fuel 1.8.1 + Doctrine
#問題
業務上、1つのトランザクションの中に、下記のPseudoコードの感じで処理を実行し、最後纏めてコミットしたい。
$em = \Fuel\Doctrine::manager("default");
$em->getConnection()->beginTransaction();
…
DB登録処理呼び出し関数1($em);
DBクエリ処理呼び出し関数1($em);
繰り返し処理{
…
DB登録処理呼び出し関数2($em);
DB更新処理呼び出し関数1($em);
…
}
…
DB更新処理呼び出し関数2($em);
$em->commit();
が、コミットはどうしても成功せず、3日を悩まされました。
#調査経過
たまたま、Doctrineトランザクション管理のNestingレベルを見ようとして、
Doctrineトランザクション公式参照⇒https://www.doctrine-project...
⇓をDB変更や登録関数の実行前後に貼って、驚きの結果がわかりました。
echo "TransactionNestingLevel Before Insert :".$em->getConnection()->getTransactionNestingLevel()."\n";
繰り返し処理の中で、Nestingレベルの数値がどんどん上がる!!!
TransactionNestingLevel Before Insert :11
TransactionNestingLevel After Insert :11
TransactionNestingLevel Before Insert :41
TransactionNestingLevel After Insert :41
TransactionNestingLevel Before Insert :215
TransactionNestingLevel After Insert :215
TransactionNestingLevel Before Insert :301
TransactionNestingLevel After Insert :301
TransactionNestingLevel Before Insert :345
TransactionNestingLevel After Insert :345
TransactionNestingLevel Before Insert :395
TransactionNestingLevel After Insert :395
TransactionNestingLevel Before Insert :461
TransactionNestingLevel After Insert :461
トランザクション階層が461階層に⇓
トランザクション階層1
トランザクション階層2
トランザクション階層3
…
トランザクション階層461
変更をDBに反映するために、$em->commit();
を__460__回実行せよ!!だからコミットできないか!
待って!今回操作対象データが230件。最後に461件というのは、230の2倍がプラスされたんじゃないか?都合がいい数値に手がかりがありそう!!
いろいろ実験を経て、下記の感じのコードを実行すると、不具合の箇所が特定できました。
$em = \Fuel\Doctrine::manager("default");
$em->getConnection()->beginTransaction();
echo "TransactionNestingLevel beginTransaction:".$em->getConnection()->getTransactionNestingLevel()."\n";
$info = array();
$info[0] = array(
"Sequence"=>5
…
);
$info[1] = array(
"Sequence"=>6
…
);
echo "TransactionNestingLevel After Setting array :".$em->getConnection()->getTransactionNestingLevel()."\n";
結果:
TransactionNestingLevel beginTransaction :1
TransactionNestingLevel After Setting array :3
#結論
__配列代入処理が一回実行で、DoctrineのトランザクションNestingレベルが1 Plusされる__ことが分かりました。だからか!前230件の2倍Plusされるのも、登録関数が呼ばれる前に、データを配列で渡すために、配列代入処理を2回実施しましたからです。
わけわからねぇ!!!!!
#対策
はい!退避策として、繰り返し処理の中のDB変更処理を全部外に出して、$em->getConnection()->setAutoCommit(false);
で、繰り返し処理でPlusされたトランザクションレベルを1に戻した。
$em = \Fuel\Doctrine::manager("default");
$em->getConnection()->beginTransaction();
…
DB登録処理呼び出し関数1($em);
DBクエリ処理呼び出し関数1($em);
繰り返し処理{
…
…
}
…
$em->getConnection()->setAutoCommit(false);
DB登録処理呼び出し関数2($em);
DB更新処理呼び出し関数1($em);
…
DB更新処理呼び出し関数2($em);
$em->commit();