一个简单的获取流水号代码:
/**
* 获取流水号
* @param billstype 业务类型
* @return
*/
@Transactional(rollbackFor = Throwable.class)
public synchronized int getOrUpdateNumber(String billstype) {
int num = 1;
//获取历史流水号
Stream stream = streamDao.getStreamBySource(billstype);
if(stream!=null){
//流水位
String data_num = stream.getStreamId();
num = Integer.parseInt(data_num);
stream.setStreamId((num + 1)+"");
streamDao.updateStreamBySource(stream);
}else{
Stream streamInfo = new Stream();
streamInfo.setSource(billstype);
streamInfo.setStreamId((num + 1)+"");
streamDao.createStream(streamInfo);
}
return num;
}
咋一看应该是没有什么问题的,可是在实际使用过程中却出现了重复的情况。
重复的原因:
@Transactional 注解和 synchronized 同时作用在一个方法上导致的。
因为Transactional 实现事务的原理是通过动态代理来实现的,会自动帮我们生成一个代理类,而在代理类上我们并没有添加synchronized ,导致代理类不是线程安全的。所以就会出现重复的流水号。
解决办法:
Transactional 和 synchronized 不要同时作用在一个方法上即可