2010-01-19 59 views
6

Tôi đang cố gắng đi qua từng hàng của bảng trong MySQL bằng Spring và JdbcTemplate. Nếu tôi không nhầm điều này phải đơn giản như:Cách quản lý tập dữ liệu lớn bằng cách sử dụng Spring MySQL và RowCallbackHandler

JdbcTemplate template = new JdbcTemplate(datasource); 
template.setFetchSize(1); 
// template.setFetchSize(Integer.MIN_VALUE) does not work either    
template.query("SELECT * FROM cdr", new RowCallbackHandler() { 
    public void processRow(ResultSet rs) throws SQLException { 
    System.out.println(rs.getString("src")); 
    } 
}); 

Tôi nhận được lỗi OutOfMemoryError vì nó đang cố đọc toàn bộ. Bất kỳ ý tưởng?

+0

Hey, chăm sóc để thay đổi câu trả lời chấp nhận. Câu hỏi của bạn là về mùa xuân và câu trả lời của @ scompt.com là phù hợp hơn. Cảm ơn nhiều. – Gray

Trả lời

9

Các Statement#setFetchSize()javadoc đã khẳng định:

Cung cấp cho các trình điều khiển JDBC một gợi ý như số lượng hàng cần được lấy từ cơ sở dữ liệu

Trình điều khiển thực sự miễn phí để áp dụng hoặc bỏ qua gợi ý. Một số trình điều khiển bỏ qua nó, một số trình điều khiển áp dụng nó trực tiếp, một số trình điều khiển cần thêm thông số. Trình điều khiển JDBC MySQL nằm trong thể loại cuối cùng. Nếu bạn đánh dấu vào MySQL JDBC driver documentation, bạn sẽ thấy các thông tin sau (di chuyển về 2/3 xuống cho đến khi tiêu đề ResultSet):

Để kích hoạt chức năng này, bạn cần phải tạo một đối tượng Statement trong những điều sau đây cách:

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY); 
stmt.setFetchSize(Integer.MIN_VALUE); 

Hãy đọc toàn bộ phần của tài liệu, nó mô tả những hãy cẩn thận của phương pháp này là tốt.

Để làm cho nó hoạt động trong Spring, tuy nhiên bạn sẽ cần phải mở rộng/ghi đè lên JdbcTemplate với triển khai tùy chỉnh. Như tôi không làm mùa xuân tôi không thể đi vào chi tiết về điều này, nhưng bây giờ bạn ít nhất biết nơi để tìm.

Chúc may mắn.

+2

Tôi đã thêm một giải pháp dựa trên Spring tại đây: http://stackoverflow.com/questions/2095490/how-to-manage-a-large-dataset-using-spring- mysql-and-rowcallbackhandler/2834590 # 2834590 –

0

Nếu bạn nghi ngờ bạn đang gặp lỗi OutOfMemory do toàn bộ bảng đã đọc, tại sao bạn không thử tách truy vấn của mình. Sử dụng bộ lọc, LIMIT khoản, vv

+1

Điều đó sẽ làm cho logic của quá trình phức tạp hơn nhiều. Bây giờ tôi đang thử nghiệm một cách để thực sự phát trực tuyến qua Spring JdbcTeamplate. Sẽ cho bạn biết nếu nó hoạt động ... – rmarimon

18

Đây là giải pháp Mùa xuân dựa trên số answer do BalusC cung cấp.

class StreamingStatementCreator implements PreparedStatementCreator { 
    private final String sql; 

    public StreamingStatementCreator(String sql) { 
     this.sql = sql; 
    } 

    @Override 
    public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { 
     final PreparedStatement statement = connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); 
     statement.setFetchSize(Integer.MIN_VALUE); 
     return statement; 
    } 
} 

Một nơi nào đó trong mã của bạn:

DataSource dataSource = ...; 
RowCallbackHandler rowHandler = ...; 
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 
jdbcTemplate.query(new StreamingStatementCreator("SELECT * FROM huge_table"), rowHandler); 
+1

đáng chú ý là bạn cần đảm bảo rằng thuộc tính useServerPrepStmts trong chuỗi kết nối của bạn được đặt đúng, tức là nếu có cơ hội nào được đặt thành false^^ sẽ không hoạt động và nó sẽ lưu lại kết quả đầy đủ Thiết lập –

+0

Điều đáng chú ý là với Spring 3, setFetchSize của JdbcTemplate bỏ qua các giới hạn nhỏ hơn 1 và vì vậy bạn phải ghi đè lên một tính năng rất cơ bản. Kinh quá. –

+0

@AndrewGilmartin Sau 4.3, nên làm việc- Lưu ý: Kể từ 4.3, các giá trị âm khác -1 sẽ được chuyển cho người lái xe, ví dụ: MySQL hỗ trợ hành vi đặc biệt cho Integer.MIN_VALUE. – Hlex

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