HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

AutoCommitの動作を誤解していた訳

以下の続き。

そもそもJDBCでは、トランザクション処理を書くときに、次のいずれかの書き方をすることになる:

// TODO エラー処理
Connection connection = DriverManager.getConnection(url, userId, password);
connection.setAutoCommit(false);
// いろんな処理
connection.commit(); // or connection.rollback();
connection.setAutoCommit(true);
// 2011/04/10 MySQLで実行しようとしたら、「java.sql.SQLException: Can't call commit when autocommit=true」とか言われたらしい。
// そういうわけで、トランザクション開始時には「connection.setAutoCommit(false)」を使わざるを得ないらしい。
// // TODO エラー処理
// Connection connection = DriverManager.getConnection(url, userId, password);
// PreparedStatement pstmt = connection.prepareStatement("START TRANSACTION");
// pstmt.executeUpdate();
// pstmt.close();
// // いろんな処理
// connection.commit(); // or connection.rollback();

が、自分は前者の書き方をしていた。そのため、setAutoCommitの結果が後々にまで影響を与えるという認識が抜け切っていたらしい(謎)。トランザクションを開始するためのメソッドがConnectionクラスにあってもよさそうなものだが‥


と、それだけだとアレなので(謎)、一応、前回のPHPでのテストと同じことをJDBCでやってみる。結果は見えているけれども。
テストに用いたのは次のプログラム。

前提とするテーブルは次のとおり。

-- tid はトランザクションID
CREATE TABLE hoge(title VARCHAR(32) NOT NULL, tid VARCHAR(32) NOT NULL)

詳細は省略するが、やっていることは基本的に前回と同じ。ただし、トランザクション制御関連の部分がちょっと違う。

  • 「START TRANSACTION」を発行しない代わりに、必ず「connection.setAutoCommit(false)」を呼ぶ。
  • トランザクションのコミット/ロールバックの直後に、「connection.setAutoCommit(true)」を呼ぶケースと呼ばないケースを実施。

表にするとこんな感じ。

Case 1 Case 2 Case 3 Case 4
setAutoCommit(false)
INSERT(111) (*1)
COMMIT
ROLLBACK
setAutoCommit(true)
INSERT(222) (*1)
  • (*1)カッコ内の数値はtitle列の値

そして実行結果。

DriverVersion           : 5.1
DatabaseProductName     : MySQL
DatabaseProductVersion  : 5.1.32-community
DatabaseProduct         : MySQL 5.1.32-community
=== AUTOCOMMIT: true ===
=== SELECT title, tid FROM hoge WHERE tid = ? (AAA) ===
| [title]           (VARCHAR   ) | [tid]             (VARCHAR   ) |
| 111        (java.lang.String ) | AAA        (java.lang.String ) |
| 222        (java.lang.String ) | AAA        (java.lang.String ) |
=== SELECT title, tid FROM hoge WHERE tid = ? (AAA) ===
| [title]           (VARCHAR   ) | [tid]             (VARCHAR   ) |
| 111        (java.lang.String ) | AAA        (java.lang.String ) |
DROP TABLE hoge: 0
=== AUTOCOMMIT: true ===
=== SELECT title, tid FROM hoge WHERE tid = ? (BBB) ===
| [title]           (VARCHAR   ) | [tid]             (VARCHAR   ) |
| 222        (java.lang.String ) | BBB        (java.lang.String ) |
=== SELECT title, tid FROM hoge WHERE tid = ? (BBB) ===
| [title]           (VARCHAR   ) | [tid]             (VARCHAR   ) |
DROP TABLE hoge: 0
=== AUTOCOMMIT: true ===
=== SELECT title, tid FROM hoge WHERE tid = ? (CCC) ===
| [title]           (VARCHAR   ) | [tid]             (VARCHAR   ) |
| 111        (java.lang.String ) | CCC        (java.lang.String ) |
| 222        (java.lang.String ) | CCC        (java.lang.String ) |
=== SELECT title, tid FROM hoge WHERE tid = ? (CCC) ===
| [title]           (VARCHAR   ) | [tid]             (VARCHAR   ) |
| 111        (java.lang.String ) | CCC        (java.lang.String ) |
| 222        (java.lang.String ) | CCC        (java.lang.String ) |
DROP TABLE hoge: 0
=== AUTOCOMMIT: true ===
=== SELECT title, tid FROM hoge WHERE tid = ? (DDD) ===
| [title]           (VARCHAR   ) | [tid]             (VARCHAR   ) |
| 222        (java.lang.String ) | DDD        (java.lang.String ) |
=== SELECT title, tid FROM hoge WHERE tid = ? (DDD) ===
| [title]           (VARCHAR   ) | [tid]             (VARCHAR   ) |
| 222        (java.lang.String ) | DDD        (java.lang.String ) |
DROP TABLE hoge: 0

それぞれ、1つ目のSELECT文はINSERT文と同じコネクション内での実行、2つ目のSELECT文は別のコネクションでの実行。結果については、分かりきっているのであえて何も言わない(謎)。