gpt4 book ai didi

java - Spring JDBC 连接池和 InputStream 结果

转载 作者:搜寻专家 更新时间:2023-11-01 03:14:52 25 4
gpt4 key购买 nike

我正在编写一个网络服务,允许用户发布文件,然后通过 URL 检索它们(基本上可以将其视为 RESTful Amazon S3)。我遇到的问题是从我的 Oracle 查询 (Spring JDBC) 返回一个字节 [] 我正在返回一个 InputStream,然后将数据以 block 的形式流回客户端。这 (IMO) 是一个更好的主意,因为我对文件没有大小限制,而且我不想在内存中使用 2GB 字节数组。

起初它似乎工作正常,但我在重负载期间遇到了一个案例,有时在前一个 servlet 可以发送文件之前,连接会被重用。似乎在返回 InputStream 的 JDBC 调用之后,Connection 将返回到池中(Spring 将调用 conn.close(),但不会清除关联的 ResultSet)。因此,如果没有其他请求给出 Connection,那么 InputStream 仍然有效并且可以从中读取,但是如果 Connection 被提供给新请求,那么 InputStream 将为 null,并且先前的请求将失败。

我的解决方案是创建一个 InputStream 的子类,它也将 Connection 作为构造函数参数,并在重写的 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();
}
}

}

BinaryCloseableCompositeCloseable 使用:

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)
)
);

当此 ClosingInputStreamclose() 方法被调用时,这实际上是发生了什么(为清楚起见省略了异常处理):

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();
}
}

您现在可以随意关闭任意数量的 Closeable 对象。

关于java - Spring JDBC 连接池和 InputStream 结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1246049/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com