单体结构项目中,此方法加了同步锁,但是结果仍出现了同步问题(即返回相同的值)
@Override
public synchronized Long nextSeq(SequenceEnum sequenceEnum,String tenantId) {
SequenceEntity one = lambdaQuery()
.eq(SequenceEntity::getType, sequenceEnum.type())
.eq(StringUtil.isNotBlank(tenantId),SequenceEntity::getTenantId,tenantId)
.and(StringUtil.isBlank(tenantId),c->{
c.isNull(SequenceEntity::getTenantId)
.or()
.eq(SequenceEntity::getTenantId,"");
})
.one();
if(one == null) {
SequenceEntity seq = new SequenceEntity();
seq.setType(sequenceEnum.type());
seq.setStep(sequenceEnum.step());
seq.setSeq(sequenceEnum.initSeq());
seq.setTenantId(tenantId);
if(AuthUtil.getUser() == null){
seq.setCreateUser(BizConstant.DEFAULT_USER_ID);
seq.setCreateDept(BizConstant.DEFAULT_DEPT_ID);
seq.setCreateTime(DateUtil.now());
}
save(seq);
return sequenceEnum.initSeq();
}
if(one.getStep()<=0){
one.setStep(1L);
}
one.setSeq(one.getSeq()+ one.getStep());
updateById(one);
return one.getSeq();
}
}
后面找到问题发生的地方
@Override
@Transactional(rollbackFor = Exception.class)
public R<UserInfo> memberUnionLogin(String tenantId, String appid, String code,String phone) {
if (!wxMaService.switchover(appid)) {
WechatAppletConfig config = iComWechatAppletConfigService.getCacheConfig(appid);
if(config == null) {
return R.fail(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
}
WxMaDefaultConfigImpl wxMaConfig = new WxMaDefaultConfigImpl();
wxMaConfig.setAppid(config.getAppid());
wxMaConfig.setSecret(config.getSecret());
wxMaConfig.setToken(config.getToken());
wxMaConfig.setAesKey(config.getAesKey());
wxMaConfig.setMsgDataFormat(config.getMsgDataFormat());
wxMaService.addConfig(appid,wxMaConfig);
}
try {
WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
String openid = session.getOpenid();
String unionId = session.getUnionid();
// 有效时长3天以内
bladeRedis.setEx(MemberUnionEntity.WECHAT_CACHE_SESSION_KEY.concat(openid).concat(":").concat(tenantId),session, Duration.ofHours(24*3-1));
log.error("微信小程序登录,unionId:{},appid:{},openid:{},tenantId:{},phone:{}",unionId,appid,openid,tenantId,phone);
return login(unionId,appid,openid,tenantId,phone, TerminalTypeEnum.TERMINAL_MINI);
} catch (WxErrorException e) {
log.error(e.getMessage(), e);
return R.fail(e.getMessage());
} finally {
WxMaConfigHolder.remove();
}
}
发现有个@Transactional注解,联想到事务,@Transactional的原理是Spring 会生成一个当前对象的代理对象,代理对象执行方法前开启事务,synchronized锁定的是当前对象,事务提交前锁可能已经释放了,所以出现了synchronized失效的结果。
解决方法:
@Override
@Transactional(propagation= Propagation.NOT_SUPPORTED)
public synchronized Long nextSeq(SequenceEnum sequenceEnum,String tenantId) {...}