一:在Yii中实现乐观锁
乐观锁(optimistic locking)体现出大胆、求实的态度。应用乐观锁的前提是, 理论利用当中,发生冲突的概率比拟低。他的设计和实现间接而简洁。 目前Web利用中,乐观锁的应用占有绝对优势。因而在Yii为ActiveReocrd乐观锁反对
1:在yii中实现乐观锁步骤、
1):给须要加锁的表增加一个字段,用于示意版本号,这里我个别选手version字段作为版本号字段,留神,如果你须要加锁的表曾经生成Model了,那么对应表的Model要将你增加的版本号字段(version)信息退出Model
2):在更新表中字段时,应用 try ... catch 看看是否能捕捉一个 yii\db\StaleObjectException 异样,如果捕捉到yii\db\StaleObjectException 异样,阐明在本次批改这个记录的过程中, 该记录曾经被批改过了,作出相应提醒
2:Yii中实现乐观锁
1):在yii中申明指定字段为版本号
版本号是实现乐观锁的基本所在。所以第一步,咱们要通知Yii,哪个字段是版本号字段,申明版本号的办法由yii\db\BaseActiveRecord(vendor/yiisoft/yii2/db/BaseActiveRecord)中的optimisticLock办法负责
public function optimisticLock(){ return null;}
这个办法返回 null ,示意不应用乐观锁,如果咱们须要应用乐观锁的话,咱们须要在咱们的须要加锁的表的Model中重载optimisticLock办法
public function optimisticLock(){ return 'version';}
如上阐明以后的ActiveRecord中,有一个 version 字段,能够为乐观锁所用
2:实现乐观锁
咱们在Model中设置了版本号后,这时候咱们的更新和删除都是乐观锁操作了,与失常操作数据库的形式统一
try { $crowd = Crowd::findOne(['crowd_id' => 12]); $crowd->status = 1; $crowd->save();} catch (\Exception $e) { return false;}
在更新过程中,咱们会调用到 yii\db\BaseActiveRecord::updateInternal()办法,此办法外面就具备解决乐观锁的代码
protected function updateInternal($attributes = null) { if (!$this->beforeSave(false)) { return false; } // 获取等下要更新的字段及新的字段值 $values = $this->getDirtyAttributes($attributes); if (empty($values)) { $this->afterSave(false, $values); return 0; } // 把原来ActiveRecord的主键作为等下更新记录的条件,也就是说,等下更新的,最多只有1个记录。 $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; // 那就阐明是因为 version 不匹配,记录被批改过了,于是抛出异样。 if ($lock !== null && !$rows) { throw new StaleObjectException('The object being updated is outdated.'); } if (isset($values[$lock])) { $this->$lock = $values[$lock]; } $changedAttributes = []; foreach ($values as $name => $value) { $changedAttributes[$name] = isset($this->_oldAttributes[$name]) ? $this->_oldAttributes[$name] : null; $this->_oldAttributes[$name] = $value; } $this->afterSave(false, $changedAttributes); return $rows; }
在删除过程中,咱们会调用到 yii\db\BaseActiveRecord::delete()办法,此办法外面就具备解决乐观锁的代码
public function delete() { $result = false; if ($this->beforeDelete()) { // 删除的SQL语句中,WHERE局部是主键 $condition = $this->getOldPrimaryKey(true); // 获取版本号字段的字段名,比方 version $lock = $this->optimisticLock(); // 如果启用乐观锁,那么WHERE局部再加一个条件,版本号 if ($lock !== null) { $condition[$lock] = $this->$lock; } $result = static::deleteAll($condition); if ($lock !== null && !$result) { throw new StaleObjectException('The object being deleted is outdated.'); } $this->_oldAttributes = null; $this->afterDelete(); } return $result; }
如上咱们就晓得了,在yii中曾经有了乐观锁相干的代码了,咱们只须要在Model中设置一个版本号字段即可
二:在Yii中实现乐观锁
正如其名字,乐观锁(pessimistic locking)体现了一种审慎的处事态度
1:在yii中实现乐观锁的步骤
1):在对任意记录进行批改前,先尝试为该记录加上锁
2):如果加锁失败,阐明该记录正在被批改,那么以后查问可能要期待或者抛出异样
3):如果胜利加锁,那么就能够对记录做批改,事务实现后就会解锁了
2:yii中乐观锁实现
应用select.....for update实现乐观锁,简略示例如下:
$transaction = Yii::$app->db->beginTransaction();try{ //查问id为12的这条数据并且锁定 $sql = "select * from ubo_crowd where crowd_id = 12 for update"; $crowd = Yii::$app->db->createCommand($sql)->queryOne(); //更新数据 $crowd1 = Crowd::findOne(['crowd_id' => $crowd['crowd_id']]); $crowd1->sort += 1; if($crowd1->save()){ $transaction->commit(); }}catch(Exception $e){ $transaction->rollBack();}