使用数据库连接池报异常too many connection

背景

用servlet+jsp+mysql开发一个练手项目在线商城,dao层选用HikariDP连接池作为数据源,网页前端点一点,刷新几次之后,即进行几次数据库操作之后,就会报错too many connection
报错信息

解决思路

报这个错误意思是连接数过多,我们都知道,连接数据库获取的连接数是有上限的,虽然上限可以设置,但是就我这么小的小项目,mysql不至于顶不住啊?另外,所有的获取连接操作,我都是try-with-resource代码块实现的,也就是说,所有获取的connection,在使用之后都正常释放了。那么问题点可能出现在三部分:

  • try-with-resource代码没有正确释放connection
  • 数据库连接池配置的连接数太少,不够支撑我们的项目
  • mysql达到连接数上限

求证

1.针对try-with-resource是否正确释放connection问题,查了资料理论上来讲应该是可以释放connection回到连接池的,连接池已经实现了AutoCloseable接口。
为了求证,我把try-with-resource代码修改成传统的try catch finally进行测试,结果还是失败,说明问题不出在这。
2.数据库连接池是否有问题?我把连接池去掉,直接采用传统的DriverManager获取连接,发现,问题解决了!说明问题一定出在连接池这里!我一度认为,是因为数据库连接池配置的最大连接数太小了,虽然这和理论不符合,因为我的这个项目,最多同时也就七八个连接!下面是我的连接池配置代码。

public class DataSourceUtil {
    ...此处省略字符串常量
    public static Connection getConn() throws SQLException {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(DB_URL);
        config.setUsername(USER);
        config.setPassword(PASS);
        config.addDataSourceProperty("connectionTimeout", "1000"); // 连接超时 1s
        config.addDataSourceProperty("idleTimeout", "60000"); // 空闲超时 60s
        config.addDataSourceProperty("maximumPoolSize" , "10"); // 最大连接数 10
        return new HikariDataSource(config).getConnection();
    }
}

我调整了连接池的最大连接数为100,空闲超时为6秒,因为如果一个connection即使没被正确释放,空闲超过6秒也会被释放。经过实验发现,还是不行,说明,连接池配置没问题,这和我理论上的预期也是一致的!

3.那都没问题?出鬼了吗,去mysql看看,我通过终端连接到mysql后,通过命令show processlist;查看当前数据库的连接情况
这个是正常情况的连接数正常情况的连接
启动项目后查看:好家伙,怎么这么多连接,即使是连接池,也应该只拿到10个连接才对,现在直接整了32个。
启动项目后
点一点项目中的功能后查看:我直接看傻了,为什么创建了153个连接,按理说1个数据库连接池拿到10个连接后,就会一直使用这10个,不会再申请了,真相只有一个!就是创建了多个数据库连接池!!
崩溃的情况
仔细分析下上面的代码可以发现:

return new HikariDataSource(config).getConnection();

这行代码是原罪…就是每调用一次getConn()方法都会new一个HikariDataSource,当然就会在mysql创建好多好多个连接,直到达到mysql的最大连接数!导致报错。

解决

数据库连接池对象只创建一个

public class DataSourceUtil {
    // 注册驱动
    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    // 数据库 URL
    static final String DB_URL = "jdbc:mysql://localhost:3306/online_mall?useUnicode=true&characterEncoding=utf8";
    // 数据库的用户名与密码,需要根据自己数据库的值设置
    static final String USER = "root";
    static final String PASS = "12345678";

    static final HikariDataSource DATA_SOURCE = getDataSource();

    public static HikariDataSource getDataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(DB_URL);
        config.setUsername(USER);
        config.setPassword(PASS);
        config.addDataSourceProperty("connectionTimeout", "1000"); // 连接超时 1s
        config.addDataSourceProperty("idleTimeout", "60000"); // 空闲超时 6s
        config.addDataSourceProperty("maximumPoolSize" , "10"); // 最大连接数 100
        return new HikariDataSource(config);
    }

    public static Connection getConn() throws SQLException {
        return DATA_SOURCE.getConnection();
    }
}

现在无论调用网页中怎么操作,连接都能正常获取和释放了,说明问题就出在这,现在再去查看一下Mysql连接的情况:
正常情况
这就对了!符合预期!问题解决!

总结与反思

1.这个问题的原因是多么基本,多么简单,我本意是想封装一个getConn()方法,使用了错误的代码逻辑导致问题出现。
2.解决类似问题的思路就是肯定是连接数超过配置的值了,至于为什么超过,原因有很多,可能是代码问题、可能是conn使用后没有正确的释放,当然也可能是业务规模增加,mysql已经不支持如此大量的业务了。总之,这个问题出现的原因必然是conn数量过多,这也体现了对于昂贵资源的合理使用与释放的重要性!
3.数据库连接池拿到的连接在不用的时候,状态都是sleep的。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值