--> -->

skimemo


Laravel-20190113 の変更点


#title(insertGetIdはスレッドセーフなのか?);
* insertGetIdはスレッドセーフなのか? [#e736011e]
DBにデータをinsertした後、Auto Incrementのフィールドに何が入ったかを知りたいケースがあります。そんな時に便利なのが、&inlinecode{insertGetId()};です。([[自動増分:https://readouble.com/laravel/5.4/ja/queries.html#inserts]])~
~
ソースを見ると以下のように書かれており、insert後に[[PDO::lastInsertId:http://php.net/manual/ja/pdo.lastinsertid.php]]を実行して取得していることが分かります。~
#code(php){{{
public function processInsertGetId(Builder $query, $sql, $values, $sequence = null)
{
    $query->getConnection()->insert($sql, $values);

    $id = $query->getConnection()->getPdo()->lastInsertId($sequence);

    return is_numeric($id) ? (int) $id : $id;
}
}}}
ここで気になるのは、別クライアントから同時にアクセス(実行)され、insert(1) - insert(2) - lastInsertId(1) - lastInsertId(2) という順序で処理が走った場合、結果の整合性は補償されるのか? という点です。~
~
そこで、以下のように検証してみました。~
** テストコード [#sdd61fe7]
簡単なテスト用のテーブルを作って(下記ではlog用のテーブルを流用して)繰り返しinsertするコードを書きます。~
これは「php artisan command:test」で実行されるように書きました。
#code(php){{
for($cnt=0;$cnt<10;$cnt++){
    $result = DB::table('logs')->insertGetId([適当な内容]);
    echo $result."\n";
}
}}

** 呼び出すバッチファイル [#z9c5b0f7]
test.bat
#code(){{{
start cmd /c sub.bat
start cmd /c sub.bat
start cmd /c sub.bat
start cmd /c sub.bat
start cmd /c sub.bat
start cmd /c sub.bat
start cmd /c sub.bat
start cmd /c sub.bat
start cmd /c sub.bat
start cmd /c sub.bat
}}}
~
sub.bat
#code(){{{
php artisan command:test
pause
}}}

** 検証 [#u67c9d02]
仮に上記のような順序で実行され、「lastInsertId(1) - lastInsertId(2)」のように連続でlastInsertId()が走るのであれば、同じ番号が返ってくるケースが生じることになります。~
test.batを実行すると10個のDOS窓が同時に開き、各々で同時並行的に10回ずつinsertが走ることになりますが、各窓に表示される数字が全て重複していなければ、概ね問題無いと考えられます。~
~
果たして結果は、全てuniqueな値が100個返ってきました。~
中身はtransactionになってるんでしょうかね(ちゃんと読んでない・・・)。~