离线投入产出统计异常
org.springframework.dao.RecoverableDataAccessException:
Error updating database. Cause: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
The last packet successfully received from the server was 593,387 milliseconds ago. The last packet sent successfully to the server was 593,388 milliseconds ago.
The error may involve defaultParameterMap
The error occurred while setting parameters
SQL: INSERT INTO XXX
背景:
离线投入产出统计定时任务, 每十分钟一次统计并更新数据库, 但一天会偶发报七八次该错误.
异常字面意思是数据库连接失败, 上次成功接收到数据库消息:593,387 milliseconds 以前,
最开始是以为是数据库链接问题, 修改数据库连接池配置, 增加固定线程数, 增大线程空闲回收时间, 增加keep-alive配置, 发现仍然会发生该异常
后来观察每次失败时, 都有一个特点, 这一次的定时任务执行时间很长, 而且因为失败,还没执行完.
ps : 正常一个任务4分钟左右跑完, 失败的任务, 7分多钟, 只执行了三分之一的代码, 然后报错.
后来怀疑是数据库死锁问题,
联系DBA 果然有死锁日志, 沿着这个思路, 发现有个rocketMQ消息处理时, 也会异步批量的更新该表的数据库, 定位对应的日志, 确实在数据库报错的时间点, 有死锁日志,
最终结论
定时任务, 处理时间太长, 对部分数据加锁更新后, 事务没有提交, 这时mq处理发生了并发, 锁住了其他部分字段, 导致数据库死锁, 数据库检测到定时任务加的行锁较少,回滚mq事务, 定时任务继续执行, 但由于定时任务该sql执行时间较长(被数据库LVS层断开了(我们公司默认4分钟自动断开))
修复:
增加分布式锁, 避免数据库死锁.