it-roy-ru.com

PreparedStatement: Как вставить данные в несколько таблиц с помощью JDBC

Может ли кто-нибудь сказать мне, требуется ли первая stmt.close(); в следующем коде JDBC для выполнения двух разных SQL-запросов к двум разным таблицам?

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

Это распространенное заблуждение с заявлениями, что закрытие их освобождает все, что их готовит. Это не верно. Оптимизация, которая приводит к подготовке выписки, выполняется базой данных. Затем он сохраняется/кэшируется базой данных и обычно используется в следующий раз при подготовке оператора.

В результате подготовленные операторы могут быть закрыты и подготовлены так часто, как вы пожелаете - база данных распознает это же заявление в следующий раз и восстановит подготовленные в кэше приготовления, которые она сделала в прошлый раз - если пожелает.

В итоге - да , заявления должны быть закрыты - и нет , это не делает не снижает эффективность ваших запросов.

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);
 }

Используя приведенный выше код, я мог вставить данные в несколько таблиц с помощью одной кнопки. Pst.execute необходимо вставить в оба запроса; если нет, запрос с pst.execute является таблицей, которая получит данные.

1
Ivan Nieves

Это не обязательно, но рекомендуется. http://docs.Oracle.com/javase/7/docs/api/Java/sql/Statement.html#close ()

Следующая строка после первой close() в вашем коде назначает новое значение для ссылки stmt, поэтому объект, который вы используете для выполнения первой вставки, будет GC'd и в конечном итоге будет закрыт. Хорошей практикой будет идти вперед и закрывать его, когда вы знаете, что с ним покончено. Это немедленно освобождает ресурсы JDBC.

1
Mike B

Рекомендуется закрывать дескриптор Statement, поскольку он высвобождает ресурсы JDBC и базы данных. Вы можете прочитать больше о stmt.close () здесь

Я хотел бы отметить, что хорошо закрывать ваш объект Statement в блоке finally, чтобы ресурсы БД высвобождались даже в случае возникновения исключения.

1
Kakarot

Да, оба метода stmt.close () необходимы ... Вы всегда должны явно закрывать объект Statement или PreparedStatement, чтобы обеспечить надлежащую очистку.

1
Sarah