浅谈Yii乐观锁的使用及原理


Posted in PHP onJuly 25, 2017

本文介绍了Yii乐观锁的使用及原理,自己做个学习笔记,也分享给大家,希望对大家有用处

原理:

数据表中使用一个int类型的字段来存储版本号,即该行记录的版本号。更新数据时,对比版本号是否一致

sql查询代码如下(伪代码)

update `test_ver` set `name`="lili" and `ver`=2 where `id`=1 and `ver`=1

即在更新时的where查询条件中,带上之前查询记录时得到的版本号,如果其他线程已经修改了该记录,则版本号势必不会一致,则更新失败

示例

数据表

假设有如下数据表

浅谈Yii乐观锁的使用及原理

模型类

appmodelsTestVer

该模型类,重写BaseActiveRecord类中的optimisticLock方法

声明用于记录版本号的字段

/**
 * 乐观锁
 * @return string
 */
public function optimisticLock()
{
 return 'ver';
}

public function updateRecord(){
 $ver = self::findOne(['id'=>1]);
 $ver->name = "lili";
 $res = $ver->update();
 return $res;
}

updateRecord修改id为1的记录

控制器

控制器中调用updateRecord方法

public function actionVersion(){
 $testVer = new TestVer();
 $res = $testVer->updateRecord();
 return $this->render('version');
}

Yii Debugger结果

查看database选项,可以查看到实际执行的sql语句。

有一条语句如下

UPDATE `test_ver` SET `name`='lili', `ver`='2' WHERE (`id`='1') AND (`ver`='1')

Yii乐观锁实现原理

实现原理在yiidbBaseActiveRecord::updateInteranl()方法

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);

 // 获取版本号字段的字段名,比如 ver
 $lock = $this->optimisticLock();

 // 如果 optimisticLock() 返回的是 null,那么,不启用乐观锁。
 if ($lock !== null) {
  // 这里的 $this->$lock ,就是 $this->ver 的意思;
  // 这里把 ver+1 作为要更新的字段之一。
  $values[$lock] = $this->$lock + 1;

  // 这里把旧的版本号作为更新的另一个条件
  $condition[$lock] = $this->$lock;
 }
 $rows = $this->updateAll($values, $condition);

 // 如果已经启用了乐观锁,但是却没有完成更新,或者更新的记录数为0;
 // 那就说明是由于 ver 不匹配,记录被修改过了,于是抛出异常。
 if ($lock !== null && !$rows) {
  throw new StaleObjectException('The object being updated is outdated.');
 }
 $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;
}

从上面的代码中,我们不难得出:

  1. 当 optimisticLock() 返回 null 时,乐观锁不会被启用。
  2. 版本号只增不减。
  3. 通过乐观锁的条件有2个,一是主键要存在,二是要能够完成更新。
  4. 当启用乐观锁后,只有下列两种情况会抛出 StaleObjectException 异常:
    1. 当记录在被别人删除后,由于主键已经不存在,更新失败。
    2. 版本号已经变更,不满足更新的第二个条件。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
提问的智慧
Oct 09 PHP
加强版phplib的DB类
Mar 31 PHP
PHP中使用CURL伪造来路抓取页面或文件
May 04 PHP
php数组的概述及分类与声明代码演示
Feb 26 PHP
解析PHP中的正则表达式以及模式匹配
Jun 19 PHP
php实现图片添加水印功能
Feb 13 PHP
PHP数组编码gbk与utf8互相转换的两种方法
Sep 01 PHP
php压缩文件夹最新版
Jul 18 PHP
java解析json方法总结
May 16 PHP
php中关于换行的实例写法
Sep 26 PHP
TP框架实现上传一张图片和批量上传图片的方法分析
Apr 23 PHP
PHP+Mysql分布式事务与解决方案深入理解
Feb 27 PHP
PHP异常处理定义与使用方法分析
Jul 25 #PHP
PHP实现防盗链的方法分析
Jul 25 #PHP
浅谈PHP发送HTTP请求的几种方式
Jul 25 #PHP
php 删除指定文件夹的实例讲解
Jul 25 #PHP
Laravel5.* 打印出执行的sql语句的方法
Jul 24 #PHP
PHP实现时间比较和时间差计算的方法示例
Jul 24 #PHP
PHP实现的登录页面信息提示功能示例
Jul 24 #PHP
You might like
Discuz! 5.0.0论坛程序中加入一段js代码,让会员点击下载附件前自动弹出提示窗口
2007/04/18 PHP
php+mysqli数据库连接的两种方式
2015/01/28 PHP
深入理解PHP中mt_rand()随机数的安全
2017/10/12 PHP
实例讲解PHP表单处理
2019/02/15 PHP
javascript YUI 读码日记之 YAHOO.util.Dom - Part.4
2008/03/22 Javascript
Javascript学习笔记6 prototype的提出
2010/01/11 Javascript
jQuery之ajax删除详解
2014/02/27 Javascript
纯css实现窗户玻璃雨滴逼真效果
2015/08/23 Javascript
javascript瀑布流布局实现方法详解
2016/02/17 Javascript
Angularjs整合微信UI(weui)
2016/03/15 Javascript
jQuery+CSS实现的table表格行列转置功能示例
2018/01/08 jQuery
详解jQuery-each()方法
2019/03/13 jQuery
详解ES6中的Map与Set集合
2019/03/22 Javascript
Vue使用Canvas绘制图片、矩形、线条、文字,下载图片
2019/04/26 Javascript
vue中使用props传值的方法
2019/05/08 Javascript
vue弹出框组件封装实例代码
2019/10/31 Javascript
js实现无限层级树形数据结构(创新算法)
2020/02/27 Javascript
[01:43]深扒TI7聊天轮盘语音出处4
2017/05/11 DOTA
php使用递归与迭代实现快速排序示例
2014/01/23 Python
python3生成随机数实例
2014/10/20 Python
python数据结构链表之单向链表(实例讲解)
2017/07/25 Python
python 读文件,然后转化为矩阵的实例
2018/04/23 Python
Python实现求解一元二次方程的方法示例
2018/06/20 Python
Django中更改默认数据库为mysql的方法示例
2018/12/05 Python
python实现彩色图转换成灰度图
2019/01/15 Python
Python搭建代理IP池实现接口设置与整体调度
2019/10/27 Python
python如何将两张图片生成为全景图片
2020/03/05 Python
python上下文管理器异常问题解决方法
2021/02/07 Python
Stutterheim瑞典:瑞典高级外套时装品牌
2019/06/24 全球购物
匡威俄罗斯官网:Converse俄罗斯
2020/05/09 全球购物
销售行业个人求职自荐信
2013/09/25 职场文书
毕业生求职推荐信
2013/11/04 职场文书
食品质量与安全专业毕业生求职信
2014/08/11 职场文书
离婚被告代理词
2015/05/23 职场文书
SpringCloud Feign请求头删除修改的操作代码
2022/03/20 Java/Android
python中数组和列表的简单实例
2022/03/25 Python