问题描述
有c/s b/s的2个项目,操作同一表结构A,表A中有字段count=100其中c/s的操作if(count>0){ count=count-100 insertData();} b/s的操作if(count>0){ count=count-100 insertData();}假设一种可能,c/s和b/s的同时通过验证if(count>0),这样会出现一种情况,count是脏数据了,这是不允许的。这该如何解决?
解决方案
如果对数据库的访问服务是有多台机器的(不同的服务,或者服务部署了集群模式),可以采用如下几种方式之一:1. 使用程序的方式申请一个全局锁,比如使用Zookeeper就可以实现一个全局锁的功能,获得该锁的授权以后才能继续执行,这样保证对count的计算和insert都是串行执行的,不会存在脏数据;2. 使用某一个表的一条记录作为行锁(insert本身是无法加行锁的,因为insert之前数据还不存在),比如创建一个名为GLOBAL_LOCK的表,其中只有一条记录(假定有id这样一个字段,记录为id=1),操作之前做: select id from GLOBAL_LOCK where id=1 for update;这样也可以保证几个数据库事务本身是串行执行的;3. 操作之前锁整个表,这个和具体数据库有关以上两种方式都是基于全局锁的方式,效率比较低,在并发比较高的情况下慎用。题主的业务逻辑不清楚,如果是需要提高一些效率的话可能需要做一些缓冲的处理,不过要因具体的业务而定。
解决方案二:
看你用什么数据库了Oracle有Select for updateSqlServer有Ulock基本都是在事务中给数据加锁,在事务结束时候解锁。思路就是在一个事务开始的时候,把可能更新的数据锁上,另一个事务想读这个数据就要等待第一个事务解锁才行。这是悲观锁,后面的事务要等待。乐观锁就是给数据加个版本号的字段,等更新的时候检查版本号是不是自己当初查出来的版本号,如果不是就报错,或者重来。这种情况不等待,但是需要报错或者重来。