今天在测试WebFast代码的过程中发现在网站的链接上单击若干次后,网站不响应了,目前开发的功能都十分简单,没有用到特别复杂的用法,怎么会造成网站无法响应的问题呢?

打开应用程序后台发现日志中大量输出如下SQL语句:

2021-12-24 12:40:00.873 DEBUG 1352 --- [io-8080-exec-38] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL query
2021-12-24 12:40:00.873 DEBUG 1352 --- [io-8080-exec-38] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [SELECT * FROM app_user WHERE username = ?]

这大量的用户信息访问主要是Shiro授权需要的,于是想是不是Shiro没有设置缓存造成了大量数据库访问没有释放数据源连接造成的,这个问题以前没有遇到过,果然过了一段时间后台输出了如下提示:

com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60011, active 20, maxActive 20, creating 0

已经看出来了是数据源连接池耗尽的提示,阿里的Druid数据源以前没有使用过,这次用就发生了问题于是就认为Shiro与阿里的数据源结合使用会出现这样不知道原因的怪问题,这下可麻烦了,然后在网上查了大量的相关内容都没有给出线索,由于我的数据库访问使用的SpringJDBC,继而想是不是jdbcTemplate操作会不释放数据库连接,但显然答案是否定的,SpringJDBC用了很长时间都没有出现这种占用连接的情况,于是这种情况排除了, 那就是Shiro没有缓存效率不高产生的问题,于是立即给Shrio加上一个简易的内存缓存,JavaConfig配置如下:

@Bean
public CacheManager shiroCacheManager() {
    return new MemoryConstrainedCacheManager();
}

@Bean
public DefaultWebSecurityManager securityManager(UserRealm userRealm, CacheManager cacheManager) {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    securityManager.setRealm(userRealm);
    securityManager.setCacheManager(cacheManager);
    securityManager.setSessionManager(mySessionManager());
    return securityManager;
}

在加入了缓存之后果然Shiro不再产生大量的SQL语句访问了,WebFast应用响应也好像不再卡壳了,难道真的是Shiro没有缓存的问题,再进一步测试,再一次单击到显示系统配置信息的页面,该页面会显示数据库的类型和版本信息,多次测试后发现该页面中的内容不能正常显示了,这里肯定有问题,于是打开处理这个页面的代码,看到如下代码片断:

if (dataSource != null) {
    try {
        Connection conn = dataSource.getConnection();
        DatabaseMetaData md = conn.getMetaData();
        model.addAttribute("dbinfo", md.getDatabaseProductName() + " " + md.getDatabaseProductVersion());
        model.addAttribute("driverinfo", md.getDriverName() + " " + md.getDriverVersion());
    } catch (Exception e) {
        // noops.
    }
}

 啊!!!一段陈年老代码,Connection获取之后竟然没有close。原因找到了,这个错误犯的太低级了,如果不是偶然发现这个Bug可能就会一直隐藏下去。花了一个上午外加中午的吃饭时间找到了这个问题的根源,那就记录一下吧。