自JDBC2.0之后,可滚动(Scrollable)结果集出现,利用可滚动结果集你可以在结果集中前后移动,并可以跳到任意行,后者通过绝对行号和当前行号的偏移量都能够实现。可滚动结果集可以“感知”到用于填充它的数据库表中行的修改,这意味着它对于数据库中的某些修改是敏感的,这称为敏感的可滚动(sensitive scrollable)结果集。结果集也可以用于更新、删除、插入底层数据库表中的行,这称为可更新(updatable)结果集。
1、结果集的创建
假设我们已经获得一个对数据库的连接conn,以下语句创建了不敏感的可滚动结果集,同时它是可更新的。
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
//createStatement接受两个参数:结果集类型(type)和结果集的并发性(concurrency)。
结果集类型决定结果集是否是可滚动的,如果是可滚动的,还要决定它对数据库修改是否敏感,结果集类型是由定义在ResultSet中的如下int类型字段指定的:
- ResultSet.TYPE_FORWARD_ONLY:指定结果集不可滚动,这是默认值。
- ResultSet.TYPE_SCROLLABLE_INSENSITIVE:指定结果集可滚动,但对数据库修改不敏感。
- ResultSet.TYPE_SCROLLABLE_SENSITIVE:指定结果集可滚动,并对数据库修改敏感。
结果集并发性由ResultSet中如下int类型字段指定:
- ResultSet.CONCUR_READ_ONLY:指定结果集不能修改填充它的数据库表中的行,这是默认值。
- ResultSet.CONCUR_UPDATABLE:指定结果接可以修改填充它的数据库表中的行。
2、在可滚动结果集中移动
创建可滚动结果集之后,可以通过以下方法来进行移动:
- next():移动到结果集中的下一行。
- previous():移动到前一行。
- first():移动到第一行。
- last():移动到最后一行。
- beforeFirst():移动到第一行之前,常用于从头开始读取行。
- afterLast():移动到最后一行之后。
- absolute(int rowNumber):移动到行数为rowNumber的行;如果rowNumber为负值,则以最后一行为首、第一行为尾,由首向尾移动行数为rowNumber的绝对值的行。
- relative(int relativeRowNumber):相对结果集当前所在行,移动行数为relativeRowNumber的行,若relativeRowNumber为负值,则相对当前行向前移动
注意:以上用于在结果集中移动的函数,如果没找到要移动到的行,则返回false,否则返回true。
获得当前位置:
getRow()、isFirst()、isLast()、isBeforeFirst()、isAfterLast()
3、在可更新结果集操作行
对于可更新结果集使用的查询有许多限制:
- 只能使用一个表。
- 必须选择这个表的主键和所有其他NOT NULL列。
- 不能使用ORDER BY字句。
- 必须只选择列值。
- 不能使用SELECT *,你必须使用表别名,如SELECT customer.* FROM customer。
更新行:update()
update方法用来对不同数据类型的列做修改,如要对VARCHAR2类型列作修改,则用到updateString(String colName,String newVal),第一个参数指定列名,第二个参数指定一个新值。例如对Date类型列修改时:
java.sql.Date newDate = new java.sql.Date(69,1,1);
myResultSet.updateDate("birthday",newDate);
注意:不能使用update方法对主键进行修改。
最后,一旦完成对当前行的修改后,需要需要使用updateRow()方法将这些修改发送到数据库:myResultSet.updateRow();可以使用Connection对象的commit()方法提交它。
删除行:deleteRow()
移动到要删除的行之后,可以利用deleteRow()方法删除当前行:
myResultSet.absolute(2);
myResultSet.deleteRow();
更新和删除时发生的冲突:
利用SELECT语句对结果集进行填充时,这个语句返回的行并没被数据库“锁定”,这就意味着其他事务可能对你的结果集进行修改,这就形成了冲突。解决这个问题的方法就是:在SELECT语句添加字句FOR UPDATE,用以锁定返回到结果集中的行。
插入行:insertRow()
插入行的一般顺序是:
1)利用moveToInsertRow()方法创建一个新的空行。
2)利用update()方法对这一空行的各列进行修改,这里要注意的是必须利用update()方法设置主键和NOT NULL列的值。
3)利用insertRow()将插入行操作发送到数据库。
4)利用moveToCurrentRow()返回到插入行之前的那个行。
最后附上创建结果集、操作结果集的实例代码:
public static void main(String[] args)throws SQLException{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORCL","username","pwd");
conn.setAutoCommit(false);
//创建敏感的可更新结果集
Statement myStatement = conn.createStatement(
ResultSet.TYPE_SCROLLABLE_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
//创建ResultSet对象,并用SELECT语句填充它。
//Note:这里利用FOR UPDATE让数据库锁定了结果集中的行
ResultSet myResultSet = myStatement.excuteQuery("SELECT id,name "+
"FROM customer FOR UPDATE");
//更新行
myResultSet.absolute(2);//直接移动到第二行
String newName = "hahaha";
myResultSet.updateString("name",newName);
myResultSet.updateRow();
//插入行
myResultSet.moveToInsertRow();
myResultSet.updateInt("id",5);//设置主键值
myResultSet.updateString("name","wowowo");//设置NOT NULL列name
myResultSet.insertRow();//将插入操作发送到数据库
myResultSet.moveToCurrentRow();//返回插入之前的那个行,这里应该是第二行
//删除行
myResultSet.relative(3);//相对当前行(第二行)向前移动三行(至第五行)
myResultSet.deleteRow();
//查询结果集中的数据
myResultSet.beforeFirst();
while(myResultSet.next()){
System.out.pritnln("id = "+myResultSet.getInt("id"));
System.out.println("name = "+myResultSet.getString("name"));
}
//关闭结果集
myResultSet.close();
//关闭JDBC对象
myStatement.close();
conn.close();
}//end of main