结果集指针的移动

while (resultSet.next()){
//......
}

指针最初指向第一条记录之前,next()是指向下一个位置,返回的是boolean值,true表示有内容(记录),false表示无内容(false)。

如果当前是指向最后一条记录,next()就指向最后一条记录之后,返回false,退出循环,遍历完成。

准确地说,应该叫做游标(Cursor),学C++的时候叫指针(Pointer)叫习惯了......

//下面3种都是相对当前位置的移动
resultSet.next(); //指针移到下一个位置
resultSet.previous(); //指针移到前一个位置     resultSet.relative(2); //相对当前位置后移2步
    resultSet.relative(-1); //正数表示后移,负数表示前移。相对当前位置前移1步。 //下面5种都是绝对位置的移动
   resultSet.absolute(n); //指向结果集中的第n+1条记录,n是下标,0表示第一条记录
resultSet.first(); //指针移到第一条记录上
resultSet.last(); //指针移到最后一条记录上 resultSet.beforeFirst(); //指针移到第一条记录之前
resultSet.afterLast(); //指针移到最后一条记录之后 //对应的判断方法
resultSet.isFirst();
resultSet.isLast();
resultSet.isBeforeFirst();
resultSet.isAfterLast();

获取结果集中的记录总数

     if(resultSet.last()) {   //指针移到最后一条记录上,使用if是因为结果集可能是空的,要先判断
System.out.println(resultSet.getRow()); //getRow()是返回当前记录是结果集中的第几条记录,int型
}

离线查询

如果要长期使用结果集中的数据,以前有2种方式:

  • 一直保持数据库连接,不关闭。如果保持的连接很多,服务器、数据库的性能都会受到影响。
  • 将结果集中的记录存储到多个JavaBean中,数据库没影响,但要编写JavaBean,写代码遍历结果集,将每行记录赋给JavaBean,自己写代码的话很麻烦。如果记录很多,创建大量的JavaBean是很花时间的,JVM要管理大量的JavaBean对象,开销很大,程序性能降低;且操作结果集比操作JavaBean的集合要简单。

离线查询:在本地搞一个结果集的副本,关闭结果集、数据库连接,使用本地的这个副本。

ResultSet接口有子接口RowSet,RowSet有子接口CachedRowSet。离线查询就是通过CachedRowSet来实现的。

 //从properties文件中加载数据库配置
Properties properties = new Properties();
InputStream inputStream =Class.forName("test.Test").getResourceAsStream("/mysql.properties");
properties.load(inputStream); String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String pwd=properties.getProperty("password"); Class.forName(driver);
Connection connection = DriverManager.getConnection(url, user, pwd); String sql = "select * from student_tb";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery(); //离线查询
RowSetFactory rowSetFactory = RowSetProvider.newFactory(); //通过RowSetProvider的静态方法创建RowSetFactory对象
CachedRowSet cachedRowSet = rowSetFactory.createCachedRowSet(); //创建CachedRowSet对象
cachedRowSet.populate(resultSet); //使用结果集填充cachedRowSet
//cachedRowSet.populate(resultSet,2); //可指定从结果集的第几条记录开始填充,默认为1,从第一条记录开始填充 //关闭数据库资源
resultSet.close();
preparedStatement.close(); //关闭Statement|PreparedStatement对象
connection.close(); //CachedRowSet是ResultSet的孙接口,继承了ResultSet的属性、方法,使用方式和ResultSet一样
while(cachedRowSet.next()){
int id = cachedRowSet.getInt("id");
String name =cachedRowSet.getString("name");
int age = cachedRowSet.getInt("age");
float score = cachedRowSet.getFloat("score");
System.out.println(id+"\t"+name+"\t"+age+"\t"+score);
}

更新结果集

ResultSet默认是可滚动的、不可更新的,不能删除、修改结果集中的记录。如果要获取可更新的结果集(可增删改结果集中的记录),需要在创建Statement | PreparedStatement对象时传入2个额外的参数。

