3秒でわかる
SQL を 1 文実行するたびに自動で確定させるモード。手軽な代わりに、複数文をまとめて取り消すことができなくなります。
もう少し詳しく
どういうものか
AutoCommit は、SQL 文を 1 つ実行するたびにトランザクションが自動的に確定されるモードです。多くのデータベースクライアントや JDBC の既定値が有効になっており、明示的に COMMIT を書かなくても結果が保存されます。
無効にすると、COMMIT を呼ぶまで変更は確定しません。途中で問題が起きれば ROLLBACK で開始前の状態へまとめて戻せます。
なぜ必要か
有効にしておく利点は、書き忘れによる未確定の変更が残らないことです。SQL を 1 文ずつ試す場面では扱いやすくなります。
問題は、複数の文で 1 つの意味を成す処理です。口座 A から引いて口座 B へ足す送金では、2 文目の直前で失敗するとお金が消えます。AutoCommit が有効だと 1 文目がすでに確定しているため、取り消せません。この「全部成功か全部無かったことにするか」を守るために無効化が必要になります。
性能面の影響もあります。1 万件を 1 件ずつ確定すると、そのたびにディスクへの書き込み確定が発生します。まとめて確定すれば桁違いに速くなります。
具体例
Connection conn = dataSource.getConnection();
try {
conn.<a href="/glossary/setautocommit" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">setAutoCommit</a>(false); // ここから手動
withdraw(conn, fromId, amount);
deposit(conn, toId, amount);
conn.commit(); // 両方成功したら確定
} catch (SQLException e) {
conn.rollback(); // どちらか失敗したら全部戻す
throw e;
} finally {
conn.setAutoCommit(true);
conn.close();
}SQL のクライアントでも切り替えられます。
SET autocommit = 0;
START TRANSACTION;
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE id = 2;
<a href="/glossary/commit" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">COMMIT</a>;つまずきやすいところ
接続プールを使う環境では、setAutoCommit(false) にした接続をそのまま返却する事故が起きます。次にその接続を借りた処理が、確定されないまま進んで原因不明の消失につながります。返す前に元へ戻すか、フレームワークのトランザクション管理に任せます。
DDL の扱いも注意が必要です。MySQL や Oracle では CREATE TABLE などが暗黙的に確定を起こすため、トランザクションの途中に混ぜると手前の変更まで確定します。
無効にしたまま長時間放置するのも問題です。ロックが保持され続け、他の処理が待たされます。
覚え方
「1 文ごとに確定するか、区切りを自分で決めるか」の切り替えスイッチです。