2009-06-08 28 views
6

Tôi muốn sử dụng báo cáo đã chuẩn bị, cho many reasons. Nhưng, tôi muốn tạo ra một phương pháp mà trông như thế này:Tại sao tôi cần kết nối để tạo PreparedStatements?

/* This opens a connection, executes the query, and closes the connection */ 
public static void executeNonQuery(String queryString); 

Nói cách khác, tôi muốn logic ứng dụng của mình tới chỉ phải xây dựng các truy vấn và thức ăn trong các thông số, nhưng không phải đối phó với các kết nối & báo cáo . Tuy nhiên, PreparedStatements được tạo ra từ một đối tượng kết nối, vì vậy tôi hiện đang buộc phải chuẩn bị chuỗi truy vấn bằng cách sử dụng String.format() - butt xấu xí và nguy hiểm.

Có cách nào để làm những gì tôi muốn mà không cần sử dụng String.format() không?

+0

Phương thức executeNonQuery của bạn có một vấn đề: nhận kết nối. Nếu bạn tạo một lần mỗi khi phương thức này được thực thi, bạn sẽ gặp phải nhiều vấn đề về hiệu suất thực hiện nhiều lần (việc tạo và đóng kết nối là tốn kém). Nếu điều này được đóng gói trên đối tượng chỉ tạo kết nối trên cuộc gọi đầu tiên, bạn sẽ gặp sự cố: khi nào cần đóng kết nối? Có lẽ dựa trên thời gian? Nếu bạn sử dụng các trường tĩnh vào bộ nhớ cache, hãy cẩn thận việc này sẽ không được thu thập. Hãy coi chừng các cuộc gọi đồng thời, khi lưu vào bộ nhớ đệm một kết nối, mặc dù: không có cơ chế khóa (chẳng hạn như được đồng bộ hóa), bạn có thể tạo nhiều kết nối. –

Trả lời

14

Tại sao tôi cần kết nối để tạo PreparedStatements?

Bởi vì các câu lệnh được chuẩn bị trên cơ sở mỗi kết nối trong hầu hết các số RDBMS.

Báo cáo được chuẩn bị thực tế được lưu trong bộ nhớ cache kế hoạch không đưa bạn quyền, mã hóa, cài đặt đối chiếu, v.v.

Tất cả điều này được thực hiện trong khi phân tích cú pháp truy vấn.

Có cách nào để làm những gì tôi muốn mà không sử dụng String.format()

Bạn không thấy lý do tại sao bạn cần String.format() đây.

Bạn có thể thực hiện truy vấn của mình dưới dạng một lớp, tạo kết nối và chuẩn bị truy vấn trong hàm tạo lớp và sau đó thực thi nó trong một phương thức.

Một truy vấn parametrized thường trông như thế này:

SELECT * 
FROM table 
WHERE col1 = ? 
     AND col2 = ? 

, nơi mà các thông số ràng buộc sẽ được thay thế cho ? 's trong thực hiện truy vấn.

Nếu bạn muốn có một phương pháp static:

  • Tạo một tay cầm static kết nối.
  • Tạo bảng băm static truy vấn được chuẩn bị bằng văn bản truy vấn được tham số dưới dạng key và tay cầm cho truy vấn đã chuẩn bị dưới dạng value.
  • Bất cứ khi nào bạn muốn thực hiện truy vấn, hãy tìm xử lý của nó (hoặc tạo nó nếu không tìm thấy) và sử dụng để liên kết các tham số và thực hiện truy vấn.
1

Tại sao không có logic "ứng dụng" của bạn sử dụng lớp dữ liệu mà bạn tạo có thể trình bày loại phương thức giao diện đó?

Lớp dữ liệu của bạn sau đó có thể xử lý việc tạo kết nối, chuẩn bị câu lệnh, v.v., tất cả trong phương thức executeNonQuery đó.

