Java 连接未关闭

Java 连接未关闭,java,oracle,spring-boot,Java,Oracle,Spring Boot,我使用Java8运行SpringBoot2.0WebService。我必须使用PreparedStatement来处理CLOB,因此我必须创建自己的连接,而不是让Spring创建Oracle连接。然而,现在我似乎有一个连接泄漏,即使我在完成后关闭连接,并且在我运行我的Web服务3次(每次运行我泄漏3个连接)后,我得到了错误: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Conn

我使用Java8运行SpringBoot2.0WebService。我必须使用PreparedStatement来处理CLOB,因此我必须创建自己的连接,而不是让Spring创建Oracle连接。然而,现在我似乎有一个连接泄漏,即使我在完成后关闭连接,并且在我运行我的Web服务3次(每次运行我泄漏3个连接)后,我得到了错误:

 org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30002ms.
DEBUG - HikariPool-1 - Pool stats (total=10, active=9, idle=1, waiting=0)
因此,我在application.properties中添加了以下内容来定位泄漏:

spring.datasource.hikari.leakDetectionThreshold=2000
然后,我在第一次运行Web服务时出现以下错误:

java.lang.Exception: Apparent connection leak detected
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:128)
at com.clarivate.singularity.chemworkbench.dcrws.database.ReadFromDb.readStructureSearch(ReadFromDb.java:187)
给出误差的方法如下:

public class myClass(){
@Autowired
 NamedParameterJdbcTemplate  jdbcTemplate;  

@Transactional
public List<DcrData> readStructureSearch(String sqlStr,  String fileData) throws SQLException  {
    List<DcrData> dcrDataList = null;
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
try {
    conn =  this.jdbcTemplate.getJdbcTemplate().getDataSource().getConnection().unwrap(OracleConnection.class); // <<<< This is line 187 mentioned above which is giving the error
    Clob myClob =  conn.createClob();

    int ret = myClob.setString( 1, fileData);

    ps = conn.prepareStatement(sqlStr);
    ps.setClob(1,myClob);       // This works, Types.CLOB doesn't work.

    rs = ps.executeQuery();

    ResultSetHandler<List<DcrData>> handler = 
            new BeanListHandler<DcrData>(DcrData.class, new BasicRowProcessor(new GenerousBeanProcessor()));

    dcrDataList = handler.handle(rs);
    return  dcrDataList;
}finally {
    if (rs != null) {
        rs.close();
    }
    if (ps != null) {
        ps.close();
    }
    if (conn != null) {
        conn.close();
    }
    logger.info("DSxxx4");
}
}
公共类myClass(){
@自动连线
NamedParameterJdbcTemplate jdbcTemplate;
@交易的
公共列表readStructureSearch(字符串sqlStr,字符串fileData)抛出SQLException{
列表dcrDataList=null;
连接conn=null;
PreparedStatement ps=null;
结果集rs=null;
试一试{

conn=this.jdbcTemplate.getJdbcTemplate().getDataSource().getConnection().unwrap(OracleConnection.class);//我对函数正在执行的操作有点困惑。它似乎在CLOB上运行选择约束,但我可能弄错了。我在不知道的情况下重新创建问题时遇到了问题

也就是说,这里有一些东西需要尝试。首先,您不需要NamedParameterJdbcTemplate,只需要一个数据源。请尝试自动连接。其次,似乎没有理由获取原始Oracle连接本身,您可以直接使用数据源返回的连接。第三,try with resources模式生成代码更容易理解的Java将处理自动关闭资源的问题。它在Java8中可用。最后,释放CLOB可能会有所帮助

下面是我提到的一个例子:

public class MyClass {

    @Autowired
    DataSource dataSource;

    @Transactional
    public List<DcrData> readStructureSearch(String sqlStr, String fileData) throws SQLException {

        try (Connection conn = this.dataSource.getConnection()) {
            Clob myClob = conn.createClob();

            myClob.setString(1, fileData);

            try (PreparedStatement ps = conn.prepareStatement(sqlStr)) {
                ps.setClob(1, myClob);

                try (ResultSet rs = ps.executeQuery()) {
                    ResultSetHandler<List<DcrData>> handler =
                            new BeanListHandler<>(DcrData.class, new BasicRowProcessor(new GenerousBeanProcessor()));

                    List<DcrData> dcrDataList = handler.handle(rs);

                    myClob.free();

                    return dcrDataList;
                }
            }
        }
    }
}
公共类MyClass{
@自动连线
数据源数据源;
@交易的
公共列表readStructureSearch(字符串sqlStr,字符串fileData)抛出SQLException{
try(Connection conn=this.dataSource.getConnection()){
Clob myClob=conn.createClob();
myClob.setString(1,fileData);
try(PreparedStatement ps=conn.prepareStatement(sqlStr)){
ps.setClob(1,myClob);
try(ResultSet rs=ps.executeQuery()){
ResultSetHandler处理程序=
新的BeanListHandler(DcrData.class,新的BasicroProcessor(新的GranousBeanProcessor());
List dcrDataList=handler.handle(rs);
myClob.free();
返回dcrDataList;
}
}
}
}
}

考虑如果代码没有成功创建结果集会发生什么情况,
rs
将为null,
rs.close()
将抛出null指针异常,
conn.close()
将不会被调用。如前所述,您的
最终只会在成功操作后清理。@khelwood,谢谢,我用您的建议更新了问题,但错误仍然存在。自动连接数据源非常有效。谢谢@darrendanvers