一、前言
前面介绍了MyBaits中两种使用游标的方式来避免搜查内容过大导致JVM OOM,这两种方式被称为是客户端side的游标,因为mysql client每次从mysqlserver获取一条记录,这虽然解决了OOM,但是会造成IO网络比较频繁,那么有没有一种方式可以让mysql server一次返回fetchsize个记录那?答案是肯定的。
二、MySQL Server Side Cursor
2.1 使用
要使用MySQL Server Side游标需要满足下面条件:
必须是select语句
设置了fetchSize>0
设置了useCursorFetch=true
数据集类型为ResultSet.TYPE_FORWARD_ONLY
数据集并发设置为ResultSet.CONCUR_READ_ONLY
Server versions 5.0.5 or newer
这是因为代码层面做了下面判断:
// we only create cursor-backed result sets if// a) The query is a SELECT// b) The server supports it// c) We know it is forward-only (note this doesn't preclude updatable result sets)// d) The user has set a fetch sizeif (this.resultFields != null && this.useCursorFetch && getResultSetType() == ResultSet.TYPE_FORWARD_ONLY
&& getResultSetConcurrency() == ResultSet.CONCUR_READ_ONLY && getFetchSize() > 0) {
packet.writeByte(OPEN_CURSOR_FLAG); // usingCursor = true;} else {
packet.writeByte((byte) 0); // placeholder for flags} Server versions 5.0.5 or newer will only open a cursor and set this flag if they can, otherwise they punt and go back to mysql_store_results()// behavior//if (this.connection.versionMeetsMinimum(5, 0, 5)) {
usingCursor = (this.serverStatus & SERVER_STATUS_CURSOR_EXISTS) != 0;
}
2.2 原理简单介绍
服务器边的游标是mysqlclient先从mysqlserver获取fetchSize个记录放到mysqlclient的游标内部的数组里面,游标获取的时候是从数组里面获取数据,如果数组为空了,在向mysql server获取fetchSize个记录。
三、总结对比
服务器边的游标的使用的确可以减少网络IO,但是这是使用占用MySQL服务器资源来实现的,因为服务器这边肯定要做维护每次返回fetchSize的事情,所以并不见的使用服务器端游标比客户端的就好。