乐趣区

关于yii:Yii-实现乐观锁和悲观锁

一:在 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();
}
退出移动版