2010-07-02 35 views
14

Làm cách nào để thực thi SQL sau theo cách có thể mở rộng bằng cách sử dụng JdbcTemplate chạy trên mySQL. Trong trường hợp này, có nghĩa là khả năng mở rộng:Chèn nhiều hàng bằng cách sử dụng JdbcTemplate

  1. tuyên bố Chỉ có một SQL được thực thi trên máy chủ
  2. nó hoạt động đối với bất kỳ số lượng hàng.

Đây là tuyên bố:

INSERT INTO myTable (foo, bar) VALUES ("asdf", "asdf"), ("qwer", "qwer") 

Giả sử rằng tôi có một danh sách các POJO với foobar lĩnh vực. Tôi nhận thấy rằng tôi chỉ có thể lặp qua danh sách và thực hiện:

jdbcTemplate.update("INSERT INTO myTable(foo, bar) VALUES (?, ?)", paramMap) 

nhưng điều đó không hoàn thành tiêu chí đầu tiên.

Tôi tin rằng tôi cũng có thể thực hiện:

jdbcTemplate.batchUpdate("INSERT INTO myTable(foo, bar) VALUES (?, ?)", paramMapArray) 

nhưng từ những gì tôi có thể nói, đó chỉ sẽ biên dịch SQL một lần và thực hiện nó nhiều lần, không những tiêu chí hàng đầu nữa.

Khả năng cuối cùng, dường như vượt qua cả hai tiêu chí, sẽ đơn giản là xây dựng bản thân SQL với StringBuffer, nhưng tôi muốn tránh điều đó.

+0

Chúng ta có thể làm như vậy chỉ sử dụng JDBC? ? –

+0

Điều này không liên quan gì đến JdbcTemplate, hoặc thậm chí JDBC. Bạn không thể làm điều này trong SQL, khoảng thời gian (hoặc SQL chuẩn), vì vậy bạn chắc chắn không thể làm điều đó trong JdbcTemplate. – skaffman

+0

@skaffman: Tôi đã cập nhật câu hỏi của mình để nói rằng tôi đang sử dụng mySQL. Có lẽ đó là một tính năng chỉ có mySQL, nhưng nó được mô tả tại http://dev.mysql.com/doc/refman/5.1/en/insert.html khoảng một phần tư chiều xuống: "Các câu lệnh INSERT sử dụng cú pháp VALUES có thể chèn Để thực hiện điều này, bao gồm nhiều danh sách các giá trị cột, mỗi danh sách được đặt trong dấu ngoặc đơn và được phân cách bằng dấu phẩy Ví dụ: " –

Trả lời

4

Chèn multirow (sử dụng "hàm tạo giá trị hàng") thực ra là một phần của tiêu chuẩn SQL-92. Xem http://en.wikipedia.org/wiki/Insert_(SQL)#Multirow_inserts.

Một số cơ sở dữ liệu không hỗ trợ cú pháp này, nhưng nhiều cơ sở thực hiện. Theo kinh nghiệm của tôi Derby/Cloudscape, DB2, Postgresql và phiên bản Hypersonic 2. * + Mới hơn hỗ trợ điều này.

Quan tâm của bạn về việc làm việc này như một PreparedStatement là dễ hiểu, nhưng tôi đã thấy các trường hợp tương tự trong đó Spring JDBC tự động xử lý Bộ sưu tập các mục cho các truy vấn nhất định (như ở đâu (?)), Nhưng tôi không thể xác minh đối với trường hợp này.

Tôi đã tìm thấy một số thông tin hữu ích tại (không thể thêm liên kết thứ hai vào bài đăng này) có thể giúp bạn.

Tôi có thể cho bạn biết rằng không thể yêu cầu thứ hai của bạn (hoạt động cho bất kỳ số đối số nào) theo nghĩa hẹp nhất: mọi cơ sở dữ liệu tôi đã sử dụng sẽ đặt ra giới hạn độ dài truy vấn .

+0

URL mà SO không cho phép tôi đăng ở trên là: http://fusesource.com/docs/router/2.2/transactions/DataAccess-JDBC.html – Will

-4

Bạn không thể làm điều này trong JDBC, thời gian. Trong MySQL nó chỉ là cú pháp cú pháp, nhưng hiệu quả của câu lệnh sẽ giống như việc phát hành một số câu lệnh INSERT. Vì vậy, bạn có thể sử dụng batchUpdate và nó sẽ có tác dụng tương tự.

+1

Không đúng. "Chèn mở rộng" của MySQL (như được trình bày trong Câu hỏi) nhanh hơn chèn hàng loạt (nơi bạn chuẩn bị trước nhưng chèn một hàng tại một thời điểm). Nó không phải là một cú pháp cú pháp trong MySQL. –

28

Bạn có thể sử dụng BatchPreparedStatementSetter như bên dưới.

public void insertListOfPojos(final List<MyPojo> myPojoList) { 

    String sql = "INSERT INTO " 
     + "MY_TABLE " 
     + "(FIELD_1,FIELD_2,FIELD_3) " 
     + "VALUES " + "(?,?,?)"; 

    getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() { 

     @Override 
     public void setValues(PreparedStatement ps, int i) 
      throws SQLException { 

      MyPojo myPojo = myPojoList.get(i); 
      ps.setString(1, myPojo.getField1()); 
      ps.setString(2, myPojo.getField2()); 
      ps.setString(3, myPojo.getField3()); 

     } 

     @Override 
     public int getBatchSize() { 
      return myPojoList.size(); 
     } 
    }); 

} 
+0

Tôi đã có "Chỉ số tham số ngoài phạm vi (1> số của các tham số, là 0) "khi sử dụng: NamedParameters thay vì?. Một số cập nhật để sử dụng với NamedParameterJdbcTemplate? – luso

-1

bạn cũng có thể thử với jdbcInsert.executeBatch (sqlParamSourceArray)

// define parameters 
jdbcInsert = new SimpleJdbcInsert(jdbcTemplate); 
jdbcInsert.withTableName("TABlE_NAME"); 
SqlParameterSource[] sqlParamSourceArray = new SqlParameterSource[apiConsumer 
     .getApiRoleIds().size()]; 
for (int i = 0; i < myCollection.size(); i++) 
    { 
    sqlParamSourceArray[i] = new MapSqlParameterSource().addValue("COL1"); 
     ...................... 
} 
// execute insert 
int[] keys = jdbcInsert.executeBatch(sqlParamSourceArray); 
+0

Câu trả lời này là sai! 'jdbcInsert.executeBatch()' KHÔNG trả về các khóa. Nó trả về 'mảng số hàng bị ảnh hưởng như được trả về bởi trình điều khiển JDBC'. Xem javadocs. https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/simple/SimpleJdbcInsert.html#executeBatch-org.springframework.jdbc.core.namedparam.SqlParameterSource – Stewart

0

Có vẻ với tôi rằng) phương pháp JdbcTemplate batchUpdate (có thể là hữu ích trong trường hợp này (sao chép từ đây):

//insert batch example 
public void insertBatch(final List<Customer> customers){ 

    String sql = "INSERT INTO CUSTOMER " + 
    "(CUST_ID, NAME, AGE) VALUES (?, ?, ?)"; 

    getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() { 

@Override 
public void setValues(PreparedStatement ps, int i) throws SQLException { 
    Customer customer = customers.get(i); 
    ps.setLong(1, customer.getCustId()); 
    ps.setString(2, customer.getName()); 
    ps.setInt(3, customer.getAge()); 
} 

@Override 
public int getBatchSize() { 
    return customers.size(); 
} 

    }); 
} 
Các vấn đề liên quan