场景: 由于在一个方法中存在多个不同业务操作
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 级别的,这样每次查询结束都会清掉一级缓存