在线上发现了死锁问题,排查解决之后,根据其原因写了一个demo,记录一下。
一:DEMO代码
/**
* 数据插入
*/
@RequestMapping("/test3")
@Transactional
public void test3() {
UEmployee uEmployee = new UEmployee();
uEmployee.setId("1111111111111111");
uEmployee.setName("test1");
uEmployee.setPsd("123456");
uEmployeeService.getuEmployeeDAO().insert(uEmployee);
System.out.println("uEmployee" + uEmployee.getId());
while (true) {
}
}
/**
* 数据删除
*/
@RequestMapping("/test4")
@Transactional
public void test4() {
UEmployee uEmployee = new UEmployee();
uEmployee.setId("1111111111111111");
uEmployee.setName("test1");
uEmployee.setPsd("123456");
uEmployeeService.getuEmployeeDAO().deleteByPrimaryKey(uEmployee.getId());
System.out.println(uEmployee);
}
二:使用postMan访问
先访问test3,将数据插入数据库
状态会一直是访问中,死循环,无法执行完成,没有数据返回到客户端
再访问test4
一开始无反应,等待中,一段时间后,报错。提示死锁;
三:原理分析及排查解决方法
首先,test4报错,提示死锁,说明当前操作数据有其他线程在执行操作。查找其他可能操作当前数据代码,找到可能代码之后,尝试重现异常。重现完成,解决代码问题,删除死锁(下面有删除数据库死锁方法),测试完成,上线。
这里出现问题的原因是,操作的是一条数据,而且test3在数据库中插入之后,因为逻辑死循环的问题,没有执行完当前方法,也就没有走完@Transactional 所注解的方法体,所以没有提交事务(commit),其他线程访问操作未提交的数据,也就理所当然的会出现死锁问题.
a.在数据库删除死锁方法
在数据库中找到"information_schema"表,选中.执行sql "SELECT * FROM INNODB_TRX;"会查询出没有执行完成的sql,
kill掉当前sql线程:(trx_mysql_tread_id)
再次查询:
kill成功