Spring JDBC连接池和InputStream结果

甘道夫:

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

最初,它似乎工作正常,但是我遇到了一个负载很重的情况,有时在以前的servlet发送文件之前,Connection将被重用。似乎在JDBC调用返回InputStream之后,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
         }
      }
   }
} 

有谁有更优雅的解决方案,或者看到我的解决方案有任何明显的问题?此外,此代码不是从我的实际代码中剪切/粘贴的,因此,如果有错字,请忽略它。

亚当·佩恩特(Adam Paynter):

不幸的是,当你问这个问题时,我的想象力变得疯狂。我不知道这种解决方案是否被认为更优雅。但是,这些类很简单并且易于重用,因此如果它们不令人满意,您可能会发现它们的用途。您将在最后看到一切……

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

}

BinaryCloseable用于CompositeCloseable

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对象。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章