本教程是针对 JDK 8 编写的。本页面中描述的示例和实践不利用后续版本引入的改进,并且可能使用不再可用的技术。
请参阅 Java 语言变更 了解 Java SE 9 及后续版本中更新的语言特性的摘要。
请参阅 JDK 发行说明 了解有关所有 JDK 版本的新功能、增强功能以及已删除或已弃用选项的信息。
Blob
、Clob
和NClob
Java对象的一个重要特点是,您可以在不将它们的所有数据从数据库服务器带到客户端计算机的情况下操作它们。一些实现使用一个定位器(逻辑指针)来表示这些类型的实例,该定位器指向实例所表示的数据库中的对象。由于BLOB
、CLOB
或NCLOB
SQL对象可能非常大,使用定位器可以显著提高性能。然而,其他实现在客户端计算机上完全实例化大对象。
如果您想将BLOB
、CLOB
或NCLOB
SQL值的数据带到客户端计算机,可以使用Blob
、Clob
和NClob
Java接口中提供的方法。这些大对象类型对象将它们所表示的对象的数据作为流实例化。
下面介绍了以下主题:
下面摘自ClobSample.addRowToCoffeeDescriptions
的代码将一个CLOB
SQL值添加到表COFFEE_DESCRIPTIONS
中。Java对象myClob
包含由fileName
指定的文件的内容。
public void addRowToCoffeeDescriptions(String coffeeName, String fileName) throws SQLException { String sql = "INSERT INTO COFFEE_DESCRIPTIONS VALUES(?,?)"; Clob myClob = this.con.createClob(); try (PreparedStatement pstmt = this.con.prepareStatement(sql); Writer clobWriter = myClob.setCharacterStream(1);){ String str = this.readFile(fileName, clobWriter); System.out.println("写入的内容如下: " + clobWriter.toString()); if (this.settings.dbms.equals("mysql")) { System.out.println("MySQL,使用setString方法在Clob对象中设置字符串"); myClob.setString(1, str); } System.out.println("Clob的长度: " + myClob.length()); pstmt.setString(1, coffeeName); pstmt.setClob(2, myClob); pstmt.executeUpdate(); } catch (SQLException sqlex) { JDBCTutorialUtilities.printSQLException(sqlex); } catch (Exception ex) { System.out.println("意外异常: " + ex.toString()); } }
以下代码创建了一个Clob
Java对象:
Clob myClob = this.con.createClob();
以下代码检索一个流(在这种情况下是一个名为clobWriter
的Writer
对象),用于将字符流写入Clob
Java对象myClob
。方法ClobSample.readFile
写入这个字符流;该流来自由String
fileName
指定的文件。方法参数1
表示Writer
对象将从Clob
值的开头开始写入字符流:
Writer clobWriter = myClob.setCharacterStream(1);
ClobSample.readFile
方法逐行读取由文件fileName
指定的文件,并将其写入由writerArg
指定的Writer
对象:
private String readFile(String fileName, Writer writerArg) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(fileName))) { String nextLine = ""; StringBuffer sb = new StringBuffer(); while ((nextLine = br.readLine()) != null) { System.out.println("Writing: " + nextLine); writerArg.write(nextLine); sb.append(nextLine); } // 将内容转换为字符串 String clobData = sb.toString(); // 返回数据。 return clobData; } }
以下代码片段创建了一个PreparedStatement
对象pstmt
,将Clob
Java对象myClob
插入到COFFEE_DESCRIPTIONS
中:
String sql = "INSERT INTO COFFEE_DESCRIPTIONS VALUES(?,?)"; Clob myClob = this.con.createClob(); try (PreparedStatement pstmt = this.con.prepareStatement(sql); // ... ) { // ... pstmt.setString(1, coffeeName); pstmt.setClob(2, myClob); pstmt.executeUpdate(); // ...
ClobSample.retrieveExcerpt
方法从COFFEE_DESCRIPTIONS
的COF_DESC
列中检索存储的CLOB
SQL值,该行的列值COF_NAME
等于由coffeeName
参数指定的String
值:
public String retrieveExcerpt(String coffeeName, int numChar) throws SQLException { String description = null; Clob myClob = null; String sql = "select COF_DESC from COFFEE_DESCRIPTIONS where COF_NAME = ?"; try (PreparedStatement pstmt = this.con.prepareStatement(sql)) { pstmt.setString(1, coffeeName); ResultSet rs = pstmt.executeQuery(); if (rs.next()) { myClob = rs.getClob(1); System.out.println("Length of retrieved Clob: " + myClob.length()); } description = myClob.getSubString(1, numChar); } catch (SQLException sqlex) { JDBCTutorialUtilities.printSQLException(sqlex); } catch (Exception ex) { System.out.println("Unexpected exception: " + ex.toString()); } return description; }
以下代码行从ResultSet
对象rs
中检索Clob
Java值:
myClob = rs.getClob(1);
以下代码行从myClob
对象中检索子字符串。子字符串从myClob
的值的第一个字符开始,并具有numChar
指定的连续字符数,其中numChar
是一个整数。
description = myClob.getSubString(1, numChar);
添加和检索BLOB
SQL对象与添加和检索CLOB
SQL对象类似。使用Blob.setBinaryStream
方法检索OutputStream
对象,以写入BLOB
SQL值,该值由调用该方法的Blob
Java对象表示。
Blob
、Clob
和NClob
Java对象在创建它们的事务的持续时间内保持有效。在长时间运行的事务期间,这可能导致应用程序耗尽资源。应用程序可以通过调用它们的free
方法释放Blob
、Clob
和NClob
资源。
在以下代码片段中,调用Clob.free
方法释放先前创建的Clob
对象所持有的资源:
Clob aClob = con.createClob(); int numWritten = aClob.setString(1, val); aClob.free();