CachedRowSet默认是可滚动的、可更新的,可删除、修改CachedRowSet中的记录。

可滚动指的是可以使用next()、first()、last()、absolute()等方法移动游标,不可滚动指的是只能使用next()来移动游标。

可更新的ResultSet:

 //从properties文件中加载数据库配置
Properties properties = new Properties();
InputStream inputStream =Class.forName("test.Test").getResourceAsStream("/mysql.properties");
properties.load(inputStream); String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String pwd=properties.getProperty("password"); Class.forName(driver);
Connection connection = DriverManager.getConnection(url, user, pwd); String sql = "select * from student_tb";
/*
获取可更新的结果集 第二个参数指定结果集是否是可滚动的:
ResultSet.TYPE_FORWARD_ONLY 不可滚动,只能使用next()移动游标
ResultSet.TYPE_SCROLL_SENSITIVE 可滚动,底层数据的变化会同步到结果集(需要底层数据库驱动的支持)
ResultSet.TYPE_SCROLL_INSENSITIVE 可滚动,底层数据的变化不会同步到结果集 第三个参数指定结果集是否是可更新的:
ResultSet.CONCUR_READ_ONLY 默认值,只读
ResultSet.CONCUR_UPDATABLE 可更新(对结果集中的记录可增删改)
*/
PreparedStatement preparedStatement = connection.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
ResultSet resultSet = preparedStatement.executeQuery(); while (resultSet.next()){
int id = resultSet.getInt("id");
if(id==5){
//updateXxx()修改当前记录某个字段的值,第一个参数指定列(字段),可以用列名或列索引,第二个参数指定新值
resultSet.updateString("name","chy"); //修改当前记录的name字段的值为chy
resultSet.updateRow(); //将对结果集中记录的改同步到数据库中,改不会自动同步到数据库中,需要手动同步
}
else if(id==10){
resultSet.deleteRow(); //删除当前记录(删除当前行),删会自动同步到数据库中
}
} //往结果集中插入一行
resultSet.moveToInsertRow();
/*
通过updateXxx()设置插入行的字段值 resultSet.updateInt("id",100);
如果不设置主键列(id)的值,默认插到结果集的末尾,
如果结果集中没有id=100的记录,但数据库中有,同步到数据库时会出错
*/
resultSet.updateString("name","CoCo");
resultSet.updateInt("age",20);
resultSet.updateInt("score",90); resultSet.insertRow(); //将增同步到数据库 //这期间需要保持数据库连接 resultSet.close();
preparedStatement.close();
connection.close();

update、insert需要手动同步,delete却是自动同步,why?

因为delete是一步操作,update、insert均是多步操作,update可能要updateXxx()修改多个字段,insert可能要updateXxx()插入多个字段的值,JVM不知道你的updateXxx()写完了没有,所以要写resultSet.updateRow()|insertRow();   告诉JVM:我对这条记录的改|插入字段已经弄完了,JVM才会同步到数据库中。

注意是updateRow()、insertRow()、deleteRow(),是Row,不是Rows,同步的只是一条记录。

所以每操作完一条记录,该手动同步的就要手动同步,不能想着一次性同步所有更新。

CachedRowSet的更新操作:

         //从properties文件中加载数据库配置
Properties properties = new Properties();
InputStream inputStream =Class.forName("test.Test").getResourceAsStream("/mysql.properties");
properties.load(inputStream); String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String pwd=properties.getProperty("password"); Class.forName(driver);
Connection connection = DriverManager.getConnection(url, user, pwd); String sql = "select * from student_tb";
PreparedStatement preparedStatement = connection.prepareStatement(sql); //CachedRowSet默认就是可更新的,不必传额外的参数
ResultSet resultSet = preparedStatement.executeQuery();
resultSet.next(); //离线结果集
RowSetFactory rowSetFactory = RowSetProvider.newFactory();
CachedRowSet cachedRowSet = rowSetFactory.createCachedRowSet();
cachedRowSet.populate(resultSet);
resultSet.close();
preparedStatement.close();
connection.close(); while (cachedRowSet.next()){
int id = cachedRowSet.getInt("id");
if (id==15){
//删除记录
cachedRowSet.deleteRow();
}
else if(id==20){
//修改记录
cachedRowSet.updateString("name","chy1");
cachedRowSet.updateRow();
}
} Connection connection1 = DriverManager.getConnection(url, user, pwd); //连接已关闭了,需要重新获取一个连接
connection1.setAutoCommit(false); //将新连接的自动提交设置为false
cachedRowSet.acceptChanges(connection1); //同步到数据库。

