導語:
有些時候我們所需要查詢的數據量比較大,但是jvm內存又是有限制的,數據量過大會導致內存溢出。這個時候就可以使用流式查詢,數據一條條的返回,處理完一條在拿下一條數據,這樣每次在內存里面的數據其實很小,不會導致內存溢出。
本文里面會講到jdbc的流式查詢和mybatis的流式查詢。
jdbc流式查詢:
jdbc的流式查詢需要在生成PreparedStatement的時候設置三個參數。如下:
1
2
|
PreparedStatement stmt = jdbcTemplate.getDataSource().getConnection().prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); stmt.setFetchSize(Integer.MIN_VALUE); |
主要使用到的是java.sql.Connection的prepareStatement方法。
1
|
PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException; |
resultSetType和resultSetConcurrency我們要分別設置為ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY。
還有就是fetchSize設置為Integer.MIN_VALUE,一開始比較疑惑為啥是這個值。后來發現代碼里面對這個值其實是有特殊處理的。
這個是com.mysql.cj.jdbc.StatementImpl的setFetchSize方法。
1
2
3
4
5
6
7
8
9
10
|
@Override public void setFetchSize( int rows) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { if (((rows < 0 ) && (rows != Integer.MIN_VALUE)) || (( this .maxRows > 0 ) && (rows > this .getMaxRows()))) { throw SQLError.createSQLException(Messages.getString( "Statement.7" ), MysqlErrorNumbers.SQL_STATE_ILLcom.mysql.cj.jdbc.StatementImpl的方法EGAL_ARGUMENT, getExceptionInterceptor()); } this .query.setResultFetchSize(rows); } } |
resultSetType,有以下三種
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/** * The constant indicating the type for a <code>ResultSet</code> object * whose cursor may move only forward. * @since 1.2 */ int TYPE_FORWARD_ONLY = 1003 ; /** * The constant indicating the type for a <code>ResultSet</code> object * that is scrollable but generally not sensitive to changes to the data * that underlies the <code>ResultSet</code>. * @since 1.2 */ int TYPE_SCROLL_INSENSITIVE = 1004 ; /** * The constant indicating the type for a <code>ResultSet</code> object * that is scrollable and generally sensitive to changes to the data * that underlies the <code>ResultSet</code>. * @since 1.2 */ int TYPE_SCROLL_SENSITIVE = 1005 ; |
1
2
|
stmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); stmt.setFetchSize(Integer.MIN_VALUE); |
resultSetConcurrency有以下兩種,流式查詢要設置為只讀的,數據不會被更新。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/** * The constant indicating the concurrency mode for a * <code>ResultSet</code> object that may NOT be updated. * @since 1.2 */ int CONCUR_READ_ONLY = 1007 ; /** * The constant indicating the concurrency mode for a * <code>ResultSet</code> object that may be updated. * @since 1.2 */ int CONCUR_UPDATABLE = 1008 ; |
mybatis流式查詢:
mapper中的代碼:
1
2
3
4
|
@Select ( "select * from xxx order by xx desc" ) @Options (resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = Integer.MIN_VALUE) @ResultType (XxxObject. class ) void queryStreamResult(ResultHandler<XxxObject> handler); |
在查詢方法上加入注解@Options和@ResultType。設置參數不用多說和上面jdbc的底層是一樣的,參數值也一樣。
只不過設置了@ResultType告訴程序應該要返回什么類型的對象。還有這個ResultHandler其實就是Consumer的函數式接口用來處理每一條返回的數據。
具體方法中的代碼:
1
2
3
4
5
6
7
|
@Override public Boolean dealDataList() { mapper.queryStreamResult(resultContext -> { dealSingleData(resultContext.getResultObject().getUid()); }); return true ; } |
這里怎么使用每一條返回的數據只要在resultContext使用ResultObject就可以拿到上面mapper設置的XxxObject對象進行操作了。
到此這篇關于jdbc和mybatis的流式查詢使用方法的文章就介紹到這了,更多相關jdbc和mybatis流式查詢內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://juejin.cn/post/7025246513622155272