结果集指针的移动

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. contest1 CF1084 div2 oooxx oooxo ooooo

    题意: div2D (x)(x) 给出一棵树, 找出一条路径, 使得每一时刻点权和\(\ge\)边权和, 并且点权和\(-\)边权和最大 div2E (x)(o) 给出两个长度为\(n(\le 5e5 ...

  2. pyhton2 and python3 生成随机数字、字母、符号字典(用于撞库测试/验证码等)

    本文介绍Python3中String模块ascii_letters和digits方法,其中ascii_letters是生成所有字母,从a-z和A-Z,digits是生成所有数字0-9.string.p ...

  3. 元素的alt和title有什么异同?

    ①alt作为图片的替代文字出现,title作为图片的解释文字出现. ②alt属性应用较少,如img.area.input中,title应用较多,如a.form.input.还有div.p这些块级元素都 ...

  4. Codeforces Round 561(Div 2)题解

    这是一场失败的比赛. 前三题应该是随便搞的. D有点想法,一直死磕D,一直WA.(赛后发现少减了个1……) 看E那么多人过了,猜了个结论交了真过了. 感觉这次升的不光彩……还是等GR3掉了洗掉这次把, ...

  5. 浅谈Asp.Net中的几种传值方式

    一.使用Querystring Querystring是一种非常简单的传值方式,其缺点就是会把要传送的值显示在浏览器的地址栏中,并且在此方法中不能够传递对象.如果你想传递一个安全性不是那么太重要或者是 ...

  6. 【cf比赛记录】Educational Codeforces Round 78 (Rated for Div. 2)

    比赛传送门 A. Shuffle Hashing 题意:加密字符串.可以把字符串的字母打乱后再从前面以及后面接上字符串.问加密后的字符串是否符合加密规则. 题解:字符串的长度很短,直接暴力搜索所有情况 ...

  7. 只访问tomcat,不访问项目时,显示指定内容。

      1.情景展示 我们知道,将javaWeb项目部署到tomcat后,访问该项目的url路径构成是: 网路协议+"://"+ip地址+":"+tomcat设定的 ...

  8. SpringMVC之使用ResponseEntity

    1.Post请求 一般情况下,在非必须的情况下,使用Jquery实现post请求,而后台返回一般都需要手动封装ResponseUtil,和使用@ResponseBody注解来实现返回.然而我们书上学到 ...

  9. Expect Command And How To Automate Shell Scripts Like Magic

    In the previous post, we talked about writing practical shell scripts and we saw how it is easy to w ...

  10. SQL 尚未定义空闲 CPU 条件 - OnIdle 作业计划将不起任何作用

    这条警告表明一个SQL Server代理设置没有配置,可能阻止某些作业运行. 你可以设置作业在CPU“空闲”时运行(在第一篇提到过).然而,在这个系统中空闲的定义还没有被 设置. 在SSMS配置此选项 ...