欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java JDBC结果集的处理

程序员文章站 2023-04-04 11:39:20
结果集指针的移动 指针最初指向第一条记录之前,next()是指向下一个位置,返回的是boolean值,true表示有内容(记录),false表示无内容(false)。 如果当前是指向最后一条记录,next()就指向最后一条记录之后,返回false,退出循环,遍历完成。 准确地说,应该叫做游标(Cur ......

 

结果集指针的移动

Java   JDBC结果集的处理

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();

 

 

 

 

获取结果集中的记录总数

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

 

 

 

 

离线查询

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

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

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

 

resultset接口有子接口rowset,rowset有子接口cachedrowset。离线查询就是通过cachedrowset来实现的。

 

 1 //从properties文件中加载数据库配置
 2         properties properties = new properties();
 3         inputstream inputstream =class.forname("test.test").getresourceasstream("/mysql.properties");
 4         properties.load(inputstream);
 5 
 6         string driver = properties.getproperty("driver");
 7         string url = properties.getproperty("url");
 8         string user = properties.getproperty("user");
 9         string pwd=properties.getproperty("password");
10 
11         class.forname(driver);
12         connection connection = drivermanager.getconnection(url, user, pwd);
13 
14         string sql = "select * from student_tb";
15         preparedstatement preparedstatement = connection.preparestatement(sql);
16         resultset resultset = preparedstatement.executequery();
17 
18         //离线查询
19         rowsetfactory rowsetfactory = rowsetprovider.newfactory();  //通过rowsetprovider的静态方法创建rowsetfactory对象
20         cachedrowset cachedrowset = rowsetfactory.createcachedrowset();  //创建cachedrowset对象
21         cachedrowset.populate(resultset);  //使用结果集填充cachedrowset
22         //cachedrowset.populate(resultset,2);  //可指定从结果集的第几条记录开始填充,默认为1,从第一条记录开始填充
23         
24         //关闭数据库资源
25         resultset.close();  
26         preparedstatement.close();  //关闭statement|preparedstatement对象
27         connection.close();  
28 
29         //cachedrowset是resultset的孙接口,继承了resultset的属性、方法,使用方式和resultset一样
30         while(cachedrowset.next()){
31             int id = cachedrowset.getint("id");
32             string name =cachedrowset.getstring("name");
33             int age = cachedrowset.getint("age");
34             float score = cachedrowset.getfloat("score");
35             system.out.println(id+"\t"+name+"\t"+age+"\t"+score);
36         }

 

 

 

 

更新结果集

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

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

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

 

可更新的resultset:

 1 //从properties文件中加载数据库配置
 2         properties properties = new properties();
 3         inputstream inputstream =class.forname("test.test").getresourceasstream("/mysql.properties");
 4         properties.load(inputstream);
 5 
 6         string driver = properties.getproperty("driver");
 7         string url = properties.getproperty("url");
 8         string user = properties.getproperty("user");
 9         string pwd=properties.getproperty("password");
10 
11         class.forname(driver);
12         connection connection = drivermanager.getconnection(url, user, pwd);
13 
14         string sql = "select * from student_tb";
15         /*
16         获取可更新的结果集
17 
18         第二个参数指定结果集是否是可滚动的:
19         resultset.type_forward_only   不可滚动,只能使用next()移动游标
20         resultset.type_scroll_sensitive  可滚动,底层数据的变化会同步到结果集(需要底层数据库驱动的支持)
21         resultset.type_scroll_insensitive  可滚动,底层数据的变化不会同步到结果集
22 
23         第三个参数指定结果集是否是可更新的:
24         resultset.concur_read_only   默认值,只读
25         resultset.concur_updatable   可更新(对结果集中的记录可增删改)
26          */
27         preparedstatement preparedstatement = connection.preparestatement(sql, resultset.type_scroll_sensitive,resultset.concur_updatable);
28         resultset resultset = preparedstatement.executequery();
29 
30         while (resultset.next()){
31             int id = resultset.getint("id");
32             if(id==5){
33                 //updatexxx()修改当前记录某个字段的值,第一个参数指定列(字段),可以用列名或列索引,第二个参数指定新值
34                 resultset.updatestring("name","chy");  //修改当前记录的name字段的值为chy
35                 resultset.updaterow();  //将对结果集中记录的改同步到数据库中,改不会自动同步到数据库中,需要手动同步
36             }
37             else if(id==10){
38                 resultset.deleterow();  //删除当前记录(删除当前行),删会自动同步到数据库中
39             }
40         }
41 
42         //往结果集中插入一行
43         resultset.movetoinsertrow();  
44         /*
45         通过updatexxx()设置插入行的字段值
46 
47         resultset.updateint("id",100);
48         如果不设置主键列(id)的值,默认插到结果集的末尾,
49         如果结果集中没有id=100的记录,但数据库中有,同步到数据库时会出错
50          */
51         resultset.updatestring("name","coco");
52         resultset.updateint("age",20);
53         resultset.updateint("score",90);
54 
55         resultset.insertrow();  //将增同步到数据库
56 
57         //这期间需要保持数据库连接
58         
59         resultset.close();
60         preparedstatement.close();
61         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的更新操作:

 1         //从properties文件中加载数据库配置
 2         properties properties = new properties();
 3         inputstream inputstream =class.forname("test.test").getresourceasstream("/mysql.properties");
 4         properties.load(inputstream);
 5 
 6         string driver = properties.getproperty("driver");
 7         string url = properties.getproperty("url");
 8         string user = properties.getproperty("user");
 9         string pwd=properties.getproperty("password");
10 
11         class.forname(driver);
12         connection connection = drivermanager.getconnection(url, user, pwd);
13 
14         string sql = "select * from student_tb";
15         preparedstatement preparedstatement = connection.preparestatement(sql);   //cachedrowset默认就是可更新的,不必传额外的参数
16         resultset resultset = preparedstatement.executequery();
17         resultset.next();
18 
19         //离线结果集
20         rowsetfactory rowsetfactory = rowsetprovider.newfactory();
21         cachedrowset cachedrowset = rowsetfactory.createcachedrowset();
22         cachedrowset.populate(resultset);
23         resultset.close();
24         preparedstatement.close();
25         connection.close();
26 
27         while (cachedrowset.next()){
28             int id = cachedrowset.getint("id");
29             if (id==15){
30                 //删除记录
31                 cachedrowset.deleterow();
32             }
33             else if(id==20){
34                 //修改记录
35                 cachedrowset.updatestring("name","chy1");
36                 cachedrowset.updaterow();
37             }
38         }
39 
40         connection connection1 = drivermanager.getconnection(url, user, pwd);   //连接已关闭了,需要重新获取一个连接
41         connection1.setautocommit(false);  //将新连接的自动提交设置为false
42         cachedrowset.acceptchanges(connection1);  //同步到数据库。

 

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

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

 

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

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

 

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

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

 

 

 

 

分页

分页有3种实现方式。

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

1 string sql = "select * from student_tb where id>? and id<?";
2         preparedstatement preparedstatement = connection.preparestatement(sql);
3         preparedstatement.setint(1,0);
4         preparedstatement.setint(2,11);
5         resultset resultset = preparedstatement.executequery();

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

 

1 string sql = "select * from student_tb limit ?,?";
2         preparedstatement preparedstatement = connection.preparestatement(sql);
3         preparedstatement.setint(1,0);   //从满足条件的记录中的第1条记录起(参数是下标)
4         preparedstatement.setint(2,10);  //只取10条记录
5         /*
6         第一个参数可缺省,默认为0,从第一条记录起。
7         string sql = "select * from student_tb limit 100"; 只取100条记录
8          */

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

 

 

2、使用游标来实现

 1  string sql = "select * from student_tb";
 2         preparedstatement preparedstatement = connection.preparestatement(sql);
 3         resultset resultset = preparedstatement.executequery();
 4 
 5         int start=0;  //开始位置
 6         int pagesize=10;  //每页显示多少条记录
 7         resultset.absolute(start);  //先转到起始处。参数是下标,0表示第一条记录
 8         while (resultset.next()){
 9             //......
10             system.out.println(resultset.getrow());
11             if(resultset.getrow()==start+pagesize)  //getrow()是获取当前记录是结果集中的第几条记录,第一条就是1。也可以设置计数器来判断
12                 break;
13         }

 

 

3、使用离线查询来实现

 1 //离线结果集
 2         rowsetfactory rowsetfactory = rowsetprovider.newfactory();
 3         cachedrowset cachedrowset = rowsetfactory.createcachedrowset();
 4         cachedrowset.setpagesize(10);  //设置每页显示多少条记录,其实设置的是cachedrowset的容量
 5         cachedrowset.populate(resultset,1);  //设置从结果集中的第几条记录开始填充。cachedrowset中的记录是结果集中的[1,10]条
 6         resultset.close();
 7         preparedstatement.close();
 8         connection.close();
 9 
10         while (cachedrowset.next()){
11            //......
12         }