对CachedRowSet使用deleteRow()、updateRow()不会立刻同步到数据库中,因为连接已经关闭了,同步不了。

这2个方法相当于把这些同步操作放在一个队列中,当   cachedRowSet.acceptChanges(connection1);   传入一个连接时,就依次执行队列中的同步操作。

CachedRowSet不能插入一条记录,因为CachedRowSet是批量同步的(队列),插入操作可能会受到队列中其他记录的影响。

CachedRowSet是默认可更新的,不是默认自动提交的。

更新操作要求结果集满足2个条件:

  • 结果集只能是单表查询的结果集
  • 结果集中必须含有主键列

分页

分页有3种实现方式。

1、使用sql语句来限定结果集范围

 String sql = "select * from student_tb where id>? and id<?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,0);
preparedStatement.setInt(2,11);
ResultSet resultSet = preparedStatement.executeQuery();

这种方式不好,因为区间上的某些记录可能被删除了,id没了。比如1页10条记录,[1,10],但id=5,id=8的记录被删除了(比如注销账户),实际取到的就比10条少。

 String sql = "select * from student_tb limit ?,?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,0); //从满足条件的记录中的第1条记录起(参数是下标)
preparedStatement.setInt(2,10); //只取10条记录
/*
第一个参数可缺省,默认为0,从第一条记录起。
String sql = "select * from student_tb limit 100"; 只取100条记录
*/

能取足10条,但limit是mysql的特性,对应的SQL  Server特性是top、Oracle特性是rownum,不跨数据库。

2、使用游标来实现

  String sql = "select * from student_tb";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery(); int start=0; //开始位置
int pageSize=10; //每页显示多少条记录
resultSet.absolute(start); //先转到起始处。参数是下标,0表示第一条记录
while (resultSet.next()){
//......
System.out.println(resultSet.getRow());
if(resultSet.getRow()==start+pageSize) //getRow()是获取当前记录是结果集中的第几条记录,第一条就是1。也可以设置计数器来判断
break;
}

3、使用离线查询来实现

 //离线结果集
RowSetFactory rowSetFactory = RowSetProvider.newFactory();
CachedRowSet cachedRowSet = rowSetFactory.createCachedRowSet();
cachedRowSet.setPageSize(10); //设置每页显示多少条记录,其实设置的是CachedRowSet的容量
cachedRowSet.populate(resultSet,1); //设置从结果集中的第几条记录开始填充。cachedRowSet中的记录是结果集中的[1,10]条
resultSet.close();
preparedStatement.close();
connection.close(); while (cachedRowSet.next()){
//......
}

