浅谈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环境配置 php5 mysql5 apache2 phpmyadmin安装与配置
Nov 17 PHP
比较好用的PHP防注入漏洞过滤函数代码
Apr 11 PHP
win7下memCache的安装过程(具体操作步骤)
Jun 28 PHP
easyui的tabs update正确用法分享
Mar 21 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(五)
Jun 23 PHP
php获得网站访问统计信息类Compete API用法实例
Apr 02 PHP
PHP实现的简单网络硬盘
Jul 29 PHP
PHP面向对象学习之parent::关键字
Jan 18 PHP
phpStudy配置多站点多域名和多端口的方法
Sep 01 PHP
php 使用mpdf实现指定字段配置字体样式的方法
Jul 29 PHP
Laravel 解决419错误 -ajax请求错误的问题(CSRF验证)
Oct 25 PHP
PHP读取文件,解决中文乱码UTF-8的方法分析
Jan 22 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
win7计划任务定时执行PHP脚本设置图解
2014/05/09 PHP
Zend Framework实现Zend_View集成Smarty模板系统的方法
2016/03/05 PHP
浅析Yii2集成富文本编辑器redactor实例教程
2016/04/25 PHP
javascript计算当月剩余天数(天数计算器)示例代码
2014/01/09 Javascript
三种检测iPhone/iPad设备方向的方法
2014/04/23 Javascript
javascript发送短信验证码实现代码
2015/11/12 Javascript
Jquery 效果使用详解
2015/11/23 Javascript
js replace(a,b)之替换字符串中所有指定字符的方法
2016/08/17 Javascript
form表单转Json提交的方法(推荐)
2016/09/23 Javascript
jQuery实现弹窗居中效果类似alert()
2017/02/27 Javascript
ES5学习教程之Array对象
2017/04/01 Javascript
使用jQuery实现购物车结算功能
2017/08/15 jQuery
用js简单提供增删改查接口
2019/05/12 Javascript
JS字符串与二进制的相互转化实例代码详解
2019/06/28 Javascript
vue组件命名和props命名代码详解
2019/09/01 Javascript
vue项目前端微信JSAPI与外部H5支付相关实现过程及常见问题
2020/04/14 Javascript
vue 动态添加的路由页面刷新时失效的原因及解决方案
2021/02/26 Vue.js
[26:52]LGD vs EG 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
python遍历文件夹并删除特定格式文件的示例
2014/03/05 Python
python中的错误处理
2016/04/10 Python
numpy实现合并多维矩阵、list的扩展方法
2018/05/08 Python
Flask框架学习笔记之使用Flask实现表单开发详解
2019/08/12 Python
Python3视频转字符动画的实例代码
2019/08/29 Python
python爬虫开发之Request模块从安装到详细使用方法与实例全解
2020/03/09 Python
Python动态强类型解释型语言原理解析
2020/03/25 Python
windows上彻底删除jupyter notebook的实现
2020/04/13 Python
python文件及目录操作代码汇总
2020/07/08 Python
python 常见的反爬虫策略
2020/09/27 Python
德国旅游网站:weg.de
2018/06/03 全球购物
法国一家多品牌成衣精品中/高档商店:Graduate Store
2019/08/28 全球购物
安踏官方商城:anta.cn
2019/12/16 全球购物
Android笔试题总结
2014/11/29 面试题
易程科技软件测试笔试
2013/03/24 面试题
法学个人求职信范文
2014/01/27 职场文书
清洁员岗位职责
2015/02/15 职场文书
一篇文章带你深入了解Mysql触发器
2021/08/02 MySQL