浅谈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数字字符串左侧补0、字符串填充和自动补齐的几种方法
May 10 PHP
ThinkPHP3.1新特性之对页面压缩输出的支持
Jun 19 PHP
php画图实例
Nov 05 PHP
PHP安装memcached扩展笔记
May 28 PHP
使用phpstorm和xdebug实现远程调试的方法
Dec 29 PHP
php实现的读取CSV文件函数示例
Feb 07 PHP
PHP使用第三方即时获取物流动态实例详解
Apr 27 PHP
PHP十六进制颜色随机生成器功能示例
Jul 24 PHP
PHP 结合 Boostrap 结合 js 实现学生列表删除编辑及搜索功能
May 21 PHP
Thinkphp5+Redis实现商品秒杀代码实例讲解
Dec 29 PHP
php实现自动生成验证码的实例讲解
Nov 17 PHP
php修改word的实例方法
Nov 17 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循环函数使用介绍之PHP基础入门教程
2013/09/21 PHP
php实现获取局域网所有用户的电脑IP和主机名、及mac地址完整实例
2014/07/18 PHP
Zend Framework数据库操作技巧总结
2017/02/18 PHP
javascript instanceof 与typeof使用说明
2010/01/11 Javascript
Grid得到选择行数据的方法总结
2011/01/17 Javascript
jQuery元素选择器用法实例
2014/12/23 Javascript
JS实现合并两个数组并去除重复项只留一个的方法
2015/12/17 Javascript
JS判断日期格式是否合法的简单实例
2016/07/11 Javascript
原生js轮播(仿慕课网)
2017/02/15 Javascript
ES6中箭头函数的定义与调用方式详解
2017/06/02 Javascript
Kindeditor单独调用多图上传实例
2017/07/31 Javascript
简单实现jQuery手风琴效果
2017/08/18 jQuery
jq源码解析之绑在$,jQuery上面的方法(实例讲解)
2017/10/13 jQuery
vue-cli 如何打包上线的方法示例
2018/05/08 Javascript
node.js中express模块创建服务器和http模块客户端发请求
2019/03/06 Javascript
JS实现贪吃蛇游戏
2019/11/15 Javascript
PyMongo安装使用笔记
2015/04/27 Python
python基于phantomjs实现导入图片
2016/05/13 Python
Python中xrange与yield的用法实例分析
2017/12/26 Python
对Python random模块打乱数组顺序的实例讲解
2018/11/08 Python
PyTorch加载预训练模型实例(pretrained)
2020/01/17 Python
TFRecord文件查看包含的所有Features代码
2020/02/17 Python
Python正则表达式学习小例子
2020/03/03 Python
Python爬虫之爬取淘女郎照片示例详解
2020/07/28 Python
html5给汉字加拼音加进度条的实现代码
2020/04/07 HTML / CSS
ALDO英国官网:加拿大女鞋品牌
2018/02/19 全球购物
生产部统计员岗位职责
2014/01/05 职场文书
打造完美自荐信
2014/01/24 职场文书
致长跑运动员加油稿
2014/02/20 职场文书
本科生就业推荐信
2014/05/19 职场文书
新闻传播专业求职信
2014/07/22 职场文书
幼儿教师师德师风演讲稿
2014/08/22 职场文书
2014年店长工作总结
2014/11/17 职场文书
拾金不昧表扬信
2015/01/16 职场文书
捐款感谢信
2015/01/20 职场文书
课改心得体会范文
2016/01/25 职场文书