2009-11-02 66 views
12

Dự án Java (JDK6) của tôi sử dụng SpringJDBCTemplate cho tất cả quyền truy cập cơ sở dữ liệu của nó. Gần đây chúng tôi đã nâng cấp từ mùa xuân 2.5 lên mùa xuân 3 (RC1). Dự án không sử dụng ORM như Hibernate cũng không phải EJB.Lập trình Java - Spring và JDBCTemplate - Sử dụng truy vấn, queryForList hoặc queryForRowSet?

Nếu tôi cần phải đọc một loạt các hồ sơ, và làm một số xử lý nội bộ với họ, nó có vẻ như có một số phương pháp (quá tải): truy vấn, queryForList và queryForRowSet

gì nên là tiêu chí sử dụng một thay vì khác? Có bất kỳ sự khác biệt về hiệu suất nào không? Thực hành tốt nhất?

Bạn có thể giới thiệu một số tài liệu tham khảo bên ngoài để nghiên cứu thêm về chủ đề này không?

Trả lời

34

Tôi thấy rằng cách tiêu chuẩn để truy cập dưới dạng danh sách là thông qua các phương thức query() thay vì bất kỳ phương pháp nào khác. Sự khác biệt chính giữa query và các phương pháp khác là bạn sẽ phải triển khai một trong các giao diện gọi lại (hoặc RowMapper, RowCallbackHandler hoặc ResultSetExtractor) để xử lý tập hợp kết quả của bạn.

A RowMapper có khả năng là những gì bạn sẽ thấy mình sử dụng phần lớn thời gian. Nó được sử dụng khi mỗi hàng của tập kết quả tương ứng với một đối tượng trong danh sách của bạn. Bạn chỉ phải thực hiện một phương thức mapRow nơi bạn điền loại đối tượng đi vào hàng của bạn và trả về nó. Mùa xuân cũng có một số BeanPropertyRowMapper có thể điền các đối tượng vào danh sách thông qua kết hợp tên thuộc tính bean với tên cột (NB lớp này là để thuận tiện không thực hiện).

A RowCallbackHandler hữu ích hơn khi bạn cần kết quả không chỉ là một danh sách đơn giản. Bạn sẽ phải tự mình quản lý đối tượng trả về bạn đang sử dụng phương pháp này. Tôi thường thấy mình sử dụng điều này khi tôi cần một cấu trúc bản đồ làm kiểu trả về của tôi (tức là cho dữ liệu được nhóm cho một bảng cây hoặc nếu tôi tạo một bộ nhớ cache tùy chỉnh dựa trên khóa chính).

A ResultSetExtractor được sử dụng khi bạn muốn kiểm soát việc lặp lại kết quả. Bạn ngụ ý một phương thức extractData sẽ là giá trị trả về của cuộc gọi đến query. Tôi chỉ thấy mình sử dụng điều này nếu tôi phải xây dựng một số cấu trúc dữ liệu tùy chỉnh phức tạp hơn để xây dựng bằng cách sử dụng một trong hai giao diện gọi lại khác.

Phương thức queryForList() có giá trị trong đó bạn không phải triển khai các phương thức gọi lại này. Có hai cách sử dụng queryForList. Đầu tiên là nếu bạn chỉ truy vấn một cột đơn từ cơ sở dữ liệu (ví dụ danh sách các chuỗi), bạn có thể sử dụng các phiên bản của phương thức lấy Class làm đối số để tự động cung cấp cho bạn danh sách các đối tượng duy nhất của các lớp đó .

Khi gọi các triển khai khác của queryForList() bạn sẽ nhận được danh sách trở lại với mỗi mục nhập là bản đồ cho từng cột. Trong khi điều này là tốt đẹp ở chỗ bạn được lưu các chi phí bằng văn bản các phương pháp gọi lại, giao dịch với cấu trúc dữ liệu này là khá khó sử dụng. Bạn sẽ thấy mình thực hiện rất nhiều thao tác truyền vì giá trị của bản đồ là loại Object.

Tôi chưa bao giờ thấy phương pháp queryForRowSet được sử dụng trong môi trường hoang dã. Điều này sẽ tải toàn bộ kết quả của truy vấn vào một đối tượng CachedRowSet bị Wapped bởi một Spring SqlRowSet. Tôi thấy một nhược điểm lớn trong việc sử dụng đối tượng này ở chỗ nếu bạn đang đi qua các SqlRowSet xung quanh các lớp khác của ứng dụng của bạn, bạn đang ghép nối các lớp đó với việc triển khai truy cập dữ liệu của mình.

Bạn không nên thấy bất kỳ khác biệt hiệu suất lớn nào giữa bất kỳ cuộc gọi nào ngoại trừ như tôi đã đề cập với BeanPropertyRowMapper. Nếu bạn đang làm việc với một số thao tác phức tạp của một tập hợp kết quả lớn, bạn có thể nhận được một số lợi ích hiệu suất từ ​​việc viết một tối ưu hóa ResultSetExtractor cho trường hợp cụ thể của bạn.

Nếu bạn muốn tìm hiểu thêm, tôi sẽ tham khảo Spring JDBC documentationJavaDoc for the classes I've mentioned. Bạn cũng có thể xem một số sách trong Spring Framework. Mặc dù nó có một chút ngày Java Development with the Spring Framework có một phần rất tốt về làm việc với khung công tác JDBC. Hầu hết tất cả, tôi sẽ nói chỉ cần thử viết một số mã với mỗi phương pháp và xem những gì làm việc tốt nhất cho bạn.

3

Kể từ khi bạn đang ở trong đất Generics tuyệt vời, những gì bạn có thể thực sự muốn làm là sử dụng SimpleJdbcTemplate và sử dụng query() phương thức của nó cho Lists của các đối tượng và queryForObject() cho các đối tượng cá nhân. Lý do cho việc này đơn giản là chúng thậm chí còn dễ sử dụng hơn so với những cái trong JdbcTemplate.

+1

AFIK phương pháp truy vấn tương thích Java 5 có sẵn trong JDBCTemplate cũng như trong Spring 3 – Adrian

+1

Bây giờ tôi đã kiểm tra, JdbcTemplate không sử dụng Generics trong Spring 2.5.6 nhưng nó là 3.0.0. Tôi ngửi thấy một sự phản đối trong tương lai ... :) – Esko

+0

SimpleJdbcTemplate hiện không được chấp nhận – Helenesh

2

Một bổ sung nhỏ cho các câu trả lời xuất sắc ở trên: các phương thức bổ sung, như queryForInt, queryForLong, queryForMap, queryForObject, v.v. có vẻ giống như các tùy chọn tốt nếu bạn đang chạy một truy vấn đơn giản và mong đợi một hàng duy nhất.

Tuy nhiên, nếu bạn có thể nhận được 0 hoặc 1 hàng trở lại, phương pháp queryForList nói chung dễ dàng hơn, nếu không bạn sẽ phải bắt IncorrectResultSizeDataAccessException. Tôi đã học một bài học đắt giá.