$ perl dbic-test.pl
DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::mysql::st execute failed: Lost connection to MySQL server during query [for Statement "SELECT SLEEP(1) FROM user me"] at dbic-test.pl line 80
名前: ok_macopy
所持金: 0
所持金が0円になってしまいました。
SELECT SLEEP(1) FROM user me という時間のかかるクエリを投げたので、コネクションがタイムアウトしてしまったようです。
データベースの状態を確認すると、userに行はあるけど、moneyは空っぽの状態です。
「userに対応するmoneyが必ず存在しなければならない」とスキーマで定義したのに、その条件を満たしていませんね。
たとえタイムアウトしたとしても、このような状態にはならないで欲しいです。
12345678910
mysql> SELECT * FROM user;
+----+-----------+
| id | username |
+----+-----------+
| 1 | ok_macopy |
+----+-----------+
1 row in set (0.00 sec)
mysql> SELECT * FROM money;
Empty set (0.00 sec)
$ perl dbic-test.pl
Transaction aborted: DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::mysql::st execute failed: Lost connection to MySQL server during query [for Statement "SELECT SLEEP(1) FROM user me"] at dbic-test.pl line 80
Rollback failed: DBIx::Class::Storage::DBI::_exec_txn_rollback(): DBI Exception: DBD::mysql::db rollback failed: Turning on AutoCommit failed at dbic-test.pl line 72
DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::mysql::st execute failed: MySQL server has gone away [for Statement "SELECT me.id, me.username FROM user me WHERE ( id = ? )" with ParamValues: 0=1] at dbic-test.pl line 89
# ※「ユーザが見つかりませんでした」と表示されて欲しいがされない
$ perl dbic-test.pl
transaction_depth = 0
transaction_depth = 1
Transaction aborted: DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::mysql::st execute failed: Lost connection to MySQL server during query [for Statement "SELECT SLEEP(1) FROM user me"] at dbic-test.pl line 82
Rollback failed: DBIx::Class::Storage::DBI::_exec_txn_rollback(): DBI Exception: DBD::mysql::db rollback failed: Turning on AutoCommit failed at dbic-test.pl line 73
transaction_depth = 1 # ※トランザクションの外なのに1になってる
DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::mysql::st execute failed: MySQL server has gone away [for Statement "SELECT me.id, me.username FROM user me WHERE ( id = ? )" with ParamValues: 0=1] at dbic-test.pl line 92
$ perl dbic-test.pl
Transaction aborted: DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::mysql::st execute failed: Lost connection to MySQL server during query [for Statement "SELECT SLEEP(1) FROM user me"] at dbic-test.pl line 80
Rollback failed: DBIx::Class::Storage::DBI::_exec_txn_rollback(): DBI Exception: DBD::mysql::db rollback failed: Turning on AutoCommit failed at dbic-test.pl line 72
(in cleanup) {UNKNOWN}: DBI Exception: DBD::mysql::db DESTROY failed: MySQL server has gone away at /home/ichinose/.plenv/versions/5.20.2/lib/perl5/site_perl/5.20.2/DBIx/Class/Schema.pm line 1077.
DBIx::Class::Schema::throw_exception(My::Schema=HASH(0x118d088), "DBI Exception: DBD::mysql::db DESTROY failed: MySQL server ha"...) called at /home/ichinose/.plenv/versions/5.20.2/lib/perl5/site_perl/5.20.2/DBIx/Class/Storage.pm line 113
DBIx::Class::Storage::throw_exception(DBIx::Class::Storage::DBI::mysql=HASH(0x118d718), "DBI Exception: DBD::mysql::db DESTROY failed: MySQL server ha"...) called at /home/ichinose/.plenv/versions/5.20.2/lib/perl5/site_perl/5.20.2/DBIx/Class/Storage/DBI.pm line 1473
DBIx::Class::Storage::DBI::__ANON__("DBD::mysql::db DESTROY failed: MySQL server has gone away", DBI::db=HASH(0x16efbb8), undef) called at dbic-test.pl line 91
eval {...} called at dbic-test.pl line 91
ユーザが見つかりませんでした
$ perl dbic-test.pl
DBIx::Class::Storage::TxnScopeGuard::DESTROY(): A DBIx::Class::Storage::TxnScopeGuard went out of scope without explicit commit or error. Rolling back. at dbic-test.pl line 88
名前: ok_macopy
所持金: 2000
$ perl dbic-test.pl
DBIx::Class::Storage::TxnScopeGuard::DESTROY(): A DBIx::Class::Storage::TxnScopeGuard went out of scope without explicit commit or error. Rolling back. at dbic-test.pl line 90
名前: ok_macopy
所持金: 1000
大人しく全部ロールバックする
MySQLにはSAVE POINTという便利機能があるとはいえ、どこまでロールバックするべきかを管理するのはすごく大変です。
現実的には ALL or NOTHING、失敗したら全部ロールバックで十分なのではと思ってます。
このサンプルではdieしてしまえばいいですね。