论坛首页 入门技术论坛

遇到一个多用户并发的问题,谁说查询操作不用做事务处理或者不用加锁?

浏览 5317 次
该帖已经被评为新手帖
作者 正文
   发表时间:2007-12-25  
查询操作不用做事务处理或者不用加锁,以前一直比较同意,今天遇到一个实际的问题,原来这种想法是错误的.

项目中遇到一个用户资金扣除出错的问题:
系统采用了quartz来做定时任务的处理,在某个时间点,自动对用户购买方案进行扣款,通过对日志的跟踪发现:当用户购买了多个方案时,有时用户可用资金会出错。

要实现的功能:
查询用户的可用资金,然后扣款。
假设用户w当前可用资金为1000元,应该执行两次扣款,第一次100,第二次50,用户w正确的余额应该是850。

出错原因:
扣款前要先查询用户当前的可用金额,然后再扣款.
通过日志发现,线程a查询完用户w的可用金额为1000元后,暂停了执行扣款的操作。
然后线程b开始执行,线程b查询用户w的可用金额为1000元,然后扣款50,更新DB,这时用户w余额是950。
然后,线程a在1000的基础上扣款100,更新DB,这时用户w的最终余额是900元。显而易见,用户w的最终余额是错误的。

结论:查询操作不用做事务处理或者说不用加锁是错误的。

其实这是一个丢失更新的典型的场景,但在实际中真实地遇到它,还是让人很兴奋啊.

欢迎大家批评指正。
   发表时间:2007-12-25  
乐观锁是用来解决这个问题的
0 请登录后投票
   发表时间:2007-12-25  
你这里的场景:查询操作只是一个完整事务的一部分

可别从一个极端到另外一个极端
0 请登录后投票
   发表时间:2007-12-25  
关键是你更新的策略问题,你在进行更新的时候逻辑是怎么写的~

如果是查询出来余额判断后执行更新操作,那么你这个逻辑的本身也是属于更新的一部分,方法类似

public void updateAccount(***){
   double account  =  queryAccout();
   XXDAO.update(XXX);
}

事务的设置可以用声明式事务对该方法进行设定 或者 自己手动控制事务
0 请登录后投票
   发表时间:2007-12-25  
脏读...锁机制存在的主要原因之一
0 请登录后投票
   发表时间:2007-12-25  
WorkingHard?! 写道
关键是你更新的策略问题,你在进行更新的时候逻辑是怎么写的~

如果是查询出来余额判断后执行更新操作,那么你这个逻辑的本身也是属于更新的一部分,方法类似

public void updateAccount(***){
   double account  =  queryAccout();
   XXDAO.update(XXX);
}

事务的设置可以用声明式事务对该方法进行设定 或者 自己手动控制事务



同意.

投入门贴的朋友们,你们都遇到过这种场景吗?表示怀疑
0 请登录后投票
   发表时间:2007-12-25  
所谓的查询  是指整个事务里只有一个查询
0 请登录后投票
   发表时间:2007-12-25  
ddandyy 写道
所谓的查询  是指整个事务里只有一个查询


看来大家的看法比较一致啊.
我这个场景中,查询只是事务的一部分而已.

这个查询方法在dao层中,事务由service方法做处理
0 请登录后投票
   发表时间:2007-12-25  
你的数据库是oracle吗?

不同的数据库有不同的锁机制。你这样说,根本就是在乱扯。虽然有那么点道理,但是与问题本质没有关系
0 请登录后投票
   发表时间:2007-12-25  
ideafrog 写道
你的数据库是oracle吗?

不同的数据库有不同的锁机制。你这样说,根本就是在乱扯。虽然有那么点道理,但是与问题本质没有关系


能解释下您说的本质吗
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics