浅谈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 正则表达式小结
Aug 31 PHP
PHP获取url的函数代码
Aug 02 PHP
解析php框架codeigniter中如何使用框架的session
Jun 24 PHP
JoshChen_php新手进阶高手不可或缺的规范介绍
Aug 16 PHP
重新认识php array_merge函数
Aug 31 PHP
自定义session存储机制避免会话保持问题
Oct 08 PHP
PHP的关于变量和日期处理的一些面试题目整理
Aug 10 PHP
Yii2.0 Basic代码中路由链接被转义的处理方法
Sep 21 PHP
php导出csv文件,可导出前导0实例代码
Nov 16 PHP
php实现URL加密解密的方法
Nov 17 PHP
php 如何禁用eval() 函数实例详解
Dec 01 PHP
PHP函数用法详解【初始化、嵌套、内置函数等】
Jun 02 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 数组遍历方法大全(foreach,list,each)
2010/06/30 PHP
Eclipse的PHP插件PHPEclipse安装和使用
2014/07/20 PHP
php中PDO方式实现数据库的增删改查
2015/05/17 PHP
php数值计算num类简单操作示例
2020/05/15 PHP
JQuery 1.4 中的Ajax问题
2010/01/23 Javascript
jQuery编写widget的一些技巧分享
2010/10/28 Javascript
jQuery拖拽div实现思路
2014/02/19 Javascript
JavaScript实现找出字符串中第一个不重复的字符
2014/09/03 Javascript
javascript在当前窗口关闭前检测窗口是否关闭
2014/09/29 Javascript
24款热门实用的jQuery插件推荐
2014/12/24 Javascript
jquery插件splitScren实现页面分屏切换模板特效
2015/06/16 Javascript
基于jQuery实现搜索关键字自动匹配功能
2020/03/26 Javascript
jQuery+ajax实现局部刷新的两种方法
2017/06/08 jQuery
Vue报错:Uncaught TypeError: Cannot assign to read only property’exports‘ of object’#‘的解决方法
2017/06/17 Javascript
Angular.js中angular-ui-router的简单实践
2017/07/18 Javascript
基于vue.js快速搭建图书管理平台
2017/10/29 Javascript
使用JavaScript保存文本文件到本地的两种方法
2019/01/22 Javascript
layui禁用侧边导航栏点击事件的解决方法
2019/09/25 Javascript
swiper4实现移动端导航栏tab滑动切换
2020/10/16 Javascript
[40:29]2018DOTA2亚洲邀请赛 4.7总决赛 LGD vs Mineski 第一场
2018/04/10 DOTA
[01:06:12]VP vs NIP 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
分分钟入门python语言
2018/03/20 Python
django admin.py 外键,反向查询的实例
2019/07/26 Python
python在OpenCV里实现投影变换效果
2019/08/30 Python
Python可视化工具如何实现动态图表
2020/10/23 Python
俄罗斯马克西多姆家居用品网上商店:Максидом
2020/02/06 全球购物
什么是WEB控件?使用WEB控件有哪些优势?
2012/01/21 面试题
代理协议书
2014/04/22 职场文书
学校对教师的评语
2014/04/28 职场文书
2015元旦文艺汇演主持稿(开场白+结束语)
2014/12/14 职场文书
我们的节日重阳节活动总结
2015/03/24 职场文书
学校勤俭节约倡议书
2015/04/29 职场文书
太行山上观后感
2015/06/05 职场文书
500字作文之难忘的同学
2019/12/20 职场文书
如何使用php生成zip压缩包
2021/04/21 PHP
Moment的feature导致线上bug解决分析
2022/09/23 Javascript