我正在编写一个Web服务,允许用户发布文件,然后在URL上检索它们(基本上将其视为RESTful Amazon S3).我遇到的问题是从我的Oracle查询返回一个byte [](Spring JDBC)我返回一个InputStream,然后以块的形式将数据流回客户端.这个(IMO)是一个更好的主意,因为我对文件没有任何大小限制,我不希望内存中有2GB字节数组.
起初它似乎运行正常,但我在重负载期间遇到了一个案例,有时在上一个servlet发送文件之前,Connection会被重用.似乎在返回InputStream的JDBC调用之后,Connection将返回到池(Spring将调用conn.close(),但不清除关联的ResultSet).因此,如果没有给出Connection的其他请求,则InputStream仍然有效并且可以从中读取,但是如果Connection被赋予新请求,那么InputStream将为null并且先前的请求将失败.
我的解决方案是创建一个InputStream的子类,它也将Connection作为构造函数arg,并且在重写的public close()方法中也关闭Connection.我不得不抛弃Spring JDBC并只进行正常的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
}
}
}
}
有没有人有更优雅的解决方案,或者看到我的解决方案有任何明显的问题?此代码也没有从我的实际代码中剪切/粘贴,所以如果有拼写错误就忽略它.
解决方法:
不幸的是,当你提出这个问题时,我的想象力很疯狂.我不知道这个解决方案是否更优雅.但是,这些类很简单且易于重复使用,因此如果它们不令人满意,您可能会发现它们的用途.你会看到最后一切都在一起……
public class BinaryCloseable implements Closeable {
private Closeable first;
private Closeable last;
public BinaryCloseable(Closeable first, Closeable last) {
this.first = first;
this.last = last;
}
@Override
public void close() throws IOException {
try {
first.close();
} finally {
last.close();
}
}
}
CompositeCloseable使用BinaryCloseable:
public class CompositeCloseable implements Closeable {
private Closeable target;
public CompositeCloseable(Closeable... closeables) {
target = new Closeable() { public void close(){} };
for (Closeable closeable : closeables) {
target = new BinaryCloseable(target, closeable);
}
}
@Override
public void close() throws IOException {
target.close();
}
}
ResultSetCloser关闭ResultSet对象:
public class ResultSetCloser implements Closeable {
private ResultSet resultSet;
public ResultSetCloser(ResultSet resultSet) {
this.resultSet = resultSet;
}
@Override
public void close() throws IOException {
try {
resultSet.close();
} catch (sqlException e) {
throw new IOException("Exception encountered while closing result set", e);
}
}
}
PreparedStatementCloser关闭PreparedStatement对象:
public class PreparedStatementCloser implements Closeable {
private PreparedStatement preparedStatement;
public PreparedStatementCloser(PreparedStatement preparedStatement) {
this.preparedStatement = preparedStatement;
}
@Override
public void close() throws IOException {
try {
preparedStatement.close();
} catch (sqlException e) {
throw new IOException("Exception encountered while closing prepared statement", e);
}
}
}
ConnectionCloser关闭Connection对象:
public class ConnectionCloser implements Closeable {
private Connection connection;
public ConnectionCloser(Connection connection) {
this.connection = connection;
}
@Override
public void close() throws IOException {
try {
connection.close();
} catch (sqlException e) {
throw new IOException("Exception encountered while closing connection", e);
}
}
}
我们现在将您原来的InputStream构思重构为:
public class ClosingInputStream extends InputStream {
private InputStream stream;
private Closeable closer;
public ClosingInputStream(InputStream stream, Closeable closer) {
this.stream = stream;
this.closer = closer;
}
// The other InputStream methods...
@Override
public void close() throws IOException {
closer.close();
}
}
最后,它们汇集在一起:
new ClosingInputStream(
stream,
new CompositeCloseable(
stream,
new ResultSetCloser(resultSet),
new PreparedStatementCloser(statement),
new ConnectionCloser(connection)
)
);
当调用此ClosingInputStream的close()方法时,实际上会发生这种情况(为清楚起见省略了异常处理):
public void close() {
try {
try {
try {
try {
// This is empty due to the first line in `CompositeCloseable`'s constructor
} finally {
stream.close();
}
} finally {
resultSet.close();
}
} finally {
preparedStatement.close();
}
} finally {
connection.close();
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。