九天猎人 发表于 2025-6-12 20:44:43

com.mysql.cj.jdbc.exceptions.CommunicationsException Communications link failure

前言:

一般这个报错大多是网络原因导致的,确保你不是网络题目再往下看
题目

在一个方法上(该方法非常复杂执行时间长)加了 @Transactional(rollbackFor = Exception.class)后出现了如下图所示的错误
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvODZlNGQ4YzNlNTI0NDYzNzkzZDUzNzA3NzUzZjRmZmIucG5n
解决:

颠末排查并非网络题目。复现时,在数据库执行show processlist;发现出现了很多存在时间非常长的锁(非死锁),那么大概率是因为数据库连接池的连接数不敷导致的数据库连接失败中断。在长事务中每次进行数据库操作都要占用连接数,并且因为事务没有提交的原因,不停没有释放连接。细化事务的范围即可(不包管整个过程一致)
比如你的主方法在A类,调用了B类的方法,就别在A类方法上加事务注解,而是在B类被调用的上方法加。假如A类调用B类方法是多次调用的话(比如循环),那么他会在B类开启你循环次数个事务,每个事务独立。例如你调用了100次,前99次全成功,末了一次失败,他是不会回滚前99次的操作的,而是会回滚你第100次的操作。
扩展表明:

@Override
public void B() {
    // 操作数据库的方法
}

@Transactional(rollbackFor = Exception.class)
public void A(List<String> strs) {
    for (String s: strs) {
      B();
    }
}

@Override
@Transactional(rollbackFor = Exception.class)
public void B() {
    // 操作数据库的方法
}

public void A(List<String> strs) {
    for (String s: strs) {
      B();
    }
}
第一段代码中只会启动一个事务,在循环的数据库操作还未全部完成之前(事务未提交)会不停占用连接池,第二段代码中,会启动strs集合大小个事务,遍历完一个元素便提交一次事务。假如两个方法都加注解,子方法启动事务的时候会判断上一层有没有事务,假如有那么会加入到上一层事务管理,而不是自己启一个事务 。这就涉及到事务的传播特性了
2024.1.04补充

在调试一个复杂的导出时,又出现了Communications link failure的错误,第一反应就是sql执行时间太长凌驾了druid设置的maxwait(获取连接等候超时时间)。
分析sql,执行 explain 你的sql 。id为执行优先级,数值一样则从上到下执行。其他参数我就不表明了,网上都有(搜索explain各个参数的意义),主要看table(表别名)、type(扫描类型,不要看到all就觉得很影响性能,其实表小的话不走索引反而更快)、row(预估扫描条数,假如数量很大,那你的sql就须要优化了)、extra(一般是看排序请客,只管让Using index出现多点)。
假如条件答应,我建议把全部连接条件中的字段(一般是id为主)和order by 、 group by背面的字段都加索引
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvZjRiNzM4MjAyNGU3NGUwOThlZTdlNWQ0YzcwNDdkYWQucG5n
页: [1]
查看完整版本: com.mysql.cj.jdbc.exceptions.CommunicationsException Communications link failure