內容來自學成在線的媒資管理事務優化
目前的邏輯是方法uploadFile中包含兩個動作
1 將文件上傳到minio
2 將文件信息存儲到資料庫
原本是整個方法上加@transactional
但是1的這部分, 你並不能保證上傳的時間會有多長
以至於說整個方法如果綁transactional會導致占用資料庫資源
現在有個想法, 打算只在2的步驟上加入transactional
然後在2的程式碼中加入會報錯的程式碼, 看看是否會回滾
部分程式碼
//將文件上傳到minio
boolean result = addMediaFilesToMinIO(localFilePath, mimeType, bucket_files, objectName);
if(!result)XueChengPlusException.cast("上傳文件失敗");
//文件大小
uploadFileParamsDto.setFileSize(file.length());
//將文件信息存儲到數據庫
MediaFiles mediaFiles = addMediaFilesToDb(companyId, fileMd5, uploadFileParamsDto, bucket_files, objectName);
if(mediaFiles==null)XueChengPlusException.cast("上傳後保存文件信息失敗");
方法片段
@Transactional
public MediaFiles addMediaFilesToDb(Long companyId, String fileMd5, UploadFileParamsDto uploadFileParamsDto, String bucket, String objectName) {
//從數據庫查詢文件
MediaFiles mediaFiles = mediaFilesMapper.selectById(fileMd5);
if (mediaFiles == null) {
mediaFiles = new MediaFiles();
//拷貝基本信息
BeanUtils.copyProperties(uploadFileParamsDto, mediaFiles);
mediaFiles.setId(fileMd5);
mediaFiles.setFileId(fileMd5);
mediaFiles.setCompanyId(companyId);
mediaFiles.setUrl("/" + bucket + "/" + objectName);
mediaFiles.setBucket(bucket);
mediaFiles.setFilePath(objectName);
mediaFiles.setCreateDate(LocalDateTime.now());
mediaFiles.setAuditStatus("002003");
mediaFiles.setStatus("1");
//保存文件信息到文件表
int insert = mediaFilesMapper.insert(mediaFiles);
int a=1/0;
if (insert <=0) {
log.error("保存文件信息到數據庫失敗,{}", mediaFiles.toString());
XueChengPlusException.cast("保存文件信息失敗");
}
log.debug("保存文件信息到數據庫成功,{}", mediaFiles.toString());
}
return mediaFiles;
}
這時發現雖然會報錯誤, 但是事務沒有回滾, 事務失效
簡單敘述目前狀況
就是controller調用service時, 第一層是調代理對象的方法
但是方法中再調用其他方法, 則會是原對象方法, 如下圖
這裡有個技巧, 可以在方法調service中的方法前加上this.用debug斷點去看this就會發現並非proxy而這不滿足事務的兩個要求
1 需要是代理對象調方法
2 在調的方法上加@Transactional註解
因為要求沒滿足, 事務沒法生效
課程提供一個解法
就是將當前類再注入進來, 使其變成代理對象
步驟
1 注入本service作為代理對象
@Autowired
MediaFileService currentProxy;
2 將需要事務管理的方法提成接口
public MediaFiles addMediaFilesToDb(Long companyId,String fileMd5,UploadFileParamsDto uploadFileParamsDto,String bucket,String objectName);
3 調用代理對象call方法
//寫入文件表
MediaFiles mediaFiles = currentProxy.addMediaFilesToDb(companyId, fileMd5, uploadFileParamsDto, bucket_files, objectName);