工作中发现,spring开启事务当竟然会阻塞线程,当开启事务的并行线程数大于数据库连接池的最大连接数时就会出现这种情况。上demo!!!
1.基础配置
1.1.配置文件
spring:
datasource:
hikari:
# 数据库连接池最大连接数
maximum-pool-size: 3
1.2.controller
@Resource
private TestService testService;
@GetMapping("/hikari")
public void testHikariPool(int num) throws Exception {
// 这里设置5个线程并行
ExecutorService executorService = Executors.newFixedThreadPool(5);
ArrayList<Future> futures = new ArrayList<>();
for (int i = 0; i < num;i++) {
final int j = i;
Future<?> future = executorService.submit(() -> testService.testHikari(j));
futures.add(future);
}
for (Future future : futures) {
future.get();
}
log.info("结束..");
}
2.开启事务
2.1.代码
@Service
@Slf4j
public class TestService {
@Resource
private GoodsMapper goodsMapper;
@Transactional
public void testHikari(int i){
log.info("进来了,{}",i);
try {
goodsMapper.selectById(1);
// 这里等待5秒,模拟业务处理
Thread.sleep(5000);
} catch (Exception e) {}
}
}
2.2.结果
从上图可以看出,1、2、4号线程执行5秒后3、5号线程才执行。说明当开启事务的并行线程数大于数据库最大连接池数量时,超出的部分会阻塞。
3.不开启事务
3.1.代码
@Service
@Slf4j
public class TestService {
@Resource
private GoodsMapper goodsMapper;
public void testHikari(int i){
log.info("进来了,{}",i);
try {
goodsMapper.selectById(1);
// 这里等待5秒,模拟业务处理
Thread.sleep(5000);
} catch (Exception e) {}
}
}
3.2.结果
从上图可以看出,当不spring不开启事务时,5条线程并行执行。
4.结论
当开启事务的并行线程数大于数据库最大连接池数量时,超出的部分会阻塞。
5.不成熟的建议
- 查询接口不要开启事务,尤其是耗时比较长的查询业务时,否则会阻塞其他开启事务接口的线程。
- @Transactional注解不要写在类上,要写在方法上。
6.为什么?
为什么会出现这种情况呢?猜测可能是开启事务后当前线程绑定了一个数据库链接,当前线程事务未提交时数据库链接不会释放回连接池,从而导致其他线程阻塞在数据库链接池上。难道不开启事务的当前线程不是绑定了一条数据库链接吗?如果是,那么为什么不会阻塞呢?研究一下,下期一答再见。