浅谈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 相关文章推荐
如何在PHP中使用Oracle数据库(4)
Oct 09 PHP
php中经典方法实现判断多维数组是否为空
Oct 23 PHP
用穿越火线快速入门php面向对象
Feb 22 PHP
php之Smarty模板使用方法示例详解
Jul 08 PHP
PHP实现模仿socket请求返回页面的方法
Nov 04 PHP
WampServer搭建php环境时遇到的问题汇总
Jul 23 PHP
PHP版本升级到7.x后wordpress的一些修改及wordpress技巧
Dec 25 PHP
PHP代码重构方法漫谈
Apr 17 PHP
tp5实现微信小程序多图片上传到服务器功能
Jul 16 PHP
tp5(thinkPHP5)框架实现多数据库查询的方法
Jan 10 PHP
php文件后缀不强制为.php的实操方法
Sep 18 PHP
laravel5.6实现数值转换
Oct 23 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
php 获取完整url地址
2008/12/20 PHP
应用开发中涉及到的css和php笔记分享
2011/08/02 PHP
table标签的结构与合并单元格的实现方法
2013/07/24 PHP
twig模板获取全局变量的方法
2016/02/05 PHP
php获取是星期几的的一些常用姿势
2019/12/15 PHP
javascript实现动态增加删除表格行(兼容IE/FF)
2007/04/02 Javascript
Javascript绝句欣赏 一些经典的js代码
2012/02/22 Javascript
关于页面嵌入swf覆盖div层的问题的解决方法
2014/02/11 Javascript
事件委托与阻止冒泡阻止其父元素事件触发
2014/09/02 Javascript
如何在node的express中使用socket.io
2014/12/15 Javascript
WordPress中利用AJAX技术进行评论提交的实现示例
2016/01/12 Javascript
jQuery代码实现对话框右上角菜单带关闭×
2016/05/03 Javascript
javascript 利用arguments实现可变长参数
2016/11/21 Javascript
HTML5实现微信拍摄上传照片功能
2017/04/21 Javascript
js实现Tab选项卡切换效果
2020/07/17 Javascript
JS计算距当前时间的时间差实例
2017/12/29 Javascript
深入浅析vue组件间事件传递
2017/12/29 Javascript
js正则取值的结果数组调试方法
2018/10/10 Javascript
如何将百度地图包装成Vue的组件的方法步骤
2019/02/12 Javascript
react-native聊天室|RN版聊天App仿微信实例|RN仿微信界面
2019/11/12 Javascript
Python 正则表达式操作指南
2009/05/04 Python
python实现将文本转换成语音的方法
2015/05/28 Python
使用Python 正则匹配两个特定字符之间的字符方法
2018/12/24 Python
Pyqt5自适应布局实例
2019/12/13 Python
Python进阶之迭代器与迭代器切片教程
2020/01/29 Python
K最近邻算法(KNN)---sklearn+python实现方式
2020/02/24 Python
Keras 数据增强ImageDataGenerator多输入多输出实例
2020/07/03 Python
世界上最大的在线汽车租赁预订平台:Rentalcars.com(支持中文)
2018/10/12 全球购物
怎样建立和理解非常复杂的声明?例如定义一个包含N 个指向返回 指向字符的指针的函数的指针的数组?
2013/03/19 面试题
EJB的激活机制
2013/10/25 面试题
小学一年级学生评语
2014/04/22 职场文书
教师批评与自我批评材料
2014/10/16 职场文书
公司庆典欢迎词
2015/01/26 职场文书
升职自荐信怎么写
2015/03/05 职场文书
2015年妇女工作总结
2015/05/14 职场文书
文明礼貌主题班会
2015/08/14 职场文书