浅谈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 相关文章推荐
Oracle 常见问题解答
Oct 09 PHP
php 全局变量范围分析
Aug 07 PHP
如何用php获取程序执行的时间
Jun 09 PHP
php5.5中类级别的常量使用介绍
Oct 02 PHP
PHP实现将浏览历史页面网址保存到cookie的方法
Jan 26 PHP
PHP生成压缩文件实例
Feb 07 PHP
yii2中的rules 自定义验证规则详解
Apr 19 PHP
Yii2中hasOne、hasMany及多对多关联查询的用法详解
Feb 15 PHP
解决PHP上传非标准格式的图片pjpeg失败的方法
Mar 12 PHP
PHP钩子与简单分发方式实例分析
Sep 04 PHP
thinkphp5使用无限极分类
Feb 18 PHP
php实现JWT(json web token)鉴权实例详解
Nov 05 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学习笔记 数组的常用函数
2011/06/13 PHP
php实现的替换敏感字符串类实例
2014/09/22 PHP
两个select多选模式的选项相互移动(示例代码)
2014/01/11 Javascript
node.js中的buffer.write方法使用说明
2014/12/10 Javascript
推荐一款jQuery插件模板
2015/01/09 Javascript
jQuery模拟原生态App上拉刷新下拉加载更多页面及原理
2015/08/10 Javascript
jQuery点击导航栏选中更换样式的实现代码
2017/01/23 Javascript
Javascript面试经典套路reduce函数查重
2017/03/23 Javascript
vue移动端裁剪图片结合插件Cropper的使用实例代码
2017/07/10 Javascript
Angular中响应式表单的三种更新值方法详析
2017/08/22 Javascript
vue组件与复用详解
2018/04/08 Javascript
vue实现的微信机器人聊天功能案例【附源码下载】
2019/02/18 Javascript
Vue实现小购物车功能
2020/12/21 Vue.js
前端如何实现动画过渡效果
2021/02/05 Javascript
python 查找文件夹下所有文件 实现代码
2009/07/01 Python
python中的闭包用法实例详解
2015/05/05 Python
Python中用于计算对数的log()方法
2015/05/15 Python
Python中使用urllib2模块编写爬虫的简单上手示例
2016/01/20 Python
浅谈Python的垃圾回收机制
2016/12/17 Python
插入排序_Python与PHP的实现版(推荐)
2017/05/11 Python
Python零基础入门学习之输入与输出
2019/04/03 Python
pygame实现贪吃蛇游戏(下)
2019/10/29 Python
python selenium自动化测试框架搭建的方法步骤
2020/06/14 Python
PyCharm Community安装与配置的详细教程
2020/11/24 Python
python复合条件下的字典排序
2020/12/18 Python
Python爬虫模拟登陆哔哩哔哩(bilibili)并突破点选验证码功能
2020/12/21 Python
Opencv+Python识别PCB板图片的步骤
2021/01/07 Python
html5的websockets全双工通信详解学习示例
2014/02/26 HTML / CSS
final, finally, finalize的区别
2012/03/01 面试题
十八大报告观后感
2014/01/28 职场文书
幼儿园大班家长评语
2014/04/17 职场文书
慈善晚会策划方案
2014/05/14 职场文书
承诺书范本大全
2015/05/04 职场文书
小学生班干部竞选稿
2015/11/20 职场文书
SQLServer2019 数据库环境搭建与使用的实现
2021/04/08 SQL Server
如何开发一个渐进式Web应用程序PWA
2021/05/10 Javascript