跳转至

存储二进制数据

存储二进制数据

SeaboxSQL™提供了两种不同的方式来存储二进制数据。可以使用数据类型BYTEA或使用大对象功能将二进制数据存储在表中,后者将二进制数据以特殊格式存储在单独的表中,并通过在表中存储OID类型的值来引用该表。

为了确定哪种方法合适,您需要了解每种方法的局限性。 BYTEA数据类型不太适合存储非常大量的二进制数据。虽然BYTEA类型的列最多可以容纳1 GB的二进制数据,但它需要大量的内存才能处理如此大数据。大对象方法更适合于存储数量非常大的二进制,但是它有其自身的局限性。删除带有大对象引用的行不会删除大对象。删除大对象需要执行额外的单独操作。大对象还存在一些安全问题,因为所有连接到数据库的人都可以查看和/或修改任何大对象,即使他们没有查看/更新包含大对象引用的行的权限。

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

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

重要

您必须在SQL事务块内访问大型对象。您可以通过调用setAutoCommit(false)来启动事务块。

示例 在JDBC中处理二进制数据包含一些有关如何使用SeaboxSQL™JDBC驱动程序处理二进制数据的示例。

示例 在JDBC中处理二进制数据

例如,假设您有一个包含图像文件名的表,并且还想将图像存储在BYTEA列中:

CREATE TABLE images (imgname text, img bytea);
为了插入图像你需要
FileInputStream fis = new FileInputStream(file);
PreparedStatement ps = conn.prepareStatement("INSERT INTO images VALUES (?, ?)");
ps.setString(1, file.getName());
ps.setBinaryStream(2, fis, (int)file.length());
ps.executeUpdate();
ps.close();
fis.close();

在这里,setBinaryStream()将流中一定数量的字节传输到BYTEA类型的列中。 如果图像的内容已经在byte[]中,则也可以使用setBytes()方法完成此操作。

注意

setBinaryStream的length参数必须正确,无法指示未知的流长度。 如果处于这种情况,则必须将流自己读取到临时存储中并确定其长度。 然后,可以用正确的长度将数据从临时存储发送到驱动程序。

从数据库中恢复图像更加容易。在这里使用PreparedStatement,但同样可以使用Statement类。

PreparedStatement ps = conn.prepareStatement("SELECT img FROM images WHERE imgname = ?");
ps.setString(1, "myimage.gif");
ResultSet rs = ps.executeQuery();
while (rs.next())
{
    byte[] imgBytes = rs.getBytes(1);
    // use the data in some way here }
rs.close();
ps.close();

二进制数据以byte[]的形式检索。 也可以改用InputStream对象。

另外,可能要存储一个非常大的文件,并希望使用LargeObject API来存储该文件:

CREATE TABLE imageslo (imgname text, imgoid oid);
插入数据
// All LargeObject API calls must be within a transaction block
conn.setAutoCommit(false);

// Get the Large Object Manager to perform operations with
LargeObjectManager lobj = conn.unwrap(com.seaboxsql.SDConnection.class).getLargeObjectAPI();

// Create a new large object
long oid = lobj.createLO(LargeObjectManager.READ | LargeObjectManager.WRITE);

// Open the large object for writing
LargeObject obj = lobj.open(oid, LargeObjectManager.WRITE);

// Now open the file
File file = new File("myimage.gif");FileInputStream fis = new FileInputStream(file);

// Copy the data from the file to the large object
byte buf[] = new byte[2048];
int s, tl = 0;
while ((s = fis.read(buf, 0, 2048)) > 0)
{
    obj.write(buf, 0, s);
    tl += s;
}

// Close the large object
obj.close();

// Now insert the row into imageslo
PreparedStatement ps = conn.prepareStatement("INSERT INTO imageslo VALUES (?, ?)");
ps.setString(1, file.getName());
ps.setLong(2, oid);
ps.executeUpdate();
ps.close();
fis.close();

// Finally, commit the transaction.
conn.commit();
从大对象恢复图像
// All LargeObject API calls must be within a transaction block
conn.setAutoCommit(false);

// Get the Large Object Manager to perform operations with
LargeObjectManager lobj = conn.unwrap(com.seaboxsql.SDConnection.class).getLargeObjectAPI();

PreparedStatement ps = conn.prepareStatement("SELECT imgoid FROM imageslo WHERE imgname = ?");
ps.setString(1, "myimage.gif");
ResultSet rs = ps.executeQuery();
while (rs.next())
{
    // Open the large object for reading
    long oid = rs.getLong(1);
    LargeObject obj = lobj.open(oid, LargeObjectManager.READ);

    // Read the data
    byte buf[] = new byte[obj.size()];
    obj.read(buf, 0, obj.size());
    // Do something with the data read here

    // Close the object
    obj.close();
}
rs.close();
ps.close();

// Finally, commit the transaction.
conn.commit();