배경
새로운 프로젝트가 곧 온라인으로 전환 될 예정입니다. 기능을 테스트 할 때 버튼을 클릭 한 후 페이지가 멈췄다는 것을 발견했습니다. 처음에는 네트워크 문제라고 생각했지만 페이지가 멈춰 100 % 재현되었습니다. 백그라운드 로그를 확인하고 업데이트 문을 실행하는 동안 잠겨 있음을 확인했습니다.
SQL을 통한 쿼리
select * from information_schema.innodb_trx;
sys_sn_rule 테이블을 업데이트하여 발생한 것으로 확인되었으므로 코드를 정렬하고 LOCK_WAIT가 나타나는 이유를 살펴 보겠습니다.
원인 조사
인터페이스 호출을보고 메서드를 찾습니다. 여기서 메서드를 단순화합니다. 단순화 된 코드는 다음과 같습니다.
@Override
@Transactional(rollbackFor = Exception.class)
public Result funA() {
//更新表table1;
funB();
...
}
public void funB() {
//更新表table1;
....
}
문제는 funA가 funB를 호출하고 두 메서드가 table1의 동일한 데이터에 대해 동시에 작동한다는 것입니다. 여기에는 두 개의 트랜잭션이 있으며 데이터가 업데이트되면 두 트랜잭션이 서로 트랜잭션을 닫을 때까지 대기하게되며 이때 교착 상태가됩니다. 그림으로 설명해 봅시다 :
교착 상태 다이어그램
위의 그림과 같이 funA가 실행되면 테이블 1이 업데이트되고 테이블이 업데이트되기 전에 트랜잭션 A가 열리고 테이블이 업데이트 될 때이 데이터 행이 잠 깁니다 (데이터 일관성을 보호하기 위해). . 그런 다음 funB를 호출하고 트랜잭션 B를 열고 table1 테이블을 업데이트합니다. table1의 행이 잠겨 있으므로 트랜잭션 B는 잠금이 해제 될 때까지 기다려야 계속 진행할 수 있습니다. 그러나 트랜잭션 A를 닫으려면 funA가 실행을 마칠 때까지 기다려야 닫힐 수 있습니다. FunB는 funA에서 호출되고 funB는 실행되기 전에 table1이 잠금을 해제 할 때까지 기다려야합니다. 이것은 무한 루프로 이어집니다.
데이터베이스 잠금에 대한 지식은 다음 기사를 읽을 수 있습니다.
“교착 상태 학습 트랜잭션 및 격리 수준을 해결하는 길 -aneasystone의 블로그
(https://www.aneasystone.com/archives/2017/10/solving-dead-locks-one.html)
”
해결책
멀티 스레딩을 사용하여 다음을 해결할 수 있습니다.
@Override
@Transactional(rollbackFor = Exception.class)
public Result funA() {
//更新表table1;
taskExecutor.execute(() -> {
try {
Thread.sleep(5 * 1000);
funB();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
...
}
public void funB() {
//更新表table1;
....
}
멀티 스레딩을 사용하면 두 트랜잭션이 두 개의 서로 다른 스레드에 있으며 대기중인 루프가 없습니다.
교착 상태 다이어그램-멀티 스레딩
코드가 수정 된 후 테스트는 순조롭게 통과되었습니다.
과거에 추천
QR 코드를 스캔하여 더 흥미 진진하게 만드세요. 또는 WeChat 에서 Lvshen_9를 검색 하여 답장하여 백그라운드에서 정보를 얻을 수 있습니다.
回复"java" 获取java电子书;
回复"python"获取python电子书;
回复"算法"获取算法电子书;
回复"大数据"获取大数据电子书;
回复"spring"获取SpringBoot的学习视频。
回复"面试"获取一线大厂面试资料
回复"进阶之路"获取Java进阶之路的思维导图
回复"手册"获取阿里巴巴Java开发手册(嵩山终极版)
回复"总结"获取Java后端面试经验总结PDF版
回复"Redis"获取Redis命令手册,和Redis专项面试习题(PDF)
回复"并发导图"获取Java并发编程思维导图(xmind终极版)
기타 : 더 많은 놀라움을 얻으 려면 [ 내 혜택 ]을 클릭하십시오 .