浅谈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和MySql来与ODBC数据连接
Oct 09 PHP
mysql5写入和读出乱码解决
Nov 25 PHP
介绍几个array库的新函数 php
Dec 29 PHP
神盾加密解密教程(二)PHP 神盾解密
Jun 08 PHP
PHP中preg_match正则匹配中的/u、/i、/s含义
Apr 17 PHP
大家都应该掌握的PHP关联数组使用技巧
Dec 25 PHP
PHP静态成员变量
Feb 14 PHP
Laravel利用gulp如何构建前端资源详解
Jun 03 PHP
PHP基于curl实现模拟微信浏览器打开微信链接的方法示例
Feb 15 PHP
php实现文章评论系统
Feb 18 PHP
PHP实现给定一列字符,生成指定长度的所有可能组合示例
Jun 22 PHP
Yii框架数据库查询、增加、删除操作示例
Oct 14 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
星际争霸 Starcraft 秘技补丁
2020/03/14 星际争霸
PHP strip_tags保留多个HTML标签的方法
2016/05/22 PHP
php+redis实现消息队列功能示例
2019/09/19 PHP
PHP实现递归的三种方法
2020/07/04 PHP
一个JS翻页效果
2007/07/23 Javascript
JS仿flash上传头像效果实现代码
2011/07/18 Javascript
分享XmlHttpRequest调用Webservice的一点心得
2012/07/20 Javascript
javascript去除字符串中所有标点符号和提取纯文本的正则
2014/06/07 Javascript
ECMAScript6函数默认参数
2015/06/12 Javascript
原生javascript+css3编写的3D魔方动画旋扭特效
2016/03/14 Javascript
javascript HTML5文件上传FileReader API
2020/03/27 Javascript
JavaScript中有关一个数组中最大值和最小值及它们的下表的输出的解决办法
2016/07/01 Javascript
微信小程序 地图map实例详解
2017/06/07 Javascript
原生JavaScript实现Ajax异步请求
2017/11/19 Javascript
基于 Vue.js 之 iView UI 框架非工程化实践记录(推荐)
2017/11/21 Javascript
nodeJs爬虫的技术点总结
2018/05/13 NodeJs
基于小程序请求接口wx.request封装的类axios请求
2020/07/02 Javascript
Python中函数的多种格式和使用实例及小技巧
2015/04/13 Python
为Python的web框架编写MVC配置来使其运行的教程
2015/04/30 Python
Python 编程速成(推荐)
2019/04/15 Python
python print出共轭复数的方法详解
2019/06/25 Python
python Jupyter运行时间实例过程解析
2019/12/13 Python
python实现TCP文件传输
2020/03/20 Python
python文件排序的方法总结
2020/09/13 Python
python删除文件、清空目录的实现方法
2020/09/23 Python
HTML5实现QQ聊天气泡效果
2017/06/26 HTML / CSS
选购国际女性时装设计师品牌:IFCHIC(支持中文)
2018/04/12 全球购物
英国异国风情旅游网站:Travel Talk Tours(团体旅游、探险旅游、帆船假期)
2018/07/26 全球购物
宣传口号大全
2014/06/16 职场文书
2014年青年志愿者工作总结
2014/12/09 职场文书
党员“一帮一”活动总结
2015/05/07 职场文书
教师见习总结范文
2015/06/23 职场文书
人力资源部工作计划
2019/05/14 职场文书
用python实现监控视频人数统计
2021/05/21 Python
详解thinkphp的Auth类认证
2021/05/28 PHP
Nginx下SSL证书安装部署步骤介绍
2021/12/06 Servers