一、在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方法负责
1
2
3
4
|
public function optimisticLock() { return null; } |
这个方法返回 null ,表示不使用乐观锁,如果我们需要使用乐观锁的话,我们需要在我们的需要加锁的表的Model中重载optimisticLock方法
1
2
3
4
|
public function optimisticLock() { return 'version' ; } |
如上说明当前的ActiveRecord中,有一个 version 字段,可以为乐观锁所用
3、实现乐观锁
我们在Model中设置了版本号后,这时候我们的更新和删除都是乐观锁操作了,与正常操作数据库的方式一致
1
2
3
4
5
6
7
|
try { $crowd = Crowd::findOne([ 'crowd_id' => 12]); $crowd ->status = 1; $crowd ->save(); } catch (\Exception $e ) { return false; } |
在更新过程中,我们会调用到 yii\db\BaseActiveRecord::updateInternal()方法,此方法里面就具有处理乐观锁的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
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()方法,此方法里面就具有处理乐观锁的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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实现悲观锁,简单示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
$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(); } |
原文链接:https://blog.csdn.net/huaweichenai/article/details/127635042
暂无评论内容