使用大对象

在 Postgres 里,大对象(也称之为 液滴(blobs) )用于保存那些无法在通常 SQL 表里面保存的数据.它们是通过表/索引对进行存储的,然后用一个 OID 值从你自己的表里面引用.
关键:对于 Postgres,你必须在一个 SQL 事务里面访问大对象。尽管我们总是这样要求,但直到版本 6.5 我们才严格要求这样做。你应该带着一个输入参数 false 使用 setAutoCommit() 方法打开一个事务:
Connection mycon;
...
mycon.setAutoCommit(false);
... now use Large Objects
现在,你有几种使用大对象的方法.第一种是标准的 JDBC 方式,这个方式在这里有文档.另一种,使用我们对该(JDBC)api (编程接口)的扩展,也是一种用于 Java 的 libpq 大对象 API 的形式,提供了一种比标准方法更好的访问大对象的访问方法.在系统内部,该驱动使用这种扩展来提供大对象支持.

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

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

create table images (imgname name,imgoid oid);
要插入一幅图象,你可以:
File file = new File("myimage.gif");
FileInputStream fis = new FileInputStream(file);
PreparedStatement ps = conn.prepareStatement("insert into images values (?,?)");
ps.setString(1,file.getName());
ps.setBinaryStream(2,fis,file.length());
ps.executeUpdate();
ps.close();
fis.close();
现在,在这个例子里,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() 后都要被关闭.