Java JDBC结果集的处理的更多相关文章

  1. Java JDBC学习实战(二): 管理结果集

    在我的上一篇博客<Java JDBC学习实战(一): JDBC的基本操作>中,简要介绍了jdbc开发的基本流程,并详细介绍了Statement和PreparedStatement的使用:利 ...

  2. Java JDBC下执行SQL的不同方式、参数化预编译防御

    相关学习资料 http://zh.wikipedia.org/wiki/Java数据库连接 http://lavasoft.blog.51cto.com/62575/20588 http://blog ...

  3. java JDBC编程流程步骤

    JDBC:Java Data Base Connection JDBC是用于运行sql语句并从数据库中获取新新的java API. JDBC是用来(让我们的程序)通过网络来操作数据库的,作用非常重要: ...

  4. JDBC结果集

    SQL语句执行后从数据库查询读取数据,返回的数据放在结果集中. SELECT语句用于从数据库中选择行并在结果集中查看它们的标准方法. java.sql.ResultSet接口表示数据库查询的结果集. ...

  5. 纯Java JDBC连接数据库,且用JDBC实现增删改查的功能

    Java JDBC连接数据库 package cn.cqvie.yjq; import java.sql.*; /** * 注册数据库的驱动程序,并得到数据库的连接对象 * @author yu * ...

  6. Java JDBC数据库链接

    好久没有编写有关数据库应用程序啦,这里回顾一下java JDBC. 1.使用Java JDBC操作数据库一般需要6步: (1)建立JDBC桥接器,加载数据库驱动: (2)连接数据库,获得Connect ...

  7. JAVA JDBC(存储过程和事务管理)

    1.什么是存储过程 存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程 ...

  8. spring:使用<prop>标签为Java持久属性集注入值

    spring:使用<prop>标签为Java持久属性集注入值 使用 spring 提供的<prop>为Java持久属性集注入值,也就是向 java.util.Propertie ...

  9. 互联网大厂Java面试题集—Spring boot面试题(一)

    Spring Boot 需要独立的容器运行吗? 可以不需要,内置了 Tomcat/ Jetty 等容器.通过pom.xml中导入依赖: <!--spring-boot-starter-web:代 ...

随机推荐

  1. ajax中什么时候进success和error

    先简单介绍下ajax: 简单的说Ajax请求通过XMLHttpRequest对象发送请求,该对象有四个状态(readyState): -未初始化.-正在初始化.-发送数据.-正在发送数据.-完成. 当 ...

  2. 前端html页面,手机查看

    在写前端页面中,经常会在浏览器运行HTML页面,从本地文件夹中直接打开的一般都是file协议,当代码中存在http或https的链接时,HTML页面就无法正常打开,为了解决这种情况,需要在在本地开启一 ...

  3. Java 静态、类加载

    1.静态是什么?有什么用? static的主要作用在于创建独立于具体对象的域变量或者方法. 每创建一个对象,都会在堆里开辟内存,存成员(属性),但是不存方法,方法是共用的,没必要每一个对象都浪费内存去 ...

  4. hadoop java.io.EOFException: Unexpected end of input stream

    执行hadoop 报错 java.io.EOFException: Unexpected end of input stream at org.apache.hadoop.io.compress.De ...

  5. django @login_required登录限制(2)-返回登陆成功后的页面

    本次要实现的功能是,访问未登录的视图函数,需要先跳转到登录页面,登陆成功在跳转回来. 之前在网上找了很多资料,都没有找到解决方案. 跳转到登录页面很好弄,就是登陆成功跳转回来出了问题,原因是登录后的p ...

  6. 概率论基础知识(Probability Theory)

    概率(Probability):事件发生的可能性的数值度量. 组合(Combination):从n项中选取r项的组合数,不考虑排列顺序.组合计数法则:. 排列(Permutation):从n项中选取r ...

  7. vs启动报4.X的错

    参考: https://www.cnblogs.com/zsx-blog/p/6136956.html https://blog.csdn.net/lishaoran369/article/detai ...

  8. .NETCore_项目启动设置域名以及端口

    //第一种方式就是启动是一个命令窗口 public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.C ...

  9. django:CBV模式,源码解析

    非常好 DRF执行流程源码解析 https://www.cnblogs.com/suguangti/p/11120793.html https://www.cnblogs.com/haitaoli/p ...

  10. Shell脚本之六 数学计算

    前面一节Shell篇之五 基本运算符介绍了常见的 Shell 算术运算符,这节介绍 Shell 的数学计算.Shell 和其它编程语言不同,Shell 不能直接进行算数运算,必须使用数学计算命令. 下 ...