当前位置: 首页 > 后端技术 > PHP

Yii实现乐观锁和悲观锁

时间:2023-03-29 16:56:42 PHP

一:Yii中的乐观锁Optimisticlocking(乐观锁)体现了一种大胆务实的态度。使用乐观锁的前提是在实际应用中,发生冲突的概率比较低。他的设计和实现简单明了。在目前的Web应用中,乐观锁的使用具有绝对的优势。因此,在Yii中,支持ActiveReocrd乐观锁1:在yii中实现乐观锁步骤,1):在需要加锁的表中增加一个字段,表示版本号。在这里,我通常使用版本字段作为版本号字段。注意,如果你需要加锁的表已经生成了一个Model,那么该表对应的Model要加上你在Model2中添加的版本号字段(version)信息:更新表中的字段时,使用try。..catch看看它是否有效捕获yii\db\StaleObjectException。如果你捕获了yii\db\StaleObjectException,这意味着在修改这条记录的过程中这条记录已经被修改了。做相应的提示2:Yii1)中实现乐观锁):声明yii中的指定字段为版本号版本号是实现乐观锁的根。所以第一步,我们要告诉Yii哪个字段是版本号字段,声明版本号的方法由yii\db\BaseActiveRecord(vendor/yiisoft/yii2/db/BaseActiveRecord)中的optimisticLock方法负责publicfunctionoptimisticLock(){returnnull;}该方法返回null,表示没有使用乐观锁。如果我们需要使用乐观锁,就需要在我们需要加锁的表的Model中重载optimisticLock方法。publicfunctionoptimisticLock(){return'version';}上面解释过,在当前的ActiveRecord中,有一个version字段,可以用来做乐观锁2:实现乐观锁。操作数据库的方式一样try{$crowd=Crowd::findOne(['crowd_id'=>12]);$人群->状态=1;$crowd->save();}catch(\Exception$e){returnfalse;}在更新过程中,我们会调用yii\db\BaseActiveRecord::updateInternal()方法,里面有处理乐观锁的代码protectedfunctionupdateInternal($attributes=null){if(!$this->beforeSave(false)){返回false;}//获取后面要更新的字段和新的字段值$values=$this->getDirtyAttributes($attributes);如果(empty($values)){$this->afterSave(false,$values);返回0;}//使用原ActiveRecord的主键作为等待更新记录的条件,也就是说最多只有一条记录$condition=$this->getOldPrimaryKey(true);//获取版本号字段的字段名,例如version$lock=$this->optimisticLock();//如果optimisticLock()返回null,则未启用乐观锁定。if($lock!==null){//这里的$this->$lock表示$this->version;version+1在这里用作要更新的字段之一。$values[$lock]=$this->$lock+1;//这里旧版本号作为更新的另一个条件$condition[$lock]=$this->$lock;}$rows=static::updateAll($values,$condition);//如果开启了乐观锁,但是更新还没有完成,或者更新的记录数为0;//表示由于版本不匹配导致记录被修改,所以抛出异常。if($lock!==null&&!$rows){thrownewStaleObjectException('正在更新的对象已过时。');}if(isset($values[$lock])){$this->$lock=$values[$lock];}$changedAttributes=[];foreach($valuesas$name=>$value){$changedAttributes[$name]=isset($this->_oldAttributes[$name])?$this->_oldAttributes[$name]:null;$this->_oldAttributes[$name]=$value;}$this->afterSave(false,$changedAttributes);返回$行;在删除过程中,我们会调用yii\db\BaseActiveRecord::delete()方法,其中有处理乐观锁的代码publicfunctiondelete(){$result=false;if($this->beforeDelete()){//在删除的SQL语句中,WHERE部分为主键$condition=$this->getOldPrimaryKey(true);//获取版本号字段的字段名,如version$lock=$this->optimisticLock();//如果启用了乐观锁,则WHERE部分再添加一个条件,版本号如果($lock!==null){$condition[$lock]=$this->$lock;}$result=static::deleteAll($condition);if($lock!==null&&!$result){thrownewStaleObjectException('被删除的对象已过时。');}$this->_oldAttributes=null;$this->afterDelete();}返回$结果;现在我们已经完成了乐观锁相关的代码,我们只需要在Model中设置一个版本号字段即可。2:在Yii中实现悲观锁。yii中实现悲观锁的步骤1):在修改任何记录之前,尝试对记录进行加锁2):如果加锁失败,说明记录正在被修改,当前查询可能要等待或者抛出异常3):如果加锁成功,可以修改记录,交易完成后解锁。2:yii中的悲观锁实现使用select.....forupdate实现悲观锁。一个简单的例子如下:$transaction=Yii::$app->db->beginTransaction();try{//查询id为12的数据并锁定$sql="select*fromubo_crowdwherecrowd_id=12for更新”;$crowd=Yii:$app->db->createCommand($sql)->queryOne();//更新数据$crowd1=Crowd::findOne(['crowd_id'=>$人群['crowd_id']]);$crowd1->sort+=1;if($crowd1->save()){$transaction->commit();}}catch(Exception$e){$transaction->rollBack();}