请教,mysql事务,锁和交易问题?

比如账户余额有100块钱,交易时检测如果 余额大于交易额,就交易成功。
现在假设这个用户同一时刻,产生了多比交易,检测的时候就会出现问题。

问题:

  1. 请问这个时候用事务的SERIERLIZED 隔离级别是否可以解决此问题。

  2. 或者给这行数据加锁,那请问这个锁该怎么加?

阅读 4.6k
5 个回答

隔离级别有四种,可串行化,可重复读,已提交读,未提交读。

一般数据库都是默认运行在已提交读的情况上,但是innodb是运行在可重复读的隔离级别上。

问题1:请问这个时候用事务的SERIERLIZED 隔离级别是否可以解决此问题。

肯定可以。这个是最高的隔离级别,等价于所有事务是串行执行,因此不会产生并发的问题。

简单重设下事务:
比如账户余额有100块钱,交易时检测如果 余额大于交易额,就交易成功。现在假设这个用户同一时刻,产生了多比交易,检测的时候就会出现问题。

事务可以用伪代码表示:

begin
read A
if(A>B)
than write(A-B)
commit

假设两个上面的事务并发执行,那么肯定是会出现问题:

--T1--                 --T2--
begin                  begin
read A                 read A
if(A>B)                if(A>B)
than write(A-B)        than write(A-B)
commit                 commit

由于read A通常是使用类似select balance from tbl,这种属于不加锁的读,也就是说这种情况下不会加任何的锁。确保重复读只是在第一次read的时候创建快照。也就是说,T1的read A,第一次读到的是100元,而T2的read A也是读到了100元。

这个时候,业务逻辑if(A>B),假设T1的B为99元,T2的B为98元,则都为真,因此虽然在write(A-B)先执行的事务中会加上写锁,但是最后的结果是这两笔交易都能成功进行,因此会造成交易异常。

那么如果增加写锁呢?

--T1--                 --T2--
begin                  begin
read A lock            read A lock
if(A>B)                if(A>B)
than write(A-B)        than write(A-B)
commit                 commit

通过这个时候会使用select...for update语句。当事务执行该语句的时候,会获得所需的锁。
不管哪个事务先执行,select..for update都会对A加上写锁,因此两个事务是不会冲突的。

但是,这种情况下(属于悲观锁),对于短事务是一种可行的方案。但是对于长事务来说,性能开销太大了。因此当应用场景是在长事务下,可以使用乐观锁来实现。

问题2:或者给这行数据加锁,那请问这个锁该怎么加?

可以这么加:select *from tbl where id=xxx for update;

用乐观锁解决此问题,就像楼上说的,如果这样操作的话,容易出现过多的乐观锁异常,需要自己手动进行对乐观锁异常进行补偿,来更新数据。
这样的问题最好还是在业务逻辑层次来进行处理,例如:如果是批量操作的,可以对账户进行汇总更新,或者通过同步队列来进行处理,但是这样对性能方面都会有所影响,主要还是得具体的业务场景和系统要求

  1. 可以解决此问题,但是可能性能会急剧下降

  2. 可以加乐观锁啊

理论上是可以解决问题的。但是如果从数据库层面修改事务隔离级别为SERIERLIZED对所有依赖这个数据库的系统是一场灾难。所有的数据库事务都变成了串行,系统基本上就趴窝了。

编码层面使用乐观锁可以提高性能,但是乐观锁的缺点是不适用与写操作较多的情况,因为频繁的发现无法更新数据,应用系统会不停的retry,导致应用系统压力越来越大,占用cpu资源,影响应用系统。

要看当时的业务场景具体分析,需要在整体架构上,思考如何解决问题。

典型的乐观锁场景,通过在写入时判断条件匹配情况,而不是在一开始就进行同步阻塞。

sql 演示:

update order set price=price-100 where id = 1 and price >= 100

对于有 ABA 问题的,也可以通过添加 version 来解决。

SERIERLIZED 采用的是悲观锁,性能会有损失。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题