今天線上出現了一個詭異bug,部分數據被提前消費。由於業務流程保密問題,下面用例子詳解
場景:現在有個需求,學校需要統計每個班,每天的考勤情況
我們用兩個定時任務來解決,定時任務A插入考勤數據,定時任務B統計考勤數據
定時任務之間可能存在併發。
package com.test.scholl.service.impl;
// 定時任務A執行方法
public void insertAttendanceAndDetails(Attendance attendance){
// 插入主表
this.insertAttendance(attendance);
// 插入明細表
for(AttendanceDetail detail: attendance.getDetails()){
this.insertDetails(detail);
}
}
public void censusAttendance(){
// 1.查詢未統計的班級
// 2.折算出勤比例
// 3.更新主表狀態爲已統計
}
此時注意,定時任務A中insertAttendanceAndDetails方法存在一個隱患,是啥呢?跑下程序,你會發現,該方法未受事務控制,也就是在執行完主表插入,事務自動提交,執行每條子表插入,事務自動提交。此時,如果定時任務B正好消費到定時任務A已提交數據,但數據未全的情況下,就會引發部分數據被提前消費,剩餘數據永遠不會被消費的問題。
爲啥會沒受事務控制呢?
我們首先調用的是AOP代理對象而不是目標對象,首先執行事務切面,事務切面內部通過TransactionInterceptor環繞增強進行事務的增強,即進入目標方法之前開啓事務,退出目標方法時提交/回滾事務。
而insertAttendanceAndDetails方法裏的this指向目標對象,因此調用this.insertDetails()將不會執行insertDetails事務切面,即不會執行事務增強
附上解決鏈接,供參考
https://www.jianshu.com/p/8ebcbacd9657