官网地址:https://docs.oracle.com/javase/tutorial/jdbc/basics/retrieving.html
一
1 ResultSet Types
主要有两个影响 :1游标是否能灵活的移动 2当数据库有变动时(其他进程修改),ResultSet结果是否会更新
参数有三:
1 TYPE_FORWARD_ONLY(官网让使用ResultSet. TYPE_SCROLL_SENSITIVE调用,实际要ResultSetImpl. TYPE_SCROLL_SENSITIVE)
指针只能后移,即只能调用rs.next(),rs不会及时更新数据库的变得(这是不被支持的)
2 TYPE_SCROLL_INSENSITIVE
指针能任意移动调用next,prviou以及其他method,rs不会及时更新数据库的变得
3 TYPE_SCROLL_SENSITIVE
指针能任意移动调用next,prviou以及其他method,rs会及时更新数据库的变得(在下面的测试代码中,这是不被支持的)
2 ResultSet Concurrency
是否能对rs进行修改(rs并不只是用于读取数据,rs是一个保持链接的数据集,当con被关闭,rs也会失效;所以这种改动可以被持久化到数据库,详见测试代码)
参数有二:
1 CONCUR_READ_ONLY :不能修改
2 CONCUR_UPDATABLE: 能修改
3 Cursor Holdability
当执行了con.commit:执行了事务提交,rs的游标应该保持在原位置,或是回到rs的头部(beforeFirst)
1 HOLD_CURSORS_OVER_COMMIT :保持在原位置
2 CLOSE_CURSORS_AT_COMMIT:回到rs的头部
二
我的测试环境:mysql
不同的数据库官方,对jdbc的实现可能不一致,有些特性不一定是被支持的。所以以下代码只能是mysql。
例如mysql对 ResultType的TYPE_FORWARD_ONLY根本无法调用;
而对ResultType的TYPE_SCROLL_SENSITIVE,查看是false。
我的测试代码:
1 类JdbcT
import com.mysql.jdbc.Connection; import com.mysql.jdbc.DatabaseMetaData; import com.mysql.jdbc.ResultSetImpl; import com.mysql.jdbc.Statement; import org.junit.Test; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; public class JdbcT { @Test public void test() throws ClassNotFoundException, SQLException, SQLException { Class.forName("com.mysql.jdbc.Driver"); Connection con = (Connection) DriverManager.getConnection( "jdbc:mysql://localhost:3306/cesium", "root", "root"); Statement st = (Statement) con.createStatement( ResultSetImpl.TYPE_SCROLL_SENSITIVE, ResultSetImpl.CONCUR_UPDATABLE, ResultSetImpl.CLOSE_CURSORS_AT_COMMIT); ResultSet rs = st.executeQuery("select * from user"); DatabaseMetaData databaseMetaData = (DatabaseMetaData) con.getMetaData(); /* 1 游标是否可以灵活移动,灵敏度,同步db读取后的修改 DatabaseMetaData.supportsResultSetType TYPE_FORWARD_ONLY:游标只能next,不能previous以及其他所有的移动游标method,数据库有改动,不会及时更新 next:将光标向前移动一行。返回true如果光标现位于一行,并false当光标位于最后一行之后。 previous:将光标向后移动一排。返回true如果光标现位于一行,并false当光标位于第一行之前。 first:将光标移动到ResultSet对象的第一行。返回true如果光标现位于第一行上false,如果ResultSet对象不包含任何行。 last::将光标移动到ResultSet对象的最后一行。返回true如果光标现位于最后一排并false如果ResultSet对象不包含任何行。 beforeFirst:将光标置于ResultSet对象的开头,第一行之前。如果ResultSet对象不包含任何行,则此方法无效。 afterLast:将光标置于ResultSet对象的末尾,最后一行之后。如果ResultSet对象不包含任何行,则此方法无效。 relative(int rows):相对于其当前位置移动光标。 absolute(int row):将光标定位在参数指定的行上row。 TYPE_SCROLL_INSENSITIVE: (不敏感的)游标能双向移动,但是获取了rs之后,数据库有改动,不会及时更新 TYPE_SCROLL_SENSITIVE: 游标能双向移动,获取了rs之后,数据库有改动,会及时更新 */ // 没有第一种,应该是不支持 System.out.println("游标可移动不敏感:"+ databaseMetaData.supportsResultSetType(ResultSetImpl.TYPE_SCROLL_INSENSITIVE) ); System.out.println("游标可移动且敏感:"+ databaseMetaData.supportsResultSetType(ResultSetImpl.TYPE_SCROLL_SENSITIVE) ); /* 2 并发:修改rs DatabaseMetaData.supportsResultSetConcurrency CONCUR_READ_ONLY: The ResultSet object cannot be updated using the ResultSet interface. 读取出来的rs,不能后期修改 CONCUR_UPDATABLE: The ResultSet object can be updated using the ResultSet interface. 读取出来的rs,能后期修改 */ System.out.println("游标可移动且敏感,数据不可修改:"+//因为 TYPE_SCROLL_SENSITIVE false databaseMetaData.supportsResultSetConcurrency(ResultSetImpl.TYPE_SCROLL_SENSITIVE, ResultSetImpl.CONCUR_READ_ONLY) ); System.out.println("游标可移动且敏感,数据修改:"+//因为 TYPE_SCROLL_SENSITIVE false databaseMetaData.supportsResultSetConcurrency(ResultSetImpl.TYPE_SCROLL_SENSITIVE, ResultSetImpl.CONCUR_UPDATABLE) ); // System.out.println("游标可移动不敏感,数据不可修改:"+ databaseMetaData.supportsResultSetConcurrency(ResultSetImpl.TYPE_SCROLL_INSENSITIVE, ResultSetImpl.CONCUR_READ_ONLY) ); System.out.println("游标可移动不敏感,数据修改:"+ databaseMetaData.supportsResultSetConcurrency(ResultSetImpl.TYPE_SCROLL_INSENSITIVE, ResultSetImpl.CONCUR_UPDATABLE) ); /* 3 游标持久保留 databaseMetaData.supportsResultSetHoldability HOLD_CURSORS_OVER_COMMIT:事务结束后(Connection.commit),游标位置保留(rs不置null?),可能提高一些性能 CLOSE_CURSORS_AT_COMMIT: */ System.out.println("ResultSet.HOLD_CURSORS_OVER_COMMIT = " + ResultSetImpl.HOLD_CURSORS_OVER_COMMIT); System.out.println("ResultSet.CLOSE_CURSORS_AT_COMMIT = " + ResultSetImpl.CLOSE_CURSORS_AT_COMMIT); System.out.println("Default cursor holdability: " + databaseMetaData.getResultSetHoldability()); System.out.println("游标保留:"+ databaseMetaData.supportsResultSetHoldability(ResultSetImpl. HOLD_CURSORS_OVER_COMMIT) ); System.out.println("游标不保留:"+ databaseMetaData.supportsResultSetHoldability(ResultSetImpl. CLOSE_CURSORS_AT_COMMIT) ); } }
2 类JdbcT2 import com.mysql.jdbc.Connection; import com.mysql.jdbc.DatabaseMetaData; import com.mysql.jdbc.ResultSetImpl; import com.mysql.jdbc.Statement; import org.junit.Test; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; public class JdbcT2 { @Test public void test1() throws ClassNotFoundException, SQLException, InterruptedException { Class.forName("com.mysql.jdbc.Driver"); Connection con = (Connection) DriverManager.getConnection( "jdbc:mysql://localhost:3306/cesium", "root", "root"); con.setAutoCommit(false);// 必须设置,才能手动提交 Statement st = (Statement) con.createStatement( ResultSetImpl.TYPE_SCROLL_SENSITIVE, ResultSetImpl.CONCUR_UPDATABLE, ResultSetImpl.CLOSE_CURSORS_AT_COMMIT); ResultSet rs = st.executeQuery("select * from user"); DatabaseMetaData databaseMetaData = (DatabaseMetaData) con.getMetaData(); if(rs.next()){ Integer i = rs.getInt("id"); System.out.println(i); rs.updateInt("id",10);// 这个更新是会被写回数据库的,应该是隐式的使用了事务,锤子:statement就是事务 rs.updateRow();// 这一行类似与commit。不写上一行不会起效 } System.out.println(rs.getInt("id")); // 测试commit后的游标保留 rs.next(); con.commit(); // 虽然设置了关闭游标,但是实际没有关闭,因为JdbcT里面测过,mysql是不支持提交关闭游标的 System.out.println(rs.getInt("id")); } // 测试第一个参数,db敏感,游标移动不用测,只有这一个选项,没有不可移动 public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException { Class.forName("com.mysql.jdbc.Driver"); Connection con = (Connection) DriverManager.getConnection( "jdbc:mysql://localhost:3306/cesium", "root", "root"); Statement st = (Statement) con.createStatement( ResultSetImpl.TYPE_SCROLL_SENSITIVE, ResultSetImpl.CONCUR_UPDATABLE, ResultSetImpl.CLOSE_CURSORS_AT_COMMIT); ResultSet rs = st.executeQuery("select * from user"); DatabaseMetaData databaseMetaData = (DatabaseMetaData) con.getMetaData(); while(rs.next()){ // 在sleep的时候,改变第二行的数据,并没有及时的更新, // 调用ResultSetImpl.TYPE_SCROLL_SENSITIVE,是无效的。 // 在上一个类中测试过,虽然有参数,但是out的是不支持(false) System.out.println("col1:"+rs.getObject(1)); System.out.println("col2:"+rs.getObject(2)); Thread.sleep(10000); } } }
三-结果分析
1 ResultSet Types
mysql对 ResultType的TYPE_FORWARD_ONLY根本无法调用;
而对ResultType的TYPE_SCROLL_SENSITIVE,查看是false。
2 ResultSet Concurrency
数据会持久化到数据库,不只是rs本身。或许rs本身就是一个指针集合??不去看底层了
3 Cursor Holdability