微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

java – Spring JDBC连接池和InputStream结果

我正在编写一个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] 举报,一经查实,本站将立刻删除。

相关推荐