Tôi nghĩ rằng nếu bạn đang cố gắng hợp nhất các tham số trong truy vấn/tuyên bố của mình thành một Chuỗi, thì bạn sẽ tự chụp chân và thực sự không sử dụng chức năng tham số của PreparedStatements. Bạn không chắc chắn lý do tại sao bạn muốn làm điều này. Bạn cũng có thể muốn xem xét sử dụng một API như Spring, trong đó có một loạt các lớp học JdbcTemplate có thể trừu tượng tất cả các kết nối xử lý ra khỏi bạn, nhưng vẫn cho phép bạn làm việc với các tham số trong một Map.

0

Tôi tóm tắt tất cả các công cụ JDBC bằng cách có lớp tôi gọi QueryRunner có phương thức thực thi lấy sql, Danh sách đối tượng đại diện cho tham số và đối tượng sẽ xử lý ResultSet. Nếu bạn sử dụng phương thức setObject từ JDBC để thiết lập các tham số của bạn, nó sẽ tìm ra các kiểu DB thích hợp để sử dụng dựa trên đối tượng bên dưới. Đây là một phần của mã của tôi. Tôi đã có một phương pháp kết thúc tốt đẹp này và nhận được kết nối.

public void executeNoCommit(Connection conn, 
          String sql, 
          List params, 
          ResultSetProcessor processor) throws SQLException { 
    PreparedStatement stmt = null; 
    ResultSet rs = null; 
    int updateCount = 0; 
    Iterator it; 
    int paramIndex = 1; 
    boolean query; 

    try { 
     stmt = conn.prepareStatement(sql); 

     if (params != null) { 
      it = params.iterator(); 
      while (it.hasNext()) { 
       stmt.setObject(paramIndex, it.next()); 
       paramIndex++; 
      } 
     } 

     query = stmt.execute(); 
     if (query) { 
      rs = stmt.getResultSet(); 
     } 
     else { 
      updateCount = stmt.getUpdateCount(); 
     } 

     processor.process(rs, updateCount); 
    } 
    finally { 
     if (rs != null) { 
      try { 
       rs.close(); 
      } 
      catch (SQLException e) { 
       log.error(e); 
      } 
     } 

     if (stmt != null) { 
      try { 
       stmt.close(); 
      } 
      catch (SQLException e) { 
       log.error(e); 
      } 
     } 
    } 
} 
+0

Bạn có thể đăng mã không? – ripper234

0

Bạn có thể muốn một cái gì đó giống như gói DbUtils trong các thư viện Apache Commons: [http://commons.apache.org/dbutils/index.html][1]

Lớp QueryRunner cho phép bạn thực hiện câu lệnh SQL mà không cần phải tự tạo PreparedStatements, hoặc thậm chí có một kết nối mở cho điều đó vấn đề. Từ trang ví dụ:

QueryRunner run = new QueryRunner(dataSource); 
try 
{ 
    // Create an object array to hold the values to insert 
    Object[] insertParams = {"John Doe", new Double(1.82)}; 
    // Execute the SQL update statement and return the number of 
    // inserts that were made 
    int inserts = run.update("INSERT INTO Person (name,height) VALUES (?,?)", 
           insertParams); 

    // Now it's time to rise to the occation... 
    Object[] updateParams = {new Double(2.05), "John Doe"}; 
    int updates = run.update("UPDATE Person SET height=? WHERE name=?", 
           updateParams); 
} 
catch(SQLException sqle) { 
    // Handle it 
} 

Vì vậy, về cơ bản, xử lý các câu lệnh được chuẩn bị một cách minh bạch và điều duy nhất bạn thực sự cần biết là Nguồn dữ liệu. Điều này cũng hoạt động tốt cho các câu lệnh không update/insert, tức là các truy vấn chọn plain-vanilla, và khả năng tạo ResultSetHandlers cung cấp cho bạn sức mạnh để chuyển đổi một ResultSet thành một cái gì đó giống như một bean được chuẩn bị đầy đủ hoặc một Map với các khóa là các tên cột và các giá trị là các giá trị hàng thực tế. Rất hữu ích khi bạn không thể thực hiện một giải pháp ORM toàn bộ.

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