浅谈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 PDO函数库详解
Apr 27 PHP
PHP数组传递是值传递而非引用传递概念纠正
Jan 31 PHP
PHP中的函数-- foreach()的用法详解
Jun 24 PHP
编写Smarty插件在模板中直接加载数据的详细介绍
Jun 26 PHP
php function用法如何递归及return和echo区别
Mar 07 PHP
php单态设计模式(单例模式)实例
Nov 18 PHP
php数组添加与删除单元的常用函数实例分析
Feb 16 PHP
PHP中实现crontab代码分享
Mar 26 PHP
Session 失效的原因汇总及解决丢失办法
Sep 30 PHP
PHP实现找出有序数组中绝对值最小的数算法分析
Aug 07 PHP
PHP实现图的邻接矩阵表示及几种简单遍历算法分析
Nov 24 PHP
Yii使用EasyWechat实现小程序获取用户的openID的方法
Apr 29 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代码
2006/12/06 PHP
ThinkPHP3.0略缩图不能保存到子目录的解决方法
2012/09/30 PHP
php中实现进程锁与多进程的方法
2016/09/18 PHP
yii使用bootstrap分页样式的实例
2017/01/17 PHP
img标签中onerror用法
2009/08/13 Javascript
jquery 与NVelocity 产生冲突的解决方法
2011/06/13 Javascript
jquery实现图片按比例缩放示例
2014/07/01 Javascript
jquery中one()方法的用法实例
2015/01/16 Javascript
JS右下角广告窗口代码(可收缩、展开及关闭)
2015/09/04 Javascript
js从外部获取图片的实现方法
2016/08/05 Javascript
JavaScript之Vue.js【入门基础】
2016/12/06 Javascript
详解Sea.js中Module.exports和exports的区别
2017/02/12 Javascript
微信小程序实战之自定义抽屉菜单(7)
2017/04/18 Javascript
详解Vue组件实现tips的总结
2017/11/01 Javascript
vue 使用Jade模板写html,stylus写css的方法
2018/02/23 Javascript
一个小时快速搭建微信小程序的方法步骤
2019/04/15 Javascript
Vue组件间通信方法总结(父子组件、兄弟组件及祖先后代组件间)
2019/04/17 Javascript
js 将线性数据转为树形的示例代码
2019/05/28 Javascript
vue给对象动态添加属性和值的实例
2019/09/09 Javascript
详解Vue template 如何支持多个根结点
2020/02/10 Javascript
JavaScript this关键字的深入详解
2021/01/14 Javascript
[02:32]DOTA2亚洲邀请赛 VG战队巡礼
2015/02/03 DOTA
[03:09]DOTA2亚洲邀请赛 LGD战队出场宣传片
2015/02/07 DOTA
Python抓取手机号归属地信息示例代码
2016/11/28 Python
python使用__slots__让你的代码更加节省内存
2018/09/05 Python
Python实现的合并两个有序数组算法示例
2019/03/04 Python
Python实现查找字符串数组最长公共前缀示例
2019/03/27 Python
Django中使用MySQL5.5的教程
2019/12/18 Python
解决Pycharm 中遇到Unresolved reference 'sklearn'的问题
2020/07/13 Python
如何在 Matplotlib 中更改绘图背景的实现
2020/11/26 Python
C/C++程序员常见面试题二
2015/11/19 面试题
经典c++面试题三
2015/07/08 面试题
丑小鸭教学反思
2014/02/03 职场文书
行政文员岗位职责
2015/02/04 职场文书
新闻稿件写作技巧
2015/07/18 职场文书
2016习总书记系列重要讲话心得体会
2016/01/15 职场文书