JavaでMySQLのデータベースにトランザクション処理

2015.12.16

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

前回の「JavaからMySQLに接続して登録する」ではSQL文を1つ1つコミットしていましたが、今回は複数のSQL文の登録とトランザクション処理を紹介します。 トランザクション処理を行うと、複数のSQL文の内の1つ以上でエラーが発生した場合に、その全ての処理を無かった事にしてくれます。

テーブル

こちらに登録します。

20151215_blog_sql_describe

コード

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class ConnectionClass {

    static final String URL = "jdbc:mysql://localhost/cm";
    static final String USERNAME = "user";
    static final String PASSWORD = "pass";
    
    public static void main(String[] args) {
    
        String sql = "INSERT INTO music VALUES (?, ?, ?, ?);";
        
        String[][] list = {
            {"1", "Sam Smith",    "Stay With Me",          "2015"},
            {"2", "Kanye West",   "Gold Digger",           "2005"},
            {"3", "Roni Size",    "It's A Jazz Thing",     "1994"},
            {"4", "Prince",       "Kiss",                  "1988"},
            {"5", "Led Zeppelin", "When The Levee Breaks", "1971"}
        };
        
        try (  Connection connection = DriverManager.getConnection(URL,USERNAME,PASSWORD);
                PreparedStatement statement = connection.prepareStatement(sql); ) {
                
            connection.setAutoCommit(false);
                
            for (int i = 0; i < list.length; i++) {
                
                statement.setInt   (1, Integer.valueOf(list[i][0]));
                statement.setString(2, list[i][1]);
                statement.setString(3, list[i][2]);
                statement.setInt   (4, Integer.valueOf(list[i][3]));
                
                statement.addBatch();
                
                System.out.println(statement.toString());
                
            }
            
            int[] result = statement.executeBatch();
            System.out.println("登録:" + result.length + "件");
                
            try {
                    
                connection.commit();
                System.out.println("登録成功");
                    
            } catch (SQLException e) {
                
                connection.rollback();
                System.out.println("登録失敗:ロールバック実行");
                    
                e.printStackTrace();
                    
            }
                
        } catch (SQLException e) {
                
            e.printStackTrace();

        }
    
    }

}

解説

動的に実行するためのSQL文を定義。
値を当てはめる箇所を "?" と記述します。

String sql = "INSERT INTO music VALUES (?, ?, ?, ?);";

SQL文に当てはめる値の配列。

        String[][] list = {
            {"1", "Sam Smith",    "Stay With Me",          "2015"},
            {"2", "Kanye West",   "Gold Digger",           "2005"},
            {"3", "Roni Size",    "It's A Jazz Thing",     "1994"},
            {"4", "Prince",       "Kiss",                  "1988"},
            {"5", "Led Zeppelin", "When The Levee Breaks", "1971"}
        };

SQL文をデータベースに送るオブジェクトを生成。
Statement と違い、ここで仮のSQL文も設定します。

PreparedStatement statement = connection.prepareStatement(sql); ) {

トランザクション処理には複数のSQL文をまとめてコミットを行う必要が有るので、自動コミット機能をオフにします。

connection.setAutoCommit(false);

配列の要素をSQL文に設定します。
setInt() で整数、 setString() で文字列に置き換えられます。
第1引数:”?”の何個目か
第2引数:置き換える値

                statement.setInt   (1, Integer.valueOf(list[i][0]));
                statement.setString(2, list[i][1]);
                statement.setString(3, list[i][2]);
                statement.setInt   (4, Integer.valueOf(list[i][3]));

addBatch() でSQL文をバッチ登録。
確認のために statement.toString() でSQL文などを標準出力します。

                statement.addBatch();

                System.out.println(statement.toString());

バッチ登録した複数のSQL文をバッチ処理します。 その返り値は int型 の配列で、更新した回数が要素数になります。

int[] result = statement.executeBatch();

データベースに登録します。

connection.commit();

データベースの登録でエラーが発生したらロールバック処理ですべての変更を取り消します。

connection.rollback();

標準出力結果

com.mysql.jdbc.JDBC4PreparedStatement@22d8cfe0: INSERT INTO music VALUES (1, 'Sam Smith', 'Stay With Me', 2015);
com.mysql.jdbc.JDBC4PreparedStatement@22d8cfe0: INSERT INTO music VALUES (2, 'Kanye West', 'Gold Digger', 2005);
com.mysql.jdbc.JDBC4PreparedStatement@22d8cfe0: INSERT INTO music VALUES (3, 'Roni Size', 'It\'s A Jazz Thing', 1994);
com.mysql.jdbc.JDBC4PreparedStatement@22d8cfe0: INSERT INTO music VALUES (4, 'Prince', 'Kiss', 1988);
com.mysql.jdbc.JDBC4PreparedStatement@22d8cfe0: INSERT INTO music VALUES (5, 'Led Zeppelin', 'When The Levee Breaks', 1971);
登録:5件
登録成功

データベースの状態

20151216_blog_sql_music

まとめ

PreparedStatement を使う事は便利なだけではなくSQLインジェクション対策になるので、Statement よりこちらを使う方が良いです。