请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

正在回答 回答被采纳积分+3

2回答

枫荇 2019-11-11 18:34:19

您好,同学!先看一下完整的SQL语句

update account set balance=balance+CAST(? AS DECIMAL(30,6)) where account_no=? and balance>=-1*CAST(? AS DECIMAL(30,6)) 


通常我们更新数据库的时候是这样执行的:

1. 开启一个数据库事务。

2. 查询出需要更新的数据

select account_no,balance from account where account_no=? 

3. 计算新的balance值:

balance=balance-扣减金额

4. 执行更新语句

update account set balance=? where account_no=? 

5. 提交事务。


只需要指定需要更新的数据和数据库表唯一标识字段更新即可,那么这样带来的问题就是在高并发情况下运行时,会导致balance被额外扣减,如下表格:



从表格中可以看到,更新后的balance和预期不一样,并发问题导致剩余金额错误,那其中一种解决方法是使用数据库行锁,也就是把上面的第2步修改一下,添加for update:


select account_no,balance from account where account_no=?  for update

那么只有拿到锁的事务才可以执行,就把2个事务强制串行化,那么剩余金额就不会出现错误了,过程就变成了:


这个方法本身没问题,但使用锁将执行串行化,增加了数据库负担降低了性能,这里的锁就是悲观锁,那么就采用乐观锁来解决问题,可以再看一下开头的那个SQL:

update account set balance=balance+ 扣减的值 where account_no=? and balance>=-1*扣减的值

目的是扣减的计算逻辑从代码移动到update语句吗,update语句执行时数据库本身会保证原子性,

同时,在where语句中除了执行唯一标识,还加了一个限制 and balance>=-1*扣减的值,含义就是,如果更新的数据中如果 balance>=-1*扣减的值,剩余金额大于扣减金额,才可以扣减;如果剩余金额小于扣减金额,就无法扣减,update语句也就会不会实际执行了。

至于cast函数,是把传进来的数字转换成对应的数据库表字段类型,才能正确执行,所以最终的只需要执行一个update SQL就可以了:


update account set balance=balance+CAST(? AS DECIMAL(30,6)) where account_no=? and balance>=-1*CAST(? AS DECIMAL(30,6)) 


另外同学可以异步学习另外的免费课程来巩固这一块的认知:

https://www.imooc.com/learn/1101,如下几章课程


0 回复 有任何疑惑可以回复我~
枫荇 2019-11-10 12:02:49

你好!同学!

这里乐观锁,是通过update语句实现的,代码在AccountDao中,“" and balance>=-1*CAST(? AS DECIMAL(30,6)) "”

//账户余额的更新

//amount 如果是负数,就是扣减;如果是正数,就是增加

func (dao *AccountDao) UpdateBalance(

accountNo string,

amount decimal.Decimal) (rows int64, err error) {

sql := "update account " +

" set balance=balance+CAST(? AS DECIMAL(30,6))" +

" where account_no=? " +

" and balance>=-1*CAST(? AS DECIMAL(30,6)) "

rs, err := dao.runner.Exec(sql,

amount.String(),

accountNo,

amount.String())

if err != nil {

return 0, err

}

return rs.RowsAffected()

}





0 回复 有任何疑惑可以回复我~
  • 提问者 慕粉2045165721 #1
    老师,这里的cast是转换函数。
    balance>=-1*amount是什么意思?这条语句怎么能体现乐观锁?
    乐观锁不是有Version字段来检查是否有更新吗
    回复 有任何疑惑可以回复我~ 2019-11-10 12:31:35
  • 枫荇 回复 提问者 慕粉2045165721 #2
    前往这里查看:http://coding.imooc.com/learn/questiondetail/qid/151175
    回复 有任何疑惑可以回复我~ 2019-11-11 18:36:55

相似问题

登录后可查看更多问答,登录/注册

问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信