2010-01-19 83 views
6

我正在嘗試使用Spring和JdbcTemplate遍歷MySQL中每個表的一行。如何使用Spring MySQL和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")); 
    } 
}); 

我得到一個OutOfMemoryError,因爲它試圖讀取整個事情:如果我沒有記錯,因爲這應該是簡單。有任何想法嗎?

+0

嘿,注意改變公認的答案。你的問題是關於春天和@ scompt.com的答案是更合適的。非常感謝。 – Gray 2016-04-09 19:03:45

回答

9

Statement#setFetchSize()javadoc已經指出:

爲JDBC驅動程序提示爲應該從數據庫中獲取的行數

驅動程序實際上可以自由應用或忽略該提示。一些驅動忽略它,一些驅動直接應用它,一些驅動需要更多的參數。 MySQL JDBC驅動程序屬於最後一類。如果您檢查MySQL JDBC driver documentation,你會看到如下信息(滾動2/3左右,直到頭的ResultSet):

要啓用此功能,您需要在下面創建一個Statement實例方式:

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

請閱讀文檔的整個部分,它描述了這種方法的注意事項,以及。

爲了在Spring中使用它,您需要使用自定義實現來擴展/覆蓋JdbcTemplate。因爲我不這樣做春天我不能詳細談論這個,但現在你至少知道在哪裏看。

祝你好運。

+2

我已經在這裏添加了一個基於Spring的解決方案:http://stackoverflow.com/questions/2095490/how-to-manage-a-large-dataset-using-spring- mysql-and-rowcallbackhandler/2834590#2834590 – 2010-05-14 13:48:44

0

如果您懷疑由於整個表讀取而導致出現OutOfMemory錯誤,爲什麼不嘗試拆分查詢。使用過濾器,LIMIT子句等

+1

這會導致該過程的邏輯複雜得多。我現在正在測試一種實際上通過Spring JdbcTeamplate進行流式處理的方法。會讓你知道它是否工作... – rmarimon 2010-01-19 20:13:44

18

以下是基於BalusC提供的answer的Spring解決方案。

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; 
    } 
} 

某處在您的代碼:

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

值得注意的是,您需要確保您的連接字符串中的useServerPrepStmts屬性設置正確,即,如果有任何機會將此設置爲false,^^將無法工作,並且會緩存完整結果設置 – 2014-10-16 19:22:10

+0

值得注意的是,對於Spring 3,JdbcTemplate的setFetchSize忽略小於1的限制,因此您必須重寫一個非常基本的功能。呸。 – 2015-01-29 13:13:16

+0

@AndrewGilmartin 4.3之後,應該工作- 注:截至4。在圖3中,除-1之外的負值將傳遞給駕駛員,因爲例如, MySQL支持Integer.MIN_VALUE的特殊行爲。 – Hlex 2017-03-26 08:12:11