2013-02-27 29 views
9

Theo hiểu biết của tôi, việc sử dụng PreparedStatement trong Java là chúng ta có thể sử dụng nó nhiều lần. Nhưng tôi có một số rắc rối khi sử dụng PreparedStatementCreator của Spring JDBC.Cách thích hợp để sử dụng PreparedStatementCreator của Spring JDBC là gì?

Ví dụ xem xét sau mã,

public class SpringTest { 

    JdbcTemplate jdbcTemplate; 
    PreparedStatementCreator preparedStatementCreator; 
    ResultSetExtractor<String> resultSetExtractor; 

    public SpringTest() throws SQLException { 

     jdbcTemplate = new JdbcTemplate(OracleUtil.getDataSource()); 

     preparedStatementCreator = new PreparedStatementCreator() { 
      String query = "select NAME from TABLE1 where ID=?"; 
      public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { 
       return connection.prepareStatement(query); 
      } 
     }; 

     resultSetExtractor = new ResultSetExtractor<String>() { 
      public String extractData(ResultSet resultSet) throws SQLException, 
      DataAccessException { 
       if (resultSet.next()) { 
        return resultSet.getString(1); 
       } 
       return null; 
      } 
     }; 
    } 
    public String getNameFromId(int id){ 
     return jdbcTemplate.query(preparedStatementCreator, new Table1Setter(id), resultSetExtractor); 
    } 

    private static class Table1Setter implements PreparedStatementSetter{ 

     private int id; 
     public Table1Setter(int id) { 
      this.id =id; 
     } 
     @Override 
     public void setValues(PreparedStatement preparedStatement) throws SQLException { 
      preparedStatement.setInt(1, id); 
     } 
    } 
    public static void main(String[] args) { 
     try { 
      SpringTest springTest = new SpringTest(); 

      for(int i=0;i<10;i++){ 
       System.out.println(springTest.getNameFromId(i)); 
      } 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Theo mã này khi tôi gọi springTest.getNameFromId (int id) phương pháp, nó sẽ trả về tên từ id đưa ra, Ở đây tôi đã sử dụng để tạo PreparedStatementCreator PreparedStatement và PreparedStatementSetter để thiết lập các tham số đầu vào và tôi nhận được kết quả từ ResultSetExtractor. Nhưng hiệu suất rất chậm.

Sau khi gỡ lỗi và nhìn vào những gì xảy ra bên trong PreparedStatementCreator và JdbcTemplate tôi đã biết rằng PreparedStatementCreator tạo mỗi và mỗi lần PreparedStatement mới ... !!!

Mỗi khi tôi gọi phương thức jdbcTemplate.query (PrepareStatementCreator, prepareStatementSetter, resultSetExtractor), nó tạo ra PreparedStatement mới và hiệu suất làm chậm chậm này.

Đây có phải là cách phù hợp để sử dụng PreparedStatementCreator không? Bởi vì trong đoạn code này tôi không thể tái sử dụng PreparedStatement. Và nếu điều này là đúng cách để sử dụng PreparedStatementCreator hơn làm thế nào để có được lợi ích của khả năng sử dụng lại của PreparedStatement?

Trả lời

2

Báo cáo đã chuẩn bị thường được lưu trong bộ nhớ cache bởi nhóm kết nối cơ bản, do đó bạn không cần phải lo lắng về việc tạo một bảng mới mỗi lần hay không.

Vì vậy, tôi nghĩ rằng việc sử dụng thực sự của bạn là chính xác.

JdbcTemplate đóng tuyên bố sau khi thực hiện nó, vì vậy nếu bạn thực sự muốn sử dụng lại cùng một tuyên bố chuẩn bị bạn có thể ủy nhiệm báo cáo kết quả và đánh chặn các phương pháp chặt chẽ trong tác giả tuyên bố

Ví dụ (không dự thi, chỉ làm ví dụ):

public abstract class ReusablePreparedStatementCreator implements PreparedStatementCreator { 

    private PreparedStatement statement; 

    public PreparedStatement createPreparedStatement(Connection conn) throws SQLException { 
     if (statement != null) 
      return statement; 

     PreparedStatement ps = doPreparedStatement(conn); 

     ProxyFactory pf = new ProxyFactory(ps); 
     MethodInterceptor closeMethodInterceptor = new MethodInterceptor() { 

      @Override 
      public Object invoke(MethodInvocation invocation) throws Throwable { 
       return null; // don't close statement 
      } 
     }; 

     NameMatchMethodPointcutAdvisor closeAdvisor = new NameMatchMethodPointcutAdvisor(); 
     closeAdvisor.setMappedName("close"); 
     closeAdvisor.setAdvice(closeMethodInterceptor); 
     pf.addAdvisor(closeAdvisor); 

     statement = (PreparedStatement) pf.getProxy(); 

     return statement;  
    } 

    public abstract PreparedStatement doPreparedStatement(Connection conn) throws SQLException; 

    public void close() { 
     try { 
      PreparedStatement ps = (PreparedStatement) ((Advised) statement).getTargetSource().getTarget(); 
      ps.close(); 
     } catch (Exception e) { 
      // handle exception 
     } 
    } 

} 
1

Sau khi gỡ lỗi và xem xét những gì xảy ra bên trong PreparedStatementCreator và JdbcTemplate Tôi đã biết rằng PreparedStatementCreator tạo mỗi và mỗi lần PreparedStatement mới ... !!!

Tôi không chắc tại sao điều đó gây sốc vì đó là mã của riêng bạn tạo ra PreparedStatement mới mỗi lần bằng cách gọi connection.prepareStatement(query);. Nếu bạn muốn sử dụng lại cùng một cái, thì bạn không nên tạo một cái mới.

+0

tôi cũng thử với trở về cùng PreparedStatement, sau đó tôi đã nhận lỗi "Closed Connection", và Khi tôi cố gắng sử dụng đối tượng kết nối cùng hơn tôi đã nhận lỗi "Closed Tuyên bố" –

+0

Nếu bạn đang nói về trong mẫu của bạn ở trên, đó là vì bạn đang quản lý giao dịch thích hợp. Với một giao dịch đang diễn ra, mọi thứ sẽ thực thi đối với cùng một kết nối và việc sử dụng lại cùng một câu lệnh không phải là một vấn đề. –

+0

Xin lỗi, typo ở trên ... làm cho rằng "bạn * không * làm quản lý giao dịch thích hợp". –

3

Bạn đang sử dụng đúng cách để sử dụng PreparedStatementCreator.

  1. Trong mỗi giao dịch mới, bạn nên tạo thương hiệu mới PreparedStatement dụ, nó chắc chắn đúng. PreparedStatementCreator được thiết kế chủ yếu để bọc các khối mã để tạo PreparedStatement dụ một cách dễ dàng, không nói rằng bạn nên resue các trường hợp mới mỗi itme.
  2. PreparedStatement được thiết kế chủ yếu để gửi DBMS câu lệnh SQL được lập trình sẵn và được biên dịch trước để tiết kiệm thời gian thực hiện SQL.

Để tóm tắt, những gì bạn đã làm là chính xác. sử dụng PreparedStatement sẽ có hiệu suất tốt hơn Tuyên bố.

Các vấn đề liên quan