JavaSpringJDBC连接池和InputStream结果
我正在编写一个Web服务,它允许用户发布文件,然后通过URL检索它们(基本上可以将其视为RESTfulAmazonS3)。我遇到的问题不是从Oracle查询(Spring JDBC)返回一个字节[],而是返回一个InputStream,然后将数据分块流回到客户机。这(IMO)是一个更好的主意,因为我对文件没有大小限制,并且我不希望内存中有2GB字节数组
起初,它似乎工作得很好,但我在重载期间遇到了这样一种情况:有时在前一个servlet发送文件之前,连接会被重用。似乎在返回InputStream的JDBC调用之后,连接将返回到池(Spring将调用conn.close(),但不清除关联的ResultSet)。因此,如果没有为该连接提供其他请求,那么InputStream仍然有效并且可以从中读取,但是如果为新请求提供了连接,那么InputStream将为null,并且之前的请求将失败
我的解决方案是创建InputStream的子类,该子类也将连接作为构造函数arg,并且在重写的public close()方法中也关闭连接。我不得不放弃SpringJDBC,只做一个普通的PreparedStatement调用,否则Spring将始终返回到池的连接
public class ConnectionInputStream extends InputStream {
private Connection conn;
private InputStream stream;
public ConnectionInputStream(InputStream s, Connection c) {
conn = c;
stream = s;
}
// all InputStream methods call the same method on the variable stream
@Override
public void close() throws IOException {
try {
stream.close();
} catch (IOException ioex) {
//do something
} finally {
try {
conn.close();
} catch (SQLException sqlex) {
//ignore
}
}
}
}
有没有人有更优雅的解决方案,或者看到我的解决方案有什么突出的问题?此外,这段代码不是从我的实际代码中剪切/粘贴的,所以如果有输入错误,请忽略它
# 1 楼答案
在自己发布查询之前,为什么不从查询中读取整个
InputStream
/byte[]
/任何内容?这听起来像是在代码告诉Spring/池您已经完成了连接之后,您正在尝试从查询返回数据# 2 楼答案
另一种方法是使用回调。下面是一种想法
# 3 楼答案
不幸的是,当你问这个问题时,我的想象力失控了。我不知道这个解决方案是否更优雅。但是,这些类很简单,并且易于重用,因此如果不满意,您可能会找到它们的用途。最后你会看到所有的事情都在一起
BinaryCloseable
由CompositeCloseable
使用:ResultSetCloser
关闭ResultSet
对象:PreparedStatementCloser
关闭PreparedStatement
对象:ConnectionCloser
关闭Connection
对象:现在,我们将您最初的
InputStream
想法重构为:最后,这一切合在一起是:
当调用这个
ClosingInputStream
的close()
方法时,实际上会发生这种情况(为了清楚起见,省略了异常处理):您现在可以随意关闭任意多个
Closeable
对象