浅谈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 相关文章推荐
人大复印资料处理程序_补充篇
Oct 09 PHP
PHP 数组实例说明
Aug 18 PHP
php从右向左/从左向右截取字符串的实现方法
Nov 28 PHP
深入了解PHP类Class的概念
Jun 14 PHP
PHP Class&Object -- 解析PHP实现二叉树
Jun 25 PHP
从零开始学YII2框架(二)通过 Composer 安装扩展插件
Aug 20 PHP
PHP文件缓存类实现代码
Oct 26 PHP
php经典算法集锦
Nov 14 PHP
CodeIgniter集成smarty的方法详解
May 26 PHP
php利用gd库为图片添加水印
Nov 09 PHP
浅谈Laravel POST,PUT,PATCH 路由的区别
Oct 15 PHP
Laravel框架处理用户的请求操作详解
Dec 20 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/10/09 PHP
2.PHP入门
2006/10/09 PHP
php中使用exec,system等函数调用系统命令的方法(不建议使用,可导致安全问题)
2012/09/07 PHP
PHP上传文件时文件过大$_FILES为空的解决方法
2013/11/26 PHP
PHP积分兑换接口实例
2015/02/09 PHP
通过修改配置真正解决php文件上传大小限制问题(nginx+php)
2015/09/23 PHP
php基于PDO连接MSSQL示例DEMO
2016/07/13 PHP
PHP面向对象程序设计OOP继承用法入门示例
2016/12/27 PHP
Yii框架扩展CGridView增加导出CSV功能的方法
2017/05/24 PHP
浅谈php调用python文件
2019/03/29 PHP
window.open不被拦截的实现代码
2012/08/22 Javascript
类似天猫商品详情随浏览器移动的示例代码
2014/02/27 Javascript
基于Jquery实现键盘按键监听
2014/05/11 Javascript
Javascript URI 解析介绍
2015/03/15 Javascript
通过实例理解javascript中没有函数重载的概念
2015/06/03 Javascript
浅谈AngularJS中使用$resource(已更新)
2017/09/14 Javascript
easyUI使用分页过滤器对数据进行分页操作实例分析
2020/06/01 Javascript
[01:41]DOTA2超级联赛专访YYF 称一辈子难忘TI2
2013/05/28 DOTA
python编码总结(编码类型、格式、转码)
2016/07/01 Python
Python+tkinter使用80行代码实现一个计算器实例
2018/01/16 Python
利用Python进行数据可视化常见的9种方法!超实用!
2018/07/11 Python
Python 类属性与实例属性,类对象与实例对象用法分析
2019/09/20 Python
Python zip函数打包元素实例解析
2019/12/11 Python
tensorflow 限制显存大小的实现
2020/02/03 Python
PyCharm MySQL可视化Database配置过程图解
2020/06/09 Python
New Era英国官网:美国棒球帽品牌
2018/03/21 全球购物
印度领先的眼镜电子商务网站:Lenskart
2019/12/16 全球购物
Java面试中常遇到的问题,也是需要注意的几点
2013/08/30 面试题
外贸实习生自荐信范文
2013/11/24 职场文书
招商专员岗位职责
2014/02/08 职场文书
拉歌口号大全
2014/06/13 职场文书
学生检讨书
2015/01/27 职场文书
大足石刻导游词
2015/02/02 职场文书
雷锋之歌观后感
2015/06/10 职场文书
初中运动会闭幕词范本3篇
2019/12/09 职场文书
我国拿下天问一号火星着陆区附近 22 个地理实体命名:平乐、西柏坡、古田、漠河等
2022/04/29 数码科技