8.5. 使用大对象

Postgres里,大对象 (也称之为 BLOB)用于保存那些无法在通常 SQL 表里面保存的数据.它们是以一种特殊的格式存储在一个独立的 表里面的,然后用一个 OID 值从你自己的表里面引用.

Important: 对于 Postgres ,你必须在一个 SQL 事务里面访问大对象。 你应该带着一个输入参数false使用 setAutoCommit() 方法打开一个事务:

Connection mycon;
...
mycon.setAutoCommit(false);
... // now use Large Objects

目前,你有两种使用大对象的方法.第一种是标准的 JDBC 方式,这个方式在这里有文档. 另一种,使用 PostgreSQL 对该(JDBC)API (编程接口)的扩展, 也是一种用于 Java 的 libpq 大对象 API 的形式, 提供了一种比标准方法更好的访问大对象的访问方法. 在系统内部,该驱动使用这种扩展来提供大对象支持.

JDBC里, 标准的访问大对象的方法是使用ResultSet里的 getBinaryStream()方法, 和 PreparedStatement 里的 setBinaryStream()方法. 这些方法把大对象表示成 Java 的流(stream), 允许你用java.io和其他的包来操纵这些对象. Example 8-2 演示了这个方法.

Example 8-2. 使用 JDBC 大对象接口

例如,假设你有一个包含一幅图象文件名的表,而且一个大对象包含这个图象:

CREATE TABLE images (imgname text, imgoid oid);

要插入一幅图象,你可以:

File file = new File("myimage.gif");
FileInputStream fis = new FileInputStream(file);
PreparedStatement ps = conn.prepareStatement("INSERT INTO images VALUES (?, ?)"); (1)
ps.setString(1, file.getName());
ps.setBinaryStream(2, fis, file.length());
ps.executeUpdate();
ps.close();
fis.close();
(1)
问好必须是逐字出现.实际的书局由下面的行替换进去.
setBinaryStream 从一个字串里把一定数量的 字节转换成一个大对象,然后把其 OID 保存到那个保存指向它的引用的 字段里.请注意,在数据库里大对象本身的创建是透明的.

检索一幅图象甚至更容易(我在这里使用PreparedStatement, 当然用Statement也是一样的):

PreparedStatement ps = con.prepareStatement("SELECT oid FROM images WHERE name=?");
ps.setString(1, "myimage.gif");
ResultSet rs = ps.executeQuery();
if (rs != null) {
    while(rs.next()) {
        InputStream is = rs.getBinaryInputStream(1);
        // use the stream in some way here
        is.close();
    }
    rs.close();
}
ps.close();

这里你可以看到这里大对象是当做一个InputStream(输入流)检索的. 你还会注意到我们在处理结果的下一行之前关闭了流. 这是 JDBC 规范的一部分, 该规范指出任何返回的InputStream在调用 ResultSet.next()ResultSet.close() 后都要被关闭.