1. 读写LOB
除了数字、字符串和日期之外,许多数据库还可以存储大对象,例如图片或其它数据。在SQL中,二进制大对象称为BLOB,字符型大对象称为CLOB。
要读取LOB,需要执行SELECT语句,然后在ResultSet上调用getBlob或getClob方法,这样就可以获得Blob或Clob类型的对象。要从Blob中获取二进制数据,可以调用getBytes或getInputStream。例如,如果你有一张保存图书封面图形的表,那么就可以像下面这样获取一张图像:
PreparedStatement stat = conn.prepareStatement("SELECT Cover FROM BookCovers WHERE ISBN=?");
stat.set(1, isbn);
ResultSet result=stat.executeQuery();if(result.next()){
Blob coverBlob= result.getBlob(1);
Image coverImage=ImageIO.read(coverBlob.getBinaryStream());
}
类似地,如果获取了Clob对象,那么就可以通过调用getSubString或getCharacterStream方法来获取其中的字符数据。
要将LOB置于数据库中,需要在Connection对象上调用createBlob或createClob,然后获取一个用于该LOB的输出流或写出器,写出数据,并将该对象存储到数据库中。例如,下面展示了如何存储一张图像:
Blob coverBlob =connection.createBlob();int offset = 0;
OutputStream out=coverBlob.setBinaryStream(offset);
ImageIO.write(coverImage,"PNG", out);
PreparedStatement stat= conn.prepareStatement("INSERT INTO Cover VALUES(?, ?)");
stat.set(1, isbn);
stat.set(2,coverBlob);
stat.executeUpdate();
2. 可滚动和可更新的结果集
要让ResultSet可以滚动个和更新,必须在创建Statement对象的时候使用下面的方式指定对应的参数:
Statement stmt = conn.createStatement(type, concurrency);
对于PreparedStatement,使用下面的方式指定参数:
PreparedStatement pstmt = conn.prepareStatement(sql, type, concurrency);
其中,type表示ResuleSet的类型,而concurrency表示是否可以使用ResuleSet来更新数据库。
type和concurrency的取值以及含义如下:
ResultSet类的type值
值
解释
ResultSet.TYPE_FORWARD_ONLY
结果集不能滚动(默认值)
ResultSet.TYPE_SCROLL_INSENSITIVE
结果集可以滚动,但ResuleSet对数据库中数据变化不敏感
ResultSet.TYPE_SCROLL_SENSIT IVE
结果集可以滚动,并且ResuleSet对数据库中发生的改变敏感
ResultSet类的Concurrency值
值
解释
ResultSet.CONCUR_READ_ONLY
结果集不能用于更新数据库(默认值)
ResultSet.CONCUR_UPDATABLE
结果集可以用于更新数据库
JDBC的结果集有很多类型。这些结果集有不同的特性,以满足各种需要。这在高性能的JDBC数据操作中有着重要应用。下面是一个应用实例:
packagelavasoft.common;importjava.sql.Connection;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.sql.Statement;/*** JDBC可滚动可更新感知更新结果集测试
*
*@authorleizhimin 2009-12-8 20:09:03*/
public classTestResultSet {public static voidmain(String[] args) {
testScrollResultSet();
testUpdateResultSet();
}/*** 可更新结果集更新测试*/
public static voidtestUpdateResultSet() {
Connection conn=DBToolkit.getConnection();
String sql= "SELECT * FROM book";try{
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs=stmt.executeQuery(sql);
System.out.println("---------原结果集--------");while(rs.next()) {
System.out.println("[行号:" + rs.getRow() + "]\t" + rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3));
}
System.out.println("---------插入一条记录--------");
rs.first();//将光标移动到插入行上
rs.moveToInsertRow();//构建行数据
rs.updateString(2, "xxxx");
rs.updateString(3, "x");//插入一行
rs.insertRow();
System.out.println("-------------更新一条记录-------------");
rs.absolute(3);//构建行数据
rs.updateString(2, "uuuu");
rs.updateString(3, "u");
rs.updateRow();
System.out.println("---------插入更新后的结果集--------");
rs=stmt.executeQuery(sql);while(rs.next()) {
System.out.println("[行号:" + rs.getRow() + "]\t" + rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3));
}
rs.close();
stmt.close();
}catch(SQLException e) {
e.printStackTrace();
}finally{
DBToolkit.closeConnection(conn);
}
}/*** 可滚动结果集滚动测试*/
public static voidtestScrollResultSet() {
Connection conn=DBToolkit.getConnection();
String sql= "SELECT * FROM book";try{
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet rs=stmt.executeQuery(sql);while(rs.next()) {
System.out.println("[行号:" + rs.getRow() + "]\t" + rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3));
}
System.out.println("------前滚操作-----");//将光标移动到此 ResultSet 对象的上一行
rs.previous();
rs.previous();
System.out.println("[行号:" + rs.getRow() + "]\t" + rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3));
System.out.println("------绝对定位-----");//将光标移动到此 ResultSet 对象的给定行编号。
rs.absolute(3);
System.out.println("[行号:" + rs.getRow() + "]\t" + rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3));
System.out.println("------移动到第一行-----");//将光标移动到此 ResultSet 对象的第一行。
if(rs.first()) {
System.out.println("[行号:" + rs.getRow() + "]\t" + rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3));
}
System.out.println("------移动到最后一行-----");//将光标移动到此 ResultSet 对象的第一行。
if(rs.last()) {
System.out.println("[行号:" + rs.getRow() + "]\t" + rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3));
}
System.out.println("------移动到第一行之前-----");//将光标移动到此 ResultSet 对象的开头,正好位于第一行之前
rs.beforeFirst();
rs.next();
System.out.println("[行号:" + rs.getRow() + "]\t" + rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3));
System.out.println("------移动到最后一行之后-----");//将光标移动到此 ResultSet 对象的末尾,正好位于最后一行之后。
rs.afterLast();
rs.previous();
System.out.println("[行号:" + rs.getRow() + "]\t" + rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3));
System.out.println("------相对当前行做移动-----");
rs.relative(-2);
System.out.println("[行号:" + rs.getRow() + "]\t" + rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3));
rs.close();
stmt.close();
}catch(SQLException e) {
e.printStackTrace();
}finally{
DBToolkit.closeConnection(conn);
}
}
}
控制台输出:
[行号:1] 1aaa a
[行号:2] 2bbb b
[行号:3] 3ccc c
[行号:4] 4ddd d
[行号:5] 5eee e
[行号:6] 6fff f
[行号:7] 7ggg g
[行号:8] 8hhh h------前滚操作-----[行号:7] 7ggg g------绝对定位-----[行号:3] 3ccc c------移动到第一行-----[行号:1] 1aaa a------移动到最后一行-----[行号:8] 8hhh h------移动到第一行之前-----[行号:1] 1aaa a------移动到最后一行之后-----[行号:8] 8hhh h------相对当前行做移动-----[行号:6] 6fff f---------原结果集--------[行号:1] 1aaa a
[行号:2] 2bbb b
[行号:3] 3ccc c
[行号:4] 4ddd d
[行号:5] 5eee e
[行号:6] 6fff f
[行号:7] 7ggg g
[行号:8] 8hhh h---------插入一条记录--------
-------------更新一条记录-------------
---------插入更新后的结果集--------[行号:1] 1aaa a
[行号:2] 2bbb b
[行号:3] 3uuuu u
[行号:4] 4ddd d
[行号:5] 5eee e
[行号:6] 6fff f
[行号:7] 7ggg g
[行号:8] 8hhh h
[行号:9] 9xxxx x
Process finished with exit code0
可保存性:设置提交时候是否关闭结果集。
ResultSet.HOLD_CURSORS_OVER_COMMIT :在提交后结果集还可用
ResultSet.CLOSE_CURSORS_AT_COMMIT:在提交时候关闭结果集
由于这些特性比较高级,不同数据库驱动对此实现也不一样。因此在使用JDBC高级特性的时候最好做个测试,以保证程序的可靠性。
当type设置为:ResultSet.TYPE_SCROLL_INSENSITIVE 或者 ResultSet.TYPE_SCROLL_INSENSITIVE 时,游标可以移动,但是移动的位置是[1,count],记住并不是从0开始,否则会报错。
既然可以移动,那么把移动的几个方法解释一下:
rs = statement.executeQuery(); 游标指向第一行前面的位置,这个位置是不能获取数据,否则报错:结果集没有当前行
rs.next(); // 游标下移一个位置,如果所在位置有结果集那么返回true,否则返回false
rs.previous(); // 游标上移一个位置,如果所在位置有结果集那么返回true,否则返回false
rs.first(); // 游标指向第一行的位置
rs.last(); // 游标指向最后一行的位置
rs.beforeFirst(); // 游标指向第一行前面的位置 , 这个位置不能获取数据
rs.afterLast(); // 游标指向最后一行后面的位置,这个位置不能获取数据
rs.absolute(index); // 游标移动至index位置,index是[1,count]的任意数字,但是不能超出,否则报错
rs.relative(index); // 游标从当前位置算移动index个位置,也就是相对移动,index可以是负数,但是计算结果同样在[1,count]内
isAfterLast(); // 判断游标是否在最后一行之后。
isBeforeFirst();// 判断游标是否在第一行之前。
ifFirst() ; //判断游标是否指向结果集的第一行。
isLast(); // 判断游标是否指向结果集的最后一行。
getRow();// 得到当前游标所指向行的行号,行号从1开始,如果结果集没有行,返回0。
原文:http://www.cnblogs.com/gaopeng527/p/4530168.html