问题描述
- 项目中需要定时同步会员系统司机(会员)数据,为了简化开发,直接使用jdbcTemplate作为数据库连接;
- 项目测试时候一切正常,等到上线后,第二天IT支持反映问题说,司机表无法操作,紧急排查问题后发现是锁表了;
解决方案
- 根据数据库锁表的时间,以及业务,判断是新上线的定时任务导致的问题;
- 因为设计后的编码工作是交给实习生完成的,心里一下没底了,可能编码出现了问题,感觉自查编码逻辑:
// 获取连接
con = jdbcTemplate.getDataSource().getConnection();
// 执行SQL
jdbcTemplate.execute(sql.toString());
con.close();
代码逻辑部分只有一条更新的sql语句,因为jdbc默认是自动提交任务的,断点调试确认也是这样的,按道理不会造成死锁才对;
重复测试,压测一直都无法找到原因,然后电脑起着不动,吃饭后回来发现出现死锁的问题了,难道是起的时间长了才会出问题?
继续用多台电脑压测,多线程继续(其实生产只起了一个job任务实例);
此时任然找不到原因,迷茫中。。。
断点调试,发现程序跑了一段时间之后,连接的自动提交属性变为false了,冷静分析,应该是被别的程序改了,此时继续查别人的代码:
con = jdbcTemplate.getDataSource().getConnection();
con.setAutoCommit(false); // 关键在这里
jdbcTemplate.execute(DELETE_SQL);
String sql = getSql(DateUtils.format(new Date()), DateUtils.format(new Date()), getCurrentStartTime());
LOG.info("execute sql={}", sql);
jdbcTemplate.execute(sql);
con.commit();
con.close();
此时问题才算是找到了,分析问题导致的原因:
- 先看一下jdbcTemplate的配置
spring.datasource.url=${db.url}
spring.datasource.username=${db.user}
spring.datasource.password=${db.password}
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.test-on-borrow=true
spring.datasource.max-active=10
spring.datasource.validation-query=select 1
- spring.datasource.max-active=10参数说明默认最大是10个连接数;连接池是在使用时创建,用完归还连接,但是归还连接时连接的属性并不会变更,所以如果有其他程序改变了连接的默认属性,此时最好手动改回来;
- 解决方案:一、在自己不需要事务的业务代码中,可以在获取连接后,将autoCommit属性设置为true;
二、或者在自己手动更改过连接池属性后,如果多人开发公用此连接,最好是再改回默认设置;
方法一
// 获取连接
con = jdbcTemplate.getDataSource().getConnection();
if(!con.getAutoCommit()){
con.setAutoCommit(true); // 关键在这里
}
// 执行SQL
jdbcTemplate.execute(sql.toString());
con.close();
方法二
con = jdbcTemplate.getDataSource().getConnection();
con.setAutoCommit(false); // 关键在这里
jdbcTemplate.execute(DELETE_SQL);
String sql = getSql(DateUtils.format(new Date()), DateUtils.format(new Date()), getCurrentStartTime());
LOG.info("execute sql={}", sql);
jdbcTemplate.execute(sql);
con.commit();
con.setAutoCommit(true); // 关键在这里
con.close();