代码拉取完成,页面将自动刷新
因为spring执行事务是在方法结束后提交的。所有会存在一段锁释放之后,事务提取之前的状态。数据库默认是支持可重复读的,所以有可能读到过时信息,导致最后出错。
原代码如下
public Result startSeckilLock(long seckillId, long userId) {
lock.lock();
try {
/**
* 1)这里、不清楚为啥、总是会被超卖101、难道锁不起作用、lock是同一个对象
* 2)来自热心网友 zoain 的细心测试思考、然后自己总结了一下,事物未提交之前,锁已经释放(事物提交是在整个方法执行完),导致另一个事物读取到了这个事物未提交的数据,也就是传说中的脏读。建议锁上移
* 3)给自己留个坑思考:为什么分布式锁(zk和redis)没有问题?(事实是有问题的,由于redis释放锁需要远程通信,不那么明显而已)
* 4)2018年12月35日,更正一下,之前的解释(脏读)可能给大家一些误导,数据库默认的事务隔离级别为 可重复读(repeatable-read),也就不可能出现脏读
* 哪个这个级别是只能是幻读了?分析一下:幻读侧重于新增或删除,这里显然不是,那这里到底是什么,给各位大婶留个坑~~~~
*/
String nativeSql = "SELECT number FROM seckill WHERE seckill_id=?";
Object object = dynamicQuery.nativeQueryObject(nativeSql, new Object[]{seckillId});
Long number = ((Number) object).longValue();
if(number>0){
nativeSql = "UPDATE seckill SET number=number-1 WHERE seckill_id=?";
dynamicQuery.nativeExecuteUpdate(nativeSql, new Object[]{seckillId});
SuccessKilled killed = new SuccessKilled();
killed.setSeckillId(seckillId);
killed.setUserId(userId);
killed.setState(Short.parseShort(number+""));
killed.setCreateTime(new Timestamp(System.currentTimeMillis()));
dynamicQuery.save(killed);
}else{
return Result.error(SeckillStatEnum.END);
}
} catch (Exception e) {
throw new RrException("异常了个乖乖");
}finally {
lock.unlock();
}
return Result.ok(SeckillStatEnum.SUCCESS);
}
可以改成
public Result startSeckilLock(long seckillId, long userId) {
try {
/**
* 1)这里、不清楚为啥、总是会被超卖101、难道锁不起作用、lock是同一个对象
* 2)来自热心网友 zoain 的细心测试思考、然后自己总结了一下,事物未提交之前,锁已经释放(事物提交是在整个方法执行完),导致另一个事物读取到了这个事物未提交的数据,也就是传说中的脏读。建议锁上移
* 3)给自己留个坑思考:为什么分布式锁(zk和redis)没有问题?(事实是有问题的,由于redis释放锁需要远程通信,不那么明显而已)
* 4)2018年12月35日,更正一下,之前的解释(脏读)可能给大家一些误导,数据库默认的事务隔离级别为 可重复读(repeatable-read),也就不可能出现脏读
* 哪个这个级别是只能是幻读了?分析一下:幻读侧重于新增或删除,这里显然不是,那这里到底是什么,给各位大婶留个坑~~~~
*/
String nativeSql = "SELECT number FROM seckill WHERE seckill_id=?";
Object object = dynamicQuery.nativeQueryObject(nativeSql, new Object[]{seckillId});
Long number = ((Number) object).longValue();
if(number>0){
nativeSql = "UPDATE seckill SET number=number-1 WHERE seckill_id=?";
dynamicQuery.nativeExecuteUpdate(nativeSql, new Object[]{seckillId});
SuccessKilled killed = new SuccessKilled();
killed.setSeckillId(seckillId);
killed.setUserId(userId);
killed.setState(Short.parseShort(number+""));
killed.setCreateTime(new Timestamp(System.currentTimeMillis()));
dynamicQuery.save(killed);
}else{
return Result.error(SeckillStatEnum.END);
}
} catch (Exception e) {
throw new RrException("异常了个乖乖");
}finally {
}
return Result.ok(SeckillStatEnum.SUCCESS);
}
public Result SeckilLock(long seckillId, long userId){
Result result=Result.error("执行失败");
lock.lock();
result= startSeckilLock(seckillId,userId);
lock.unlock();
return result;
}
将锁至于事务外,这样就不会出现锁失效的问题了