结果集指针的移动

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. js中a + 1 < a等于true,(a ==1 && a== 2 && a==3) 等于 true如何实现

    先说a + 1 < a const a = { i: 1, valueOf: () => { if (a.i === 1) { return a.i++; } return a.i+2; ...

  2. VUE温习:内存泄漏、Vue.$set、key作用与虚拟diff算法

    一.内存泄漏 1.指令绑定了事件,却没有解绑事件,容易产生内存泄漏.(曾经遇到过的案例) 2.v-if指令产生内存泄漏,比如v-if删除了父级元素,却没有删除父级元素里的dom片段 3.跳转到别的路由 ...

  3. 将float数字按照一定格式写入到文件中

    /* float.c */ #include<stdio.h> #include<string.h> int main() { FILE *fp = fopen("D ...

  4. Lab1:bootloader操作系统的启动

    前言 最近接了一个外包项目再加上填一些之前立的flag,发现好像很久没有发博客了.现在编译原理操作系统算法方面都还有大坑没有填,加上离实习越来越近,应用层方面的学习也要加强了,但反倒是压力越大越想摸鱼 ...

  5. 记录一次在生成数据库服务器上出现The timeout period elapsed prior to completion of the operation or the server is not responding.和Exception has been thrown by the target of an invocation的解决办法

    记一次查询超时的解决方案The timeout period elapsed...... https://www.cnblogs.com/wyt007/p/9274613.html Exception ...

  6. 安卓 App 性能专项测试之流畅度深度解析-中篇

    背景 毫无疑问,流畅度在Android众多性能指标中其重要程度不言而喻,而且也是最为复杂的一个.为了描述这样的一个维度,业界大佬纷纷提出了各种指标来对其进行衡量.在上篇文章中给大家介绍了FPS这一项指 ...

  7. Java安装 --- jdk 和eclipse tomcat

    ​本文主要使用win7进行安装 安装jdk jdk:  这里面有四个版本78910,会持续增加 链接:https://pan.baidu.com/s/1LTauKbBJKQVOvlbHx2dTwQ提取 ...

  8. [转帖]华为PC端台式机电脑来啦!自研主板及自研CPU处理器

    华为PC端台式机电脑来啦!自研主板及自研CPU处理器 在性能上,4核版相当于酷睿i5 ,8核版相当于酷睿i5 8300H. https://www.bilibili.com/read/cv376376 ...

  9. Sitecore 8.2 防火墙规则的权威指南

    如今,使用多层安全保护您的数据不再是奢侈品; 这是不容谈判的.此外,您需要确保Sitecore解决方案保持运行并与集成服务(例如SQL,Mongo,Solr)通信,同时保持相同的安全级别. 让我们假设 ...

  10. 拦截器配置类使用继承写法导致jackson的全局配置失效

    问题描述 项目中需要一个拦截器用于拦截请求,在没有请求中生成requestId.然后写了一个配置类,这个类继承了 WebMvcConfigurationSupport类,重写了addIntercept ...