web-dev-qa-db-ja.com

PreparedStatement:JDBCを使用して複数のテーブルにデータを挿入する方法

2つの異なるテーブルに対して2つの異なるSQLクエリを実行するために、次のJDBCコードで最初のstmt.close();が必要かどうかを誰かに教えてもらえますか?

public class MyService {
    private Connection connection = null;

    public void save(Book book) {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "password"); 

            PreparedStatement stmt = connection.prepareStatement("INSERT INTO PUBLISHER (CODE, PUBLISHER_NAME) VALUES (?, ?)");
            stmt.setString(1, book.getPublisher().getCode());   
            stmt.setString(2, book.getPublisher().getName());           
            stmt.executeUpdate();

            stmt.close(); //1

            stmt = connection.prepareStatement("INSERT INTO BOOK (ISBN, BOOK_NAME, PUBLISHER_CODE) VALUES (?, ?, ?)");
            stmt.setString(1, book.getIsbn());  
            stmt.setString(2, book.getName());
            stmt.setString(3, book.getPublisher().getCode());
            stmt.executeUpdate();

            stmt.close(); //2       
        } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } 
        finally { connection.close(); }         
    }
}
6
skip

私の本では、リークの可能性を回避するために、開いているリソースを閉じることを常にお勧めします。

もう少し現代的な方法は、 try-with-resources を使用することです。

try (Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "password")) {

    try (PreparedStatement stmt = connection.prepareStatement("INSERT INTO PUBLISHER (CODE, PUBLISHER_NAME) VALUES (?, ?)")) {
        stmt.setString(1, book.getPublisher().getCode());   
        stmt.setString(2, book.getPublisher().getName());           
        stmt.executeUpdate();
    }
    // stmt is auto closed here, even if SQLException is thrown

    try (PreparedStatement stmt = connection.prepareStatement("INSERT INTO BOOK (ISBN, BOOK_NAME, PUBLISHER_CODE) VALUES (?, ?, ?)");
        stmt.setString(1, book.getIsbn());  
        stmt.setString(2, book.getName());
        stmt.setString(3, book.getPublisher().getCode());
        stmt.executeUpdate();
    }
    // stmt is auto closed here, even if SQLException is thrown
}
// connection is auto closed here, even if SQLException is thrown
9
beny23

それらを閉じると、それらを準備するすべてのものが解放されるというステートメントの一般的な誤解です。これは間違っています。ステートメントの準備につながる最適化は、データベースによって実行されます。その後、データベースによって保存/キャッシュされ、通常、次にステートメントが準備されるときに再利用されます。

その結果、準備されたステートメントは、必要に応じて何度でも閉じて準備できます。データベースは、次回同じステートメントを認識し、必要に応じて、前回作成したキャッシュされた準備を回復します。

要約すると、yes、ステートメントを閉じる必要がありますno、これはnotクエリの有効性を低下させます。

4
OldCurmudgeon
 try{
     String insertIntoCust = "insert into NORTHWIND_CUSTOMER(CUSTOMER_ID,FIRST_NAME,LAST_NAME,ADDRESS,CITY,STATE,POSTAL_CODE) values(?,?,?,?,?,?)";
     pst = connect.prepareStatement(insertIntoCust);
     pst.setString(1, txtCustomerId.getText());
     pst.setString(2, txtFirstName.getText());
     pst.setString(3, txtLastName.getText());
     pst.setString(4, txtAddress2.getText());
     pst.setString(5, txtCity.getText());
     pst.setString(6, txtState.getText());
     pst.setString(7, txtPostalCode.getText());

     pst.execute();

     String insertIntoOrder = "insert into NORTHWIND_ORDER(ORDER_ID,ORDER_DATE) values(?,?)";
     pst = connect.prepareStatement(insertIntoOrder);
     pst.setString(1, txtOrderId.getText());
     pst.setString(2, txtOrderDate.getText());

     pst.execute();
     JOptionPane.showMessageDialog(null, "Saved");
 }catch(Exception e){
     JOptionPane.showMessageDialog(null, e);
 }

上記のコードを使用すると、1つのボタンで複数のテーブルにデータを挿入できます。 pst.executeは両方のクエリに挿入する必要があります。そうでない場合、pst.executeを持つクエリは、データを受信するテーブルです。

1
Ivan Nieves

必須ではありませんが、お勧めします。 http://docs.Oracle.com/javase/7/docs/api/Java/sql/Statement.html#close()

コードの最初のclose()の後の次の行は、参照stmtに新しい値を割り当てるため、最初の挿入の実行に使用するオブジェクトはGCされ、最終的に閉じられます。使い終わったことがわかったら、先に進んで閉じることをお勧めします。これにより、JDBCリソースがすぐに解放されます。

1
Mike B

JDBCおよびデータベースリソースを解放するため、ステートメントハンドルを閉じることをお勧めします。 stmt.close()についてもっと読むことができます ここ

例外が発生した場合でもDBリソースが解放されるように、finallyブロックでStatementオブジェクトを閉じるとよいことを指摘しておきます。

1
Kakarot

はい、両方のstmt.close()メソッドが必要です。適切なクリーンアップを確実にするために、StatementまたはPreparedStatementオブジェクトを常に明示的に閉じる必要があります。

1
Sarah