版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011870280/article/details/82835738
今天压测用户中心的登录接口。发现这个接口在并发下几乎不可用,错误率70%。
查看后台日志全是:
登录接口出现死锁了。
看了下代码,登录中做了更新用户登录时间,插入用户log。查询数据库,发行用户更新和插入log都会lock wait
判断可能是在压测同一个用户登录时,某个请求中的事务读取到了另一个请求里事务未提交的数据。从而需要等待之前的事务提交。(幻读)
然后将事务隔离机制改成SERIALIZABLE。
@Transactional(isolation= Isolation.SERIALIZABLE)。
然而并不能解决问题。
后来发现问题出现在记录用户日志上
save(user)后,user对象是持久态,然后把持久态的user塞到userlog对象里
虽然这里没配置@cascade,但是如果对象是持久态的话,会默认级联更新。
所以在后续我执行save(userlog)时,有对这个user update了一遍。照成死锁。
然后我去除了manyToOne的依赖,改成ID。
结果fuck,问题依然存在!
最后看到一篇文章:
https://www.percona.com/blog/2006/12/12/innodb-locking-and-foreign-keys/
才发现罪魁或者是外键,userLog表有外键。
当插入一条userLog时,会把关联的user数据给锁了,然后对这个user的更新操作很容易死锁。
删除外键后,解决问题。