我有以下场景:客户端正在将文件上传到服务器。该文件已存储
通过Hibernate进入Oracle数据库。直到最近,为该文件建模的实体具有byte[]
数组属性,用于对Blob进行建模。我们将其更改为InputStream
,因为我们不希望将整个文件放在服务器的RAM中。在不久的将来,我们希望更多用户上传更大的文件,因此RAM确实是一个问题。
我做了一些性能测试,到目前为止结果显示,与插入字节数组相比,流式传输速度大约慢1.8倍。以下是为10次迭代插入100MB文件的一些结果:
Method Mean Duration [ms] SD [ms]
---------------------------------------
Byte Array 10733.0 264.0
Streaming 18089.0 913.0
客户端和服务器之间的通信使用Spring RMI完成,二进制数据本身的流式传输使用RMIIO完成。由于使用了RMIIO,我们必须编写自己的Blobtype,从客户端解包二进制文件并将其推送到blob的二进制流中。你可以在下面看到这个代码。
到目前为止我所做的事情:
与插入字节数组相比,任何人都可以分享一些有关插入流的原因的深入见解吗?
我的配置:
带有字节数组的旧实体(插入更快):
@Entity
@Table(name = "MYBINARYOBJECT")
public class MyBinaryObject {
@Id
private Long id;
@Lob
private byte[] bytes;
}
带输入流的新实体(插入速度较慢):
@Entity
@Table(name = "MYBINARYSTREAMOBJECT")
public class MyBinaryStreamObject {
@Id
private Long id;
@Type(type = "MyBlobType")
private RemoteInputStream bytes;
}
我们的自定义Blob类型:
public class MyBlobType extends AbstractLobType {
@Override
protected Object nullSafeGetInternal(ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
throws SQLException, IOException, HibernateException {
RemoteInputStreamServer server = new GZIPRemoteInputStream(lobHandler.getBlobAsBinaryStream(rs, names[0]));
return server.export();
}
@Override
protected void nullSafeSetInternal(PreparedStatement ps, int index, Object value, LobCreator lobCreator)
throws SQLException, IOException, HibernateException {
BufferedInputStream stream = null;
try {
((RemoteInputStream) value).available();
stream = new BufferedInputStream(
RemoteInputStreamClient.wrap((RemoteInputStream) value, RemoteRetry.NEVER), 16384);
lobCreator.setBlobAsBinaryStream(ps, index, stream, -1);
} catch (IllegalArgumentException e) {
throw new MyStreamingException();
}
}
}