【问题标题】:Insertion of BLOB fails with the file being NULL插入 BLOB 失败,文件为 NULL
【发布时间】:2014-08-07 18:18:48
【问题描述】:

在 Java 中,我尝试使用 JDBC 在 Oracle 数据库表的 BLOB 列中插入文件。

我是这样进行的:

private Statement getStatement(File f, String fid, Long dex, String uid, int id)
{
  FileInputStream fis = null;
  PreparedStatement statement;
  try
  {
    statement = connection.prepareStatement("INSERT INTO BLOBTABLE (FID, FDEX, SFILE, UID, ID) VALUES (?, ?, ?, ?, ?)");
    statement.setString(1, fid);
    statement.setLong(2, dex);
    fis = new FileInputStream(file);
    statement.setBinaryStream(3, fis, file.length());
    statement.setString(4, uid);
    statement.setInt(5, id);
  }
  finally
  {
    if (fis != null)
      fis.close();
  }
  return statement;
}

private insertStuff()
{
  File f = new File("/home/user/thisFileExists");
  PreparedStatement statement = getStatement(f, "XYZ", 18L, "ABC", 78);
  statement.execute();
}

当 .execute 运行时,我得到一个 Oracle 错误:

java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot insert NULL into ("ORACLEUSER"."BLOBTABLE"."SFILE")

SFILE 是 BLOB 列。所以这意味着链末端的数据库在查询中接收到 NULL。

怎么会?

如果我替换:

statement.setBinaryStream(3, fis, file.length());

与:

statement.setBinaryStream(3, new ByteArrayInputStream(("RANDOMSTRING".getBytes())));

它可以工作,所以 it 不知何故不喜欢我的文件流。

我关闭流有问题吗?这就是他们在我看到的所有样本上的做法。

【问题讨论】:

  • BLOB类型列的情况下插入''一个空字符串而不是null
  • 除此之外 - 不需要if (null != stream) 的“尤达条件”。只需使用if (stream != null),大多数人会发现它更具可读性。

标签: java oracle jdbc blob


【解决方案1】:

您在执行语句之前关闭了FileInputStream,因此语句无法在实际需要时获取数据。最好将InputStream 传递到您的方法中,这样您就可以在语句执行后在外部关闭它:

private insertStuff() {
    File file = new File("/home/user/thisFileExists");
    try (InputStream stream = new FileInputStream(file)) {
        PreparedStatement statement = getStatement(stream, "XYZ", 18L, "ABC", 78);
        statement.execute();
    }
}

... 其中getStatement 将接受InputStream 而不是File,并使用不占用数据长度的setBinaryStream 的重载。或者,您可以传入File,它可以打开流、创建语句、执行语句,然后关闭流。

附带说明,您也应该使用 try-with-resource 或 try/finally 语句来关闭语句。

【讨论】:

  • 传递长度并不是必须的:当使用setBinaryStream(int, InputStream) 时,只传递流就足够了
  • 是的,在执行之前不再关闭流可以防止插入整体失败,但它会插入一个 0 字节的 BLOB,这并不好,...
  • @tisek:那听起来像是一个单独的问题。你确定你没有从你传入的流中读取吗?这是我能想到的唯一解释。您可能想用一个简短但完整的新代码示例提出一个新问题,以演示该问题 - 当然,为了简单起见,所有这些都可以在一个方法中。不需要单独的课程。 Stack Overflow 不能很好地处理随时间演变的问题。
【解决方案2】:

您在数据库使用之前关闭了FileInputStream。允许 JDBC 驱动程序将流的消耗推迟到实际执行。

另请注意,您与固定字符串的测试比较并不完全公平:它不是同一个方法重载,因此可能一个有效而另一个无效(尽管这里不是这种情况)。

【讨论】:

    猜你喜欢
    • 2016-11-18
    • 2013-07-06
    • 1970-01-01
    • 2019-09-25
    • 1970-01-01
    • 2018-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多