這裏先簡單描述一下問題,
場景:在一個線程中創建了另外一個線程處理一部分業務,
主線程對數據庫進行新增操作,在操作結束後,啓動一個新的線程去執行查詢插入的數據的查詢操作,發現了數據沒有查詢的問題。
下面我們我們直接上代碼:
@Service
@Transactional
@Slf4j
public class RPatientService extends BaseService<RPatient, RPatientExample> {
@Autowired
private SequenceIdGenerator sequenceIdGenerator;
@Autowired
private WeChatMessageService weChatMessageService;
@Autowired
private RPatientMapper rPatientMapper;
@Autowired
private RReportIllnessService rReportIllnessService;
@Autowired
private ImSessionUserService imSessionUserService;
@Autowired
private RDoctorService rDoctorService;
public void registerPS(String openId, String doctorId, byte status) {
//按openId查詢用戶
synchronized (openId.intern()) {
RUser rUser = rUserService.getRUserByOpenId(openId);
RPatient rPatient = null;
if (rUser == null) {
//用戶不存在插入用戶
rUser = rUserService.createUserByOpenIdAndPS(openId, Constant.RUSER_TYPE_0_PATIENT, status);
//新增患者
rPatient = initPatient(rUser);
log.info("[RPatientService]:new patient join:{}", JsonUtil.toJson(rUser));
} else if (rUser.getType() == Constant.RUSER_TYPE_1_DOCTOR) {
//醫生掃描醫生二維碼,不處理
return;
}
if (rPatient == null) {
rPatient = this.getPatientByUserId(rUser.getId());
if(rPatient == null){
log.error("[RPatientService]: patient not exist:{}", JsonUtil.toJson(rUser));
return ;
}
}
Long rDoctorId = null;
if (!StringUtils.isEmpty(doctorId)) {
//報到 關聯醫生和患者生成report
rDoctorId = Long.valueOf(doctorId);
RDoctor rDoctor = rDoctorService.getDoctorById(rDoctorId);
if(rDoctor == null){
log.error("[RPatientService]: doctor not exist:doctorId:{}", doctorId);
return;
}
rReportService.report(rDoctorId, rPatient.getId());
}
eventBus.post(new PatientEvent(rUser.getId(), rDoctorId));
//新
//this.registerEvent(new PatientEvent(rUser.getId(), rDoctorId));
}
}
//EventBus執行
@Subscribe
@AllowConcurrentEvents
public void registerEvent(PatientEvent patientEvent) {
log.info("[PatientEvent]:{}", JsonUtil.toJson(patientEvent));
Long rUserId = patientEvent.getrUserId();
if (rUserId == null) {
return;
}
RUser rUser = rUserService.selectByPrimaryKey(rUserId);
RPatient rPatient = this.getPatientByUserId(rUserId);
// RReport rReport = rReportService.getByPatientId(rPatient.getId());
if (StringUtils.isEmpty(rPatient.getPhone())) {
//提示用戶身份驗證
weChatMessageService.sendToIdentityVerificationKFMsgForPatient(rUser.getVxopenid());
} else if (patientEvent.getrDoctorId() != null) {
//創建會話
rReportService.createNewSession(rPatient.getId());
//已關聯醫生,提示選擇疾病
weChatMessageService.sendToChoiceIllnessKFMsgForPatient(rUser.getVxopenid(), patientEvent.getrDoctorId());
}
}
}
新增操作的代碼:
@Service
@Transactional
@Slf4j
public class RReportService extends BaseService<RReport, RReportExample> {
@Autowired
private SequenceIdGenerator sequenceIdGenerator;
@Autowired
private RReportMapper rReportMapper;
@Autowired
private RPatientService patientService;
@Autowired
private ImSessionService imSessionService;
public RReport report(Long doctorId, Long patientId) {
RReport rReport = getByDoctorIdPatientId(doctorId, patientId);
if (rReport == null) {
rReport = initRReport(doctorId, patientId);
log.info("new report generate:{}", JsonUtil.toJson(rReport));
}
return rReport;
}
//插入數據
private RReport initRReport(Long doctorId, Long patientId) {
RReport rReport = new RReport();
rReport.setRdoctorid(doctorId);
rReport.setRpatientid(patientId);
rReport.setCreatetime(new Date());
insertOrUpdate(rReport);
return rReport;
}
//EventBus新事務執行的代碼
public void createNewSession(Long patientId) {
RPatient rPatient = patientService.selectByPrimaryKey(patientId);
if (StringUtils.isEmpty(rPatient.getPhone())) {
log.info("患者沒有完善個人信息,需要先完善個人信息!");
return;//未完善信息的不處理
}
RReportExample rReportExample = new RReportExample();
rReportExample.createCriteria().andRpatientidEqualTo(patientId).andImsessionidIsNull();
List<RReport> rReportList = this.selectByExample(rReportExample);
log.info("查詢隱患報道關係." + "數量只能有一條:" + rReportList.size() + "記錄信息=" + rReportList.toString());
if (rReportList != null && rReportList.size() != 0) {
for (RReport rReport : rReportList) {
Long doctorId = rReport.getRdoctorid();
//創建會話
ImSession imSession = imSessionService.createNewSession(doctorId, patientId);
rReport.setImsessionid(imSession.getId());
this.insertOrUpdate(rReport);//更新會話ID
}
}
ImSessionExample imSessionExample = new ImSessionExample();
imSessionExample.createCriteria().andCreateuseridEqualTo(patientId).andSessiontypeEqualTo((byte) 2);
ImSession a = imSessionService.selectOneByExample(imSessionExample);
if (a == null) {
//創建客服
imSessionService.createNewSession2(424987751667077198L, patientId);
}
}
}
下面直接看我分析服務器打出一段日誌就可以了
############這裏創建了一個事務 35ea154e http-nio-8081-exec-10線程編號
2020-01-11 11:13:47.834 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | org.springframework.jdbc.datasource.DataSourceTransactionManager | Creating new transaction with name [com.framework.code.service.report.RPatientService.registerPS]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2020-01-11 11:13:47.836 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | org.springframework.jdbc.datasource.DataSourceTransactionManager | Acquired Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@5c225ae5 [wrapping: com.mysql.jdbc.JDBC4Connection@35ea154e]] for JDBC transaction
########切換JDBC事務並且交給Spring管理
2020-01-11 11:13:47.837 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | org.springframework.jdbc.datasource.DataSourceTransactionManager | Switching JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@5c225ae5 [wrapping: com.mysql.jdbc.JDBC4Connection@35ea154e]] to manual commit
############參與當前的事務 35ea154e
2020-01-11 11:13:47.837 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | org.springframework.jdbc.datasource.DataSourceTransactionManager | Participating in existing transaction
2020-01-11 11:13:47.838 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.doctor.RUserMapper.selectByExample | ooo Using Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@5c225ae5 [wrapping: com.mysql.jdbc.JDBC4Connection@35ea154e]]
#######通過openid查詢用戶
2020-01-11 11:13:47.838 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.doctor.RUserMapper.selectByExample | ==> Preparing: select 'true' as QUERYID, Id_, VxHeadUrl_, VxNickName_, VxSex_, VxOpenid_, VxProvince_, VxCity_, VxCountry_, Type_, PromotionSource_ from r_user WHERE ( VxOpenid_ = ? )
2020-01-11 11:13:47.839 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.doctor.RUserMapper.selectByExample | ==> Parameters: oMGuv5uRcp03ycIgyjclwpZfr1Eg(String)
##########使用當前事務35ea154e
2020-01-11 11:13:47.842 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.report.RPatientMapper.selectByExample | ooo Using Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@5c225ae5 [wrapping: com.mysql.jdbc.JDBC4Connection@35ea154e]]
#######根據用戶Id查詢患者信息
2020-01-11 11:13:47.842 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.report.RPatientMapper.selectByExample | ==> Preparing: select 'true' as QUERYID, Id_, RUserId_, RegisterTime_, Name_, Phone_, CardNo_, Age_, Illness_, Irritability_, Inheritance_, IsBindFinished_, Sex_, VxHeadUrl_, PfksShopUserId_ from r_patient WHERE ( RUserId_ = ? )
2020-01-11 11:13:47.843 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.report.RPatientMapper.selectByExample | ==> Parameters: 458690345937539120(Long)
#############這裏表示使用AOP調用其他的事務,判斷當前有事務,那麼默認直接使用當前事務
2020-01-11 11:13:47.844 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | org.springframework.jdbc.datasource.DataSourceTransactionManager | Participating in existing transaction
############繼續使用當前事務 35ea154e
2020-01-11 11:13:47.845 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.doctor.RDoctorMapper.selectByExample | ooo Using Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@5c225ae5 [wrapping: com.mysql.jdbc.JDBC4Connection@35ea154e]]
#######通過醫生Id查詢醫生信息
2020-01-11 11:13:47.845 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.doctor.RDoctorMapper.selectByExample | ==> Preparing: select 'true' as QUERYID, Id_, RUserId_, Name_, NamePY_, RHospitalId_, RDepartmentId_, PositionCode_, Phone_, RegisterTime_, CheckStatus_, CheckTime_, CheckUserName_, CheckRemark_, Speciality_, Profile_, VxHeadUrl_, Dtype_, PfksShopUserId_, RDocCareType_ from r_doctor WHERE ( Id_ = ? )
2020-01-11 11:13:47.846 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.doctor.RDoctorMapper.selectByExample | ==> Parameters: 463413442003472478(Long)
#############再次使用AOP調用其他的事務,判斷當前有事務,那麼默認使用當前事務
2020-01-11 11:13:47.849 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | org.springframework.jdbc.datasource.DataSourceTransactionManager | Participating in existing transaction
#########繼續使用當前事務 35ea154e
2020-01-11 11:13:47.851 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.report.RReportMapper.selectByExample | ooo Using Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@5c225ae5 [wrapping: com.mysql.jdbc.JDBC4Connection@35ea154e]]
#########通過醫生ID和患者的ID查詢醫患報道表的信息
2020-01-11 11:13:47.852 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.report.RReportMapper.selectByExample | ==> Preparing: select 'true' as QUERYID, Id_, RPatientId_, RDoctorId_, CreateTime_, IMSessionId_, IllnessName_, RDoctorNameRemark_, RPatientNameRemark_ from r_report WHERE ( RDoctorId_ = ? and RPatientId_ = ? )
2020-01-11 11:13:47.853 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.report.RReportMapper.selectByExample | ==> Parameters: 463413442003472478(Long), 458690345958510641(Long)
##############繼續使用當前事務 35ea154e
2020-01-11 11:13:47.854 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.report.RReportMapper.insert | ooo Using Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@5c225ae5 [wrapping: com.mysql.jdbc.JDBC4Connection@35ea154e]]
#############添加醫患報道表的一條記錄 患者ID=458690345958510641 IMSessionId_是null
2020-01-11 11:13:47.857 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.report.RReportMapper.insert | ==> Preparing: insert into r_report (Id_, RPatientId_, RDoctorId_, CreateTime_, IMSessionId_, IllnessName_, RDoctorNameRemark_, RPatientNameRemark_) values (?, ?, ?, ?, ?, ?, ?, ?)
2020-01-11 11:13:47.858 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.mapper.report.RReportMapper.insert | ==> Parameters: 481834561777569793(Long), 458690345958510641(Long), 463413442003472478(Long), 2020-01-11 11:13:47.853(Timestamp), null, null, null, null
###########這裏輸出的日誌
2020-01-11 11:13:47.861 | myHost | INFO | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | com.framework.code.service.report.RReportService | new report generate:{"id":481834561777569793,"rpatientid":458690345958510641,"rdoctorid":463413442003472478,"createtime":1578712427853,"imsessionid":null,"illnessname":null,"rdoctornameremark":null,"rpatientnameremark":null}
########提交啓動的事務
2020-01-11 11:13:47.861 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | org.springframework.jdbc.datasource.DataSourceTransactionManager | Initiating transaction commit
#########這裏我們又需要創建一個新的事務 7fb1091a 線程編號pool-1-thread-7
2020-01-11 11:13:47.861 | myHost | DEBUG | pool-1-thread-7 | [] | org.springframework.jdbc.datasource.DataSourceTransactionManager | Creating new transaction with name [com.framework.code.service.report.RPatientService.registerEvent]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
########之前線程的事務進行提交
2020-01-11 11:13:47.861 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | org.springframework.jdbc.datasource.DataSourceTransactionManager | Committing JDBC transaction on Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@5c225ae5 [wrapping: com.mysql.jdbc.JDBC4Connection@35ea154e]]
################這裏是我們新的事務 7fb1091a
2020-01-11 11:13:47.862 | myHost | DEBUG | pool-1-thread-7 | [] | org.springframework.jdbc.datasource.DataSourceTransactionManager | Acquired Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@75935acf [wrapping: com.mysql.jdbc.JDBC4Connection@7fb1091a]] for JDBC transaction
2020-01-11 11:13:47.862 | myHost | DEBUG | pool-1-thread-7 | [] | org.springframework.jdbc.datasource.DataSourceTransactionManager | Switching JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@75935acf [wrapping: com.mysql.jdbc.JDBC4Connection@7fb1091a]] to manual commit
######這裏是日誌輸出
2020-01-11 11:13:47.862 | myHost | INFO | pool-1-thread-7 | [] | com.framework.code.service.report.RPatientService | [PatientEvent]:{"rUserId":458690345937539120,"rDoctorId":463413442003472478}
##########使用當前事務
2020-01-11 11:13:47.862 | myHost | DEBUG | pool-1-thread-7 | [] | com.framework.code.mapper.doctor.RUserMapper.selectByPrimaryKey | ooo Using Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@75935acf [wrapping: com.mysql.jdbc.JDBC4Connection@7fb1091a]]
##########通過用戶Id查詢用戶信息
2020-01-11 11:13:47.862 | myHost | DEBUG | pool-1-thread-7 | [] | com.framework.code.mapper.doctor.RUserMapper.selectByPrimaryKey | ==> Preparing: select Id_, VxHeadUrl_, VxNickName_, VxSex_, VxOpenid_, VxProvince_, VxCity_, VxCountry_, Type_, PromotionSource_ from r_user where Id_ = ?
2020-01-11 11:13:47.863 | myHost | DEBUG | pool-1-thread-7 | [] | com.framework.code.mapper.doctor.RUserMapper.selectByPrimaryKey | ==> Parameters: 458690345937539120(Long)
######之前的線程釋放JDBC連接
2020-01-11 11:13:47.867 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | org.springframework.jdbc.datasource.DataSourceTransactionManager | Releasing JDBC Connection
[com.mchange.v2.c3p0.impl.NewProxyConnection@5c225ae5 [wrapping: com.mysql.jdbc.JDBC4Connection@35ea154e]] after transaction
2020-01-11 11:13:47.867 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | org.springframework.jdbc.datasource.DataSourceUtils | Returning JDBC Connection to DataSource
2020-01-11 11:13:47.867 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | org.springframework.web.servlet.DispatcherServlet | Completed 200 OK
####被AOP的切面攔截輸入的日誌
2020-01-11 11:13:47.867 | myHost | INFO | pool-1-thread-8 | [] | com.framework.web.eventbus.LogSubscribe | [LogSubscribe]:{"threadName":"http-nio-8081-exec-10","className":"com.framework.code.controller.webchat.WeChartController","methodName":"receiveEvent","argsMap":{"request":"ServletRequest","response":"ServletResponse"},"argsJson":"{\"request\":\"ServletRequest\",\"response\":\"ServletResponse\"}","happenTime":1578712427867,"throwable":null,"throwableString":null,"traceId":"436ed24f998d411ab5150b1258b22cd0","result":null,"useTime":33}
2020-01-11 11:13:47.867 | myHost | DEBUG | http-nio-8081-exec-10 | [436ed24f998d411ab5150b1258b22cd0] | org.springframework.session.web.http.SessionRepositoryFilter.SESSION_LOGGER | No session found by id: Caching result for getSession(false) for this HttpServletRequest.
########使用當前事務 7fb1091a
2020-01-11 11:13:47.867 | myHost | DEBUG | pool-1-thread-7 | [] | com.framework.code.mapper.report.RPatientMapper.selectByExample | ooo Using Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@75935acf [wrapping: com.mysql.jdbc.JDBC4Connection@7fb1091a]]
###通過用戶ID查詢患者信息
2020-01-11 11:13:47.867 | myHost | DEBUG | pool-1-thread-7 | [] | com.framework.code.mapper.report.RPatientMapper.selectByExample | ==> Preparing: select 'true' as QUERYID, Id_, RUserId_, RegisterTime_, Name_, Phone_, CardNo_, Age_, Illness_, Irritability_, Inheritance_, IsBindFinished_, Sex_, VxHeadUrl_, PfksShopUserId_ from r_patient WHERE ( RUserId_ = ? )
2020-01-11 11:13:47.869 | myHost | DEBUG | pool-1-thread-7 | [] | com.framework.code.mapper.report.RPatientMapper.selectByExample | ==> Parameters: 458690345937539120(Long)
##########使用AOP調用其他的事務,判斷當前有事務,那麼默認使用當前事務 7fb1091a
2020-01-11 11:13:47.870 | myHost | DEBUG | pool-1-thread-7 | [] | org.springframework.jdbc.datasource.DataSourceTransactionManager | Participating in existing transaction
2020-01-11 11:13:47.876 | myHost | DEBUG | pool-1-thread-7 | [] | com.framework.code.mapper.report.RPatientMapper.selectByPrimaryKey | ooo Using Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@75935acf [wrapping: com.mysql.jdbc.JDBC4Connection@7fb1091a]]
######通過用戶ID查詢患者信息
2020-01-11 11:13:47.876 | myHost | DEBUG | pool-1-thread-7 | [] | com.framework.code.mapper.report.RPatientMapper.selectByPrimaryKey | ==> Preparing: select Id_, RUserId_, RegisterTime_, Name_, Phone_, CardNo_, Age_, Illness_, Irritability_, Inheritance_, IsBindFinished_, Sex_, VxHeadUrl_, PfksShopUserId_ from r_patient where Id_ = ?
2020-01-11 11:13:47.876 | myHost | DEBUG | pool-1-thread-7 | [] | com.framework.code.mapper.report.RPatientMapper.selectByPrimaryKey | ==> Parameters: 458690345958510641(Long)
##########使用當前事務 7fb1091a
2020-01-11 11:13:47.878 | myHost | DEBUG | pool-1-thread-7 | [] | com.framework.code.mapper.report.RReportMapper.selectByExample | ooo Using Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@75935acf [wrapping: com.mysql.jdbc.JDBC4Connection@7fb1091a]]
##########通過患者ID查詢患者報道信息表 458690345958510641
2020-01-11 11:13:47.878 | myHost | DEBUG | pool-1-thread-7 | [] | com.framework.code.mapper.report.RReportMapper.selectByExample | ==> Preparing: select 'true' as QUERYID, Id_, RPatientId_, RDoctorId_, CreateTime_, IMSessionId_, IllnessName_, RDoctorNameRemark_, RPatientNameRemark_ from r_report WHERE ( RPatientId_ = ? and IMSessionId_ is null )
2020-01-11 11:13:47.878 | myHost | DEBUG | pool-1-thread-7 | [] | com.framework.code.mapper.report.RReportMapper.selectByExample | ==> Parameters: 458690345958510641(Long)
########輸出查詢結果
2020-01-11 11:13:47.879 | myHost | INFO | pool-1-thread-7 | [] | com.framework.code.service.report.RReportService | 查詢隱患報道關係.數量只能有一條:0記錄信息=[]
看完日誌 我們不難發現,在主線程明明已經執行完成新增操作,並且已經釋放了JDBC連接,在EventBus的線程中新的事務中並沒有查詢到我們要插入的數據。。。。
按照正常的邏輯思考這就是一個死循環的。。。。。。明明我已經執行完成了新增操作並且釋放了連接到連接池 。。問什麼我在新的事務中查詢不到數據呢。
個人的分析可能數據庫出來也許一個短暫 的時間,因爲主線程插入數據的時間和EventBus線程去查詢間隔時間只有0.02秒的時間可能數據並沒有寫入完成操作的。我的解決方案就是放棄EventBus使用主線程一次處理所有業務,讓一次接口調用的響應時間加長,來減少併發出現的問題。