我是靠谱客的博主 潇洒外套,最近开发中收集的这篇文章主要介绍使用数据库连接池报异常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的。

最后

以上就是潇洒外套为你收集整理的使用数据库连接池报异常too many connection的全部内容,希望文章能够帮你解决使用数据库连接池报异常too many connection所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部