Web应用程序并发问题处理的一点小经验
在web应用中,一个账户,会有N多个涉及到数字的字段。比如一个账户的金额,积分等。这些字段就涉及到增减的情况。如果是在测试环境下,靠程序员或者测试手动点击。一般是发现不了问题。
一旦上到正式环境下。有真实用户做操作了,就很容易出现莫名其妙的金额和流水记录不一致的情况。如果没有足够的经验,很难排查出问题。
据我了解,业界一般用使用三种解决方案
- 1.使用消息队列
- 2.悲观锁
- 3.乐观锁
因为博主自身处于小公司,对于消息队列没有实际操作经验。所以本篇文章主要讨论后面两种。
悲观锁
从名字上看,就是认为一定会发生并发的可能性,从源头上杜绝数据错乱的情况。
常见的处理方式:
数据库加锁。如SQL server的RowLock和Mysql中的for update
优点:程序没问题的情况下完全不会出现数据问题
缺点:性能不太好,数据库锁是非常消耗资源的行为
乐观锁
乐观锁和悲观锁相反。认为不会有并发问题。只在提交修改的时候,去检查一下当前这条数据是否有修改的迹象。
常见处理方式:
在数据库中加入一个列。记录下当前修改的版本号。每次修改的时候,判断版本号是否和之前查询出的是否一致,如果一致的。修改成功,不一致,无法修改。需要重新加载一次查询数据,然后循环判断操作
伪代码如下:
ndex = 1 //约定重试次数 while(true){ selct id ,money ,version from table //查询当前记录 money+=1; //修改数据 update table set money = money,version = (version+1) where id = @id and version = version //更新到数据库,判断是否更新成功 if(update){ break; } // index+=1; if(index>3){ break; } }
乐观锁优点: 可以实现无锁操作,性能会比悲观锁高很多
乐观锁缺点:有脏读问题,而且查询次数会比悲观锁多几倍
了解这两种方式,已经可以纵横各大中小型应用了。