場景: 由於在一個方法中存在多個不同業務操作
private void insertOrUpdateField(CompanyReport entity) { //計算並數據 calcReportData(entity); // 對比上季度或上年度數據,生成風險警示 raiseReportRisk(entity.getId()); // 檢測並級聯產生年度數據,並對比年度數據,生成風險警示 checkAndGenerateYearData(entity.getId()); } private void raiseReportRisk(String reportId){ CompanyReport report = get(reportId); //產生問題的地方--------------------------- //若為季度數據,則找上一季度 if(report.getYear() != null && report.getQuarter() != null){ if(report.getQuarter() >1){ report.setQuarter(report.getQuarter() - 1); } else{ report.setYear(report.getYear() - 1); report.setQuarter(4); } } else { //若為年度數據,則找上一年度 report.setYear(report.getYear() - 1); } CompanyReport lastReport = getByPeriod(report); if(lastReport != null){ //重置風險狀態 fieldValueMapper.updateForResetRisk(reportId); //識別風險狀態 fieldValueMapper.updateForRisk(reportId, lastReport.getId()); } } private void checkAndGenerateYearData(String reportId){ CompanyReport currentReport = get(reportId); //這里的year quarter兩個值與數據庫里不一致了 }
由於上面一段代碼的執行順序問題
1:生成風險警示raiseReportRisk 執行這個方法的時候 通過id查詢了companyReport對象 那么這時候mybatis會將數據存儲在一級緩存中
同時將查詢結果companyReposrt 中的year 與quarter修改了
2:在級聯產生年度數據的時候checkAndGenerateYearData 又通過id去查詢companyReport 由於第一次已經查詢過了 第二次又進行了一次查詢 第二次默認查詢了是緩存中的數據
那么結果就是year 被修改的數據 造成了嚴重的不一致問題
解決方案:1:調整兩個方法的執行順序 在業務允許的情況下
2:將raiseReportRisk 中查詢的companyReposrt 重新創建一個新的對象 將屬性賦值過去 兩個對象 修改重新創建的對象
3: 每次查詢都更新查詢緩存 mybatis一級緩存如何修改
一級緩存的級別設為 statement 級別的,這樣每次查詢結束都會清掉一級緩存