PreparedStatement:如何使用JDBC将数据插入多个表

时间:2014-02-24 22:54:46

标签: java sql jdbc prepared-statement

有人可以告诉我,以下JDBC代码中是否需要第一个stmt.close();,用于针对两个不同的表执行两个不同的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 个答案:

答案 0 :(得分:10)

在我的书中,我总是建议关闭已经打开的资源以避免可能的泄漏。

稍微更现代的方法是使用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

答案 1 :(得分:4)

这是一个常见的误解,声明关闭它们会释放所有准备它们的东西。这是错的。导致语句准备的优化由数据库执行。然后由数据库存储/缓存它,并且通常在下次准备语句时重复使用。

因此,准备好的陈述可以随时关闭和准备 - 数据库将在下次识别相同的陈述并恢复上次制作的缓存准备 - 如果愿意的话。

总结 - ,语句应该关闭 - 会降低查询的效率。

答案 2 :(得分:1)

不是必需的,但建议使用。 http://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html#close()

代码中第一个close()之后的下一行为引用stmt分配一个新值,因此用于执行第一个插入的对象将被GC并最终关闭。当你知道自己已经完成它时,最好先关闭它。这会立即释放JDBC资源。

答案 3 :(得分:1)

关闭Statement句柄的好习惯是它将释放JDBC&数据库资源。您可以阅读有关stmt.close()here

的更多信息

我想指出,最好在finally块中关闭Statement对象,以便即使发生异常也会释放数据库资源。

答案 4 :(得分:1)

是的,两个stmt.close()方法都是必需的。 您应该始终显式关闭Statement或PreparedStatement对象以确保正确清理。

答案 5 :(得分:1)

 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的查询是将接收数据的表。