该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间: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的最终余额是错误的。 结论:查询操作不用做事务处理或者说不用加锁是错误的。 其实这是一个丢失更新的典型的场景,但在实际中真实地遇到它,还是让人很兴奋啊. 欢迎大家批评指正。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2007-12-25
乐观锁是用来解决这个问题的
|
|
返回顶楼 | |
发表时间:2007-12-25
你这里的场景:查询操作只是一个完整事务的一部分
可别从一个极端到另外一个极端 |
|
返回顶楼 | |
发表时间:2007-12-25
关键是你更新的策略问题,你在进行更新的时候逻辑是怎么写的~
如果是查询出来余额判断后执行更新操作,那么你这个逻辑的本身也是属于更新的一部分,方法类似 public void updateAccount(***){ double account = queryAccout(); XXDAO.update(XXX); } 事务的设置可以用声明式事务对该方法进行设定 或者 自己手动控制事务 |
|
返回顶楼 | |
发表时间:2007-12-25
脏读...锁机制存在的主要原因之一
|
|
返回顶楼 | |
发表时间:2007-12-25
WorkingHard?! 写道 关键是你更新的策略问题,你在进行更新的时候逻辑是怎么写的~
如果是查询出来余额判断后执行更新操作,那么你这个逻辑的本身也是属于更新的一部分,方法类似 public void updateAccount(***){ double account = queryAccout(); XXDAO.update(XXX); } 事务的设置可以用声明式事务对该方法进行设定 或者 自己手动控制事务 同意. 投入门贴的朋友们,你们都遇到过这种场景吗?表示怀疑 |
|
返回顶楼 | |
发表时间:2007-12-25
所谓的查询 是指整个事务里只有一个查询
|
|
返回顶楼 | |
发表时间:2007-12-25
ddandyy 写道 所谓的查询 是指整个事务里只有一个查询
看来大家的看法比较一致啊. 我这个场景中,查询只是事务的一部分而已. 这个查询方法在dao层中,事务由service方法做处理 |
|
返回顶楼 | |
发表时间:2007-12-25
你的数据库是oracle吗?
不同的数据库有不同的锁机制。你这样说,根本就是在乱扯。虽然有那么点道理,但是与问题本质没有关系 |
|
返回顶楼 | |
发表时间:2007-12-25
ideafrog 写道 你的数据库是oracle吗?
不同的数据库有不同的锁机制。你这样说,根本就是在乱扯。虽然有那么点道理,但是与问题本质没有关系 能解释下您说的本质吗 |
|
返回顶楼 | |