4.6.?存储二进制数据

UXDB提供两种不同的方法存储二进制数据。二进制数据可以使用二进制数据类型bytea存储在表中,或者使用大对象 特性,该特性以一种特殊的格式将二进制数据存储在一个独立的表中,然后通过在表中保存一个指向该表的类型为oid的数值来引用它。

为了判断哪种方法比较合适,必须理解每种方法的局限。

bytea数据类型并不适合存储非常大数量的二进制数据。虽然类型为bytea的字段可以存储最多1G字节的二进制数据, 但是这样它会要求数量巨大的内存来处理这样巨大的数值。存储二进制的大对象的方法更适合存储非常大的数值, 但也有自己的局限。特别是删除一个包含大对象引用的行并未删除大对象。 删除大对象是一个需要执行的独立的操作。大对象还有一些安全性的问题, 因为任何连接到数据库的人都可以查看或者更改大对象,即使他们没有查看/更新包含大对象引用的行的权限也一样。

版本7.2是第一个支持bytea类型的JDBC驱动版本。在7.2中引入的这个功能同时也引入了一个和以往的版本不同的行为。自7.2以来,方法getBytes(), setBytes(),getBinaryStream() 和setBinaryStream()操作bytea类型。 在7.1和更早的版本里这些方法操作和OID类型关联的大对象。 澳门游戏平台注册网站可以通过在Connection上设置compatible属性为数值7.1来获取旧的7.1的行为。

要使用bytea数据类型只需要使用getBytes(),setBytes(),getBinaryStream(),或者setBinaryStream()方法。

要使用大对象的功能,可以使用UXDB JDBC驱动提供的LargeObject类,或者使用getBLOB()和setBLOB()方法。

你必须在一次SQL事务内访问大对象。可以通过调用setAutoCommit(false)打开一个事务。

注意

在将来的JDBC驱动中,getBLOB()和setBLOB()方法可能不再操作大对象,而是将处理bytea数据类型。 因此如果要用大对象,建议使用LargeObject API。

在JDBC里处理二进制数据,假设有一个表包含一幅图像和它的文件名,并且在bytea字段里存储图像,示例如下:

CREATE TABLE images (imgname text, img bytea);

要插入一幅图象:

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()把来自一个流的一些数目的字节转换成类型bytea的字段。 如果图像的内容已经放在byte[]里面了,那么也可以使用setBytes()方法。

检索一幅图象使用的是PreparedStatement,也可以使用Statement。示例如下:

PreparedStatement ps = con.prepareStatement("SELECT img FROM images WHERE imgname = ?");
ps.setString(1, "myimage.gif");
ResultSet rs = ps.executeQuery();
if (rs != null) {
        while (rs.next()) {
                byte[] imgBytes = rs.getBytes(1);
                // 从这开始使用数据
                }
        rs.close();
}
ps.close();

这里的二进制数据是以byte[]形式检索的。也可以使用一个InputStream。另外可能会需要存储一个非常大的文件,因此希望使用LargeObject类存储该文件:

CREATE TABLE imageslo (imgname text, imgOID oid);

要插入一个图像,示例如下:

// 所有大对象 API 调用都必须在一次事务中
conn.setAutoCommit(false);

// 获取大对象管理器以便进行操作
LargeObjectManager lobj = ((org.UXDB.UXConnection)conn).getLargeObjectAPI();

//创建一个新的大对象
int oid = lobj.create(LargeObjectManager.READ | LargeObjectManager.WRITE);

//打开一个大对象进行写
LargeObject obj = lobj.open(oid, LargeObjectManager.WRITE);

// 现在打开文件
File file = new File("myimage.gif");
FileInputStream fis = new FileInputStream(file);

// 从文件拷贝数据到大对象
byte buf[] = new byte[2048];
int s, tl = 0;
while ((s = fis.read(buf, 0, 2048)) > 0){
      obj.write(buf, 0, s);
      tl += s;
}

// 关闭大对象
obj.close();

//现在向 imgeslo 插入行
PreparedStatement ps = conn.prepareStatement("INSERT INTO imageslO VALUES (?,?)");
ps.setString(1, file.getName());
ps.setInt(2, oid);
ps.executeUpdate();
ps.close();
fis.close();

从大对象中检索图像,示例如下:

// 所有 LargeObject API 调用都必须在一个事务里
conn.setAutoCommit(false);

// 获取大对象管理器以便进行操作
LargeObjectManager lobj = ((org.UXDB.UXConnection)conn).getLargeObjectAPI();

PreparedStatement ps = con.prepareStatement("SELECT imgoid FROM imageslO WHERE imgname = ?");
ps.setString(1, "myimage.gif");
ResultSet rs = ps.executeQuery();
if (rs != null) {
    while (rs.next()) {
      //打开大对象读
      int oid = rs.getInt(1);
      LargeObject obj = lobj.open(oid, LargeObjectManager.READ);

      //读取数据
      byte buf[] = new byte[obj.size()];
      obj.read(buf, 0, obj.size());
      //在这里对读取的数据做些处理

      // 关闭对象
      obj.close();
    }
    rs.close();
}
ps.close();
XML 地图 | Sitemap 地图