何时可以安全地关闭PreparedStatement.setBlob使用的InputStream?

3
PreparedStatement.setBlob方法、PreparedStatement.setBinaryStream方法以及一些其他的PreparedStatement方法能够从InputStream中读取查询所需的数据。很可惜,文档并没有说明在何时数据被读取。它只是简单地说明了:

将会根据需要从流中读取数据,直到达到文件结尾。

我可以想到三种可能的解释来说明数据在何时被需要:
  • 在调用setBlob(或其他具有InputStream参数的方法)返回之前
  • 当语句被执行时
  • 当事务提交时
那么,在何时关闭InputStream(或其他相关InputStream依赖资源)才是安全的?这是否取决于驱动程序(目前我正在使用MySQL,但考虑到迁移的可能性,也许了解其他驱动程序如何处理此问题也是好的)。

顺便提一下,我的代码目前假设流在语句执行后可以关闭,并且似乎正常工作,但我不知道如何确保它总是有效的。 - Jules
1个回答

2

我写了一个快速示例来测试本地MySQL(请原谅糟糕的异常处理):

public void testInputStream(String filePath) throws SQLException, IOException {
    DBUtil util = new DBUtil();//just a simple connection util
    Connection conn = util.getConnection("test");

    conn.setAutoCommit(false);

    File file = new File(filePath);
    FileInputStream fis = null;

    fis = new FileInputStream(file);

    String sql = "insert into testtable(scol,lob) values(?,?)";
    PreparedStatement stmt = conn.prepareStatement(sql);
    stmt.setString(1, "number4!");
    stmt.setBlob(2, fis);
    //fis.close() //this throws an exception
    stmt.executeUpdate();
    fis.close();//no exception here
    conn.commit();
    //fis.close();//no exception when called here
    stmt.close();
}

testtable是一个非常简单的表格:

create table testtable (
    id int auto_increment primary key,
    scol varchar(50),
    lob blob
)engine=innodb;

在我的测试中,执行语句后似乎是正确答案。虽然在不同的驱动程序中可能会有所不同,但我认为在查询执行之前关闭InputStream不会起作用。通过查看MySQL的PreparedStatement源代码,它看起来非常简单; 它需要打开流以调用sendPacket()(实际执行操作的底层方法),但在完成executeUpdate()后,流对象似乎处于空闲状态。
我认为您可以安全地假设这种行为在几乎所有实现JDBC规范的驱动程序中都是一致的。可能会有一些例外情况,但如果它们支持InputStream,则应以相同的方式工作。

它目前看起来确实可以工作,但我的问题更多是“我可以安全地假设特定的答案吗?”例如,我担心将来的JDBC驱动程序更新或DBMS更改会破坏代码。我希望有一些行为规范在API Javadoc之外指定了,但我可能错过了。 - Jules

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接