【问题标题】:Hibernate 4.2.2 create blob from unknown-length input streamHibernate 4.2.2 从未知长度的输入流创建 blob
【发布时间】:2013-11-23 08:50:31
【问题描述】:

您好,我想在休眠状态下从输入流创建一个 blob,但我不知道流的长度。

Hibernate.getLobCreator(sessionFactory.getCurrentSession()).createBlob(stream, length)

如何在不知道流长度的情况下创建 blob?

编辑1

在旧的休眠版本中是可能的

http://viralpatel.net/blogs/tutorial-save-get-blob-object-spring-3-mvc-hibernate/

Blob blob = Hibernate.createBlob(file.getInputStream());

EDIT2

好的,但它有一个错误的实现

return new SerializableBlob(new BlobImpl(stream, stream.available()));

stream.available 不是实际大小

编辑 3

我试过了

session.doWork(new Work() {
            @Override
            public void execute(Connection conn) throws SQLException {
            LargeObjectManager lobj = ((org.postgresql.PGConnection) conn).getLargeObjectAPI();

但 conn 只是来自 c3p0 的 NewProxyConnection。

【问题讨论】:

  • 加载它一个数组,用 ByteInputStream 包装数组并使用数组的长度作为第二个参数。
  • 我只是将其更改为流,因为我想处理大量数据而不将其读取到内存中
  • 将大量数据作为 blob 保存在数据库中真的是最好的方法吗?将它们保存到文件然后将文件路径保存在数据库中不是更容易更快吗?
  • 这是另一个问题 ;) ...不是我的...但是复制代表了这种方法
  • 您始终可以使用普通 Hibernate 保存记录,但将 blob 列保留为 NULL,然后使用低级 JDBC 设置 blob 列。作为一种解决方法,不应该出现其他任何东西(我个人认为这是适合设计的实际解决方案,而不是解决方法)。 docs.oracle.com/javase/tutorial/jdbc/basics/blob.html

标签: java hibernate stream blob


【解决方案1】:

这是我现在使用的

Session currentSession = getSessionFactory().getCurrentSession();
Blob blob = Hibernate.getLobCreator(currentSession).createBlob(new byte[0]);
OutputStream setBinaryStream = blob.setBinaryStream(1);
Utils.fastChannelCopy(input, setBinaryStream);
setBinaryStream.close();

【讨论】:

  • 什么是 Utils.fastChannelCopy ?
  • 只是一个自定义的utils函数来复制一个流,你可以使用apache的ioutils
【解决方案2】:

尝试传入InputStream,长度为-1:

session.getLobHelper().createBlob(stream, -1);

这适用于 SQL Server 2008。似乎 Hibernate 将此值直接传递给 JDBC 驱动程序,因此这可能会或可能不会工作,具体取决于您的数据库驱动程序。

注意:如果我传入了不正确的流长度(包括0),我会从Hibernate中得到一个DataException(来自驱动程序:“com.microsoft.sqlserver.jdbc.SQLServerException: The stream value is not the specified length.指定长度为 10,实际长度为 13.")。长度为-1,一直运行不报错,数据成功保存到数据库中。

【讨论】:

  • HSQL 不喜欢这样:`org.hsqldb.HsqlException: JDBC 调用中的参数无效:长度:-1`
  • 因为 PostgreSQL 9.4 这应该可以工作:jdbc.postgresql.org/documentation/…
  • 有人使用 Postgres 成功了吗?
【解决方案3】:

解决方法可能是将输入流保存到文件中,然后将文件读入 blob。

【讨论】:

  • 这是少数几个真正有意义的答案之一
【解决方案4】:

我知道我的回答与您的问题有些不同。但这可能会帮助其他登陆这里的人。根据我的要求,我将绝对文件路径作为创建 blob 的输入。如果你也有类似的需求,可以使用下面的sn-p。

Session session = sessionFactory.getCurrentSession();
File file = new File(filePath);
Blob blob = Hibernate.getLobCreator(session).createBlob(new FileInputStream(file), file.length());

file.length() 会给你文件的长度。

【讨论】:

  • 这是可能的解决方案,将未知长度的流写入临时文件并使用 FileInputStream(现在已知大小)
【解决方案5】:

如下改变Dao中的保存方式

@Transactional
public void save(Document document, InputStream inputStream) throws IOException {
    Session session = sessionFactory.getCurrentSession();
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();

    int nRead;
    byte[] data = new byte[16384];

    while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
        buffer.write(data, 0, nRead);
    }

    buffer.flush();
    Blob blob = Hibernate.getLobCreator(session).createBlob(buffer.toByteArray());
    document.setContent(blob);
    session.save(document);
}

【讨论】:

  • 这不是一个解决方案,ByteArrayOutputStream 缓冲了 RAM 中的所有数据。我想避免这种情况
  • 仅使用 byte[] 而不是 ByteArrayOutputStream int expected = inputStream.available();字节 [] 内容 = 新字节 [预期]; int 长度 = inputStream.read(内容); if(length != expected) throw new IOException("Could not read full input");
  • 这不仅将所有内容读入内存,而且过于复杂
【解决方案6】:

我认为,这是一个 goog 解决方案,如果您将 InputStream 转换为字节数组,那么您可以使用 createBlob 方法,该方法接受字节数组而不是 InputStream 和长度作为参数。 对于转换,您可以使用 Apache Commons IO 中的 IOUtils。

Hibernate.getLobCreator(sessionFactory.getCurrentSession()).createBlob(IOUtils.toByteArray(stream)); 

【讨论】:

  • 这违背了流媒体的目的:/
猜你喜欢
  • 2016-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多