存储制品库maven包,有两张表meta_maven存储groupId、artifactId、version信息,meta_maven_file存储GAV下的具体文件jar、pom、sha1、meta_maven.xml。
场景1: deploy上传snapshot的maven包,用新的meta_maven.xml替换之前的,之前的删除。
场景2: 下载GAV包,检查是否有漏洞:开始更新组件状态为扫描中,从黑鸭子获取扫描结果(超长时间等待),更新组件的扫描结果,有漏洞禁止下载。
场景1伪代码:
@Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITED, rollbackfor=Exception.class)
public void upload(MetaMavenFile metaMavenFile) {
MetaMaven metaMaven = metaMavenMapper.select(metaMavenFile);
Result uploadRet = metaMavenFileService.upload(metaMavenFile);
metaMaven.setModify("xxx");
metaMavenMapper.update(metaMaven);
}
@Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITED, timeout = 8, rollbackfor=Exception.class)
public Result upload(MetaMavenFile metaMavenFile) {
MetaMavenFile existMetaMavenFile = metaMavenFileMapper.select(metamavenFile);
String filePath = fastdfsServer.upload(metaMavenFile);
existMetaMavenFile.setStorageReference(filePath);
metaMavenFileMapper.updateByPrimaryKeySelective(existMetaMavenFile);
}
场景2伪代码:
@Transactional(propagation= Propagation.REQUIRED, isolation= Isolation.READ_COMMITED, timeout = 8, rollbackFor = Exception.class)
public void download(MetaMavenFile metaMavenFile, HttpResponse response){
mataMaven existMetaMaven = metaMavenMapper.select(metaMavenFile);
mataMavenMapper.updateCompoentStatus(existMetaMaven.getId(), ComponentStatus.SCANNING, null);
hasSecurityExist(existMetaMaven.getId());
}
public void hasSecurityExist(Long metaMavenId) {
JSONObject scanResult = getblackDuckScanResult(metaMavenId);
mataMaven existMetaMaven = metaMavenMapper.select(metaMavenId);
metaMavenMapper.updateByPrimaryKey(existMetaMavenFile);
}
步骤 | 事务1 | 事务2 |
---|---|---|
1 | begin | begin |
2 | select * from meta_maven where id = 1 | |
3 | select * from meta_maven where id =1 | |
4 | update meta_maven set component_status = 1 where id =1 | |
5 | update meta_maven set status = 1 where id =1 | |
6 | 获取黑鸭子扫描结果(超长时间等待) | |
7 | deallock detected | |
8 | update meta_maven set component_status = 2 where id = 1 | |
9 | commit | rollback |
一般产生死锁的场景(上面的和它不一样,上面的和我们之前介绍的悲观锁发生死锁等待很像):
步骤 | 事务1 | 事务2 |
---|---|---|
1 | begin | begin |
2 | update table1 set col =1 where id =1 | |
3 | update table1 set col1 = 2 where id =2 | |
4 | update table1 set col1 = 3 where id = 2 | |
5 | update table1 set col1 = 4 where id = 1 | |
6 | deaded lock | deaded lock |
Error updating databse, Cause: org.postgressql.util.PSQLException: ERROR: deadlock detected
Detail: Process 322869 waits for sharelock in transaction 3523519865;
blocked by process 369631.
Process 369631 waits foe ShareLock on transaction 3523519865;
blocked by process 369632.
where: while updating tuple(22892,30) in relation "meta_maven";ERROR: deadlock detected
### SQL: update meta_maven set modifyer = ? where id = ?
我们可以看到,问题很大是出现在hasSecurityExist这个超长等待,
REQUIRED_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起,意思是创建一个新的事务,和原来的事务没有关系
处理思路;
场景2优化伪代码:
@Transactional(propagation= Propagation.REQUIRED, isolation= Isolation.READ_COMMITED, timeout = 8, rollbackFor = Exception.class)
public void download(MetaMavenFile metaMavenFile, HttpResponse response){
mataMaven existMetaMaven = metaMavenMapper.select(metaMavenFile);
// 处理死锁问题,这个方法单独抽出来,单独声明事务传播机制
hasSecurityExist(existMetaMaven.getId());
}
@Transaction(propagation= Propagation= Propagation.REQUIRES_NEW)
public void updateCompentScaning(Long metaMavenId) {
mataMavenMapper.updateCompoentStatus(metaMavenId, ComponentStatus.SCANNING, null);
}
@Transaction(propagation= Propagation= Propagation.REQUIRES_NEW)
public void hasSecurityExist(Long metaMavenId) {
JSONObject scanResult = getblackDuckScanResult(metaMavenId);
mataMaven existMetaMaven = metaMavenMapper.select(metaMavenId);
metaMavenMapper.updateByPrimaryKey(existMetaMavenFile);
}