HikariPool-1 - Connection is not available

 

在springboot项目中出现一个问题,该问题从字面意思上说是数据链池链接资源已全部使用完毕,没有可用的链接使用

排查问题发现原因是:

  sql由于参数填写错误,进行了全表扫描,由于返回数据量过大导致数据卡在映射层,导致资源卡死的情况,每调用一次就会损失一个链接资源,当所有链接资源都使用完毕时候,就出现以上的情况。

  所以在写sql时一定要注意分页处理,避免这种情况。

  

导致卡死 分为两种情况

  第一种是 卡在数据库层 : 就是当前执行的sql过去复杂又没有索引,一直处于在运行状态没有结果返回。

  第二种是 卡住程序映射层 : 就是数据量过大,数据库里面的大量数据映射到程序中这个过程过去长,而jdbc本身又没有处理这种情况的方式。

 

我们以spring 提供的 JdbcTemplate 为列

第一种解决方案

设置jdbc自带的queryTimeOut() 的方法,在一定时间内未返回数据 就自动断开链接释放资源。

 

第二种解决方案

jdbc本身没有处理这种情况的能力,会一直等待响应,我们需要重写他们的方法,设定一定时间,如果超过这个时间还没有返回数据出来,就手动抛出异常,释放链接资源

 

关键代码

//需要其他方法时,自行重写
public class JdbcTemplateWapper extends JdbcTemplate {

    /**
     * 查询超时时间
     */
    public static int queryTimeout = 30;
    //数据读取超时时间 ms
    public static long readTimeOut = 10000;//ms
    
    private final JdbcTemplate jdbcTemplate;
    
    
    public JdbcTemplateWapper(JdbcTemplate jdbcTemplate){
        this.jdbcTemplate = jdbcTemplate;
        this.jdbcTemplate.setQueryTimeout(queryTimeout);
    }


    @Override
    public <T> List<T> queryForList(String sql, Class<T> elementType) throws DataAccessException {
        return jdbcTemplate.query(sql, new SingleColumnRowMapperWapper(elementType));
    }

    @Override
    public List<Map<String, Object>> queryForList(String sql) throws DataAccessException {
        return jdbcTemplate.query(sql, new ColumnMapRowMapperWapper());
    }

    @Override
    public List<Map<String, Object>> queryForList(String sql, Object... args) throws DataAccessException {
        return jdbcTemplate.query(sql, args, new ColumnMapRowMapperWapper());
    }

    public Map<String, Object> queryForMap(String sql, @Nullable Object... args) throws DataAccessException {
        return result(jdbcTemplate.queryForObject(sql, args, new ColumnMapRowMapperWapper()));
    }

    @Override
    public Map<String, Object> queryForMap(String sql) throws DataAccessException {
        return result(jdbcTemplate.queryForObject(sql, new ColumnMapRowMapperWapper()));
    }

    private static <T> T result(@Nullable T result) {
        Assert.state(result != null, "No result");
        return result;
    }



    public class ColumnMapRowMapperWapper extends ColumnMapRowMapper{
        long startDate = 0l;
        @Override
        protected Object getColumnValue(ResultSet rs, int index) throws SQLException {
            if(startDate <= 0l) startDate = new Date().getTime();//记录第一次读取的时间 为开始时间
            if(startDate+readTimeOut < System.currentTimeMillis()) throw new SQLException("数据读取超时");
            return super.getColumnValue(rs, index);
        }
    }

    public class SingleColumnRowMapperWapper<T> extends SingleColumnRowMapper<T>{

        SingleColumnRowMapperWapper(Class<T> requiredType){
            super(requiredType);
        }

        long startDate = 0l;
        @Override
        public T mapRow(ResultSet rs, int rowNum) throws SQLException {
            if(startDate <= 0l) startDate = new Date().getTime();//记录第一次读取的时间 为开始时间
            else if(startDate+readTimeOut < System.currentTimeMillis()) throw new SQLException("数据读取超时");
            return super.mapRow(rs, rowNum);
        }
    }


}

  

posted @ 2023-07-04 16:54  lanwf  阅读(1244)  评论(0编辑  收藏  举报