Every cursor uses temporary resources to hold its data. These resources can be memory, a disk paging file, temporary disk files, or even temporary storage in the database.
The cursor is called a client-side cursor when these resources are located on the client computer.
The cursor is called a server-side cursor when these resources are located on the server.
2020-11-29T14:52:45.255304Z 26 Connect root@localhost on test using TCP/IP 2020-11-29T14:52:45.257730Z 26 Query /* mysql-connector-java-8.0.16 (Revision: 34cbc6bc61f72836e26327537a432d6db7c77de6) */SELECT @@session.auto_increment_increment AS auto_increment_increment, @@character_set_client AS character_set_client, @@character_set_connection AS character_set_connection, @@character_set_results AS character_set_results, @@character_set_server AS character_set_server, @@collation_server AS collation_server, @@collation_connection AS collation_connection, @@init_connect AS init_connect, @@interactive_timeout AS interactive_timeout, @@license AS license, @@lower_case_table_names AS lower_case_table_names, @@max_allowed_packet AS max_allowed_packet, @@net_write_timeout AS net_write_timeout, @@performance_schema AS performance_schema, @@sql_mode AS sql_mode, @@system_time_zone AS system_time_zone, @@time_zone AS time_zone, @@transaction_isolation AS transaction_isolation, @@wait_timeout AS wait_timeout 2020-11-29T14:52:45.275263Z 26 Query SET character_set_results = NULL 2020-11-29T14:52:45.276567Z 26 Query SET autocommit=1 2020-11-29T14:52:45.286060Z 26 Query SET autocommit=0 2020-11-29T14:52:45.320721Z 26 Query select * from words
Server Side Cursor
要使用Server Side Cursor,需要改两个配置,
一个是jdbc的连接参数useCursorFetch
useCursorFetch
If connected to MySQL > 5.0.2, and setFetchSize() > 0 on a statement, should that statement use cursor-based fetching to retrieve rows?
2020-11-29T15:07:33.852536Z 27 Connect root@localhost on test using TCP/IP 2020-11-29T15:07:33.855425Z 27 Query /* mysql-connector-java-8.0.16 (Revision: 34cbc6bc61f72836e26327537a432d6db7c77de6) */SELECT @@session.auto_increment_increment AS auto_increment_increment, @@character_set_client AS character_set_client, @@character_set_connection AS character_set_connection, @@character_set_results AS character_set_results, @@character_set_server AS character_set_server, @@collation_server AS collation_server, @@collation_connection AS collation_connection, @@init_connect AS init_connect, @@interactive_timeout AS interactive_timeout, @@license AS license, @@lower_case_table_names AS lower_case_table_names, @@max_allowed_packet AS max_allowed_packet, @@net_write_timeout AS net_write_timeout, @@performance_schema AS performance_schema, @@sql_mode AS sql_mode, @@system_time_zone AS system_time_zone, @@time_zone AS time_zone, @@transaction_isolation AS transaction_isolation, @@wait_timeout AS wait_timeout 2020-11-29T15:07:33.869299Z 27 Query SET character_set_results = NULL 2020-11-29T15:07:33.870598Z 27 Query SET autocommit=1 2020-11-29T15:07:33.880234Z 27 Query SET autocommit=0 2020-11-29T15:07:33.900411Z 27 Prepare select * from words 2020-11-29T15:07:34.044284Z 27 Close stmt
// org.apache.ibatis.executor.resultset.DefaultResultSetHandler#skipRows privatevoidskipRows(ResultSet rs, RowBounds rowBounds)throws SQLException { if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) { if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) { rs.absolute(rowBounds.getOffset()); } } else { for (int i = 0; i < rowBounds.getOffset(); i++) { if (!rs.next()) { break; } } } }
ResultSet的type是1003,正好是forward only:
1 2 3 4 5 6
/** * 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;
字面上就是只能一次一次往前走,所以offset的数据也得fetch到,然后一条一条的丢弃掉。
这个可以修改statement的声明:
1 2 3
<selectid="selectAll"fetchSize="3"resultSetType="SCROLL_INSENSITIVE"resultType="com.air.mybatis.sqlsession.WordDTO"> select * from words </select>
When creating a Statement, the specification for the resultSetType parameter was not honored, so that the ResultSet type was always set to ResultSet.TYPE_FORWARD_ONLY. With this fix, the resultSetType parameter is now honored. Also, type validation has been added so that calling the methods beforeFirst, afterLast, first, last, absolute, relative, or previous results in an exception if the ResultSet type is ResultSet.TYPE_FORWARD_ONLY. (Bug #30474158)
A table of data representing a database result set, which is usually generated by executing a statement that queries the database.
A ResultSet object maintains a cursor pointing to its current row of data. Initially the cursor is positioned before the first row. The next method moves the cursor to the next row, and because it returns false when there are no more rows in the ResultSet object, it can be used in a while loop to iterate through the result set.
A default ResultSet object is not updatable and has a cursor that moves forward only. Thus, you can iterate through it only once and only from the first row to the last row. It is possible to produce ResultSet objects that are scrollable and/or updatable. The following code fragment, in which con is a valid Connection object, illustrates how to make a result set that is scrollable and insensitive to updates by others, and that is updatable. See ResultSet fields for other options.
1 2 3 4 5 6
Statement stmt = con.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmt.executeQuery("SELECT a, b FROM TABLE2"); // rs will be scrollable, will not show changes made by others, // and will be updatable
ResultSet类型:
分页的三种方式
逻辑分页
Mybatis提供了RowBounds来进行分页:
1 2
物理分页
物理分页是指基于数据库提供的类似 limit offset,rows这样的语法。
但是,比如limit 10000,20, 就会读取10020条数据,但是只会返回后面20条数据。
手工计算
如果id是有序的,可以做一个简单的转换,比如使用 where id between 10000 and 10020, 这样的效率就会相对的高些