浅谈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 is_file 判断给定文件名是否为一个正常的文件
May 10 PHP
防止用户利用PHP代码DOS造成用光网络带宽
Mar 01 PHP
php URL跳转代码 减少外链
Jun 25 PHP
Ping服务的php实现方法,让网站快速被收录
Feb 04 PHP
PHP类与对象中的private访问控制的疑问
Nov 01 PHP
PHP批量采集下载美女图片的实现代码
Jun 03 PHP
Windows下的PHP 5.3.x安装 Zend Guard Loader教程
Sep 06 PHP
thinkphp使用phpmailer发送邮件的方法
Nov 24 PHP
调试WordPress中定时任务的相关PHP脚本示例
Dec 10 PHP
PHP获取星期几的常用方法小结
Dec 18 PHP
thinkphp5 框架结合plupload实现图片批量上传功能示例
Apr 04 PHP
laravel添加角色和模糊搜索功能的实现代码
Jun 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
php-accelerator网站加速PHP缓冲的方法
2008/07/30 PHP
深入PHP变量存储的详解
2013/06/13 PHP
解决php接收shell返回的结果中文乱码问题
2014/01/23 PHP
使用PHP生成二维码的两种方法(带logo图像)
2014/03/14 PHP
ThinkPHP有变量的where条件分页实例
2014/11/03 PHP
浅谈PHP中静态方法和非静态方法的相互调用
2016/10/04 PHP
用js统计用户下载网页所需时间的脚本
2008/10/15 Javascript
Jquery倒数计时按钮setTimeout的实例代码
2013/07/04 Javascript
JQuery 文本框回车跳到下一个文本框示例代码
2013/08/30 Javascript
纯js简单日历实现代码
2013/10/05 Javascript
jQuery回调函数的定义及用法实例
2014/12/23 Javascript
JS常用算法实现代码
2016/11/14 Javascript
JS返回只包含数字类型的数组实例分析
2016/12/16 Javascript
Spring shiro + bootstrap + jquery.validate 实现登录、注册功能
2017/06/02 jQuery
React中上传图片到七牛的示例代码
2017/10/10 Javascript
angular4 JavaScript内存溢出问题
2018/03/06 Javascript
koa2使用ejs和nunjucks作为模板引擎的使用
2018/11/27 Javascript
微信小程序实现消息框弹出动画
2020/04/18 Javascript
javascript(基于jQuery)实现鼠标获取选中的文字示例【测试可用】
2019/10/26 jQuery
Javascript如何实现双指控制图片功能
2020/02/25 Javascript
[01:00:49]DOTA2-DPC中国联赛 正赛 Ehome vs iG BO3 第二场 1月31日
2021/03/11 DOTA
python基于mysql实现的简单队列以及跨进程锁实例详解
2014/07/07 Python
Python中使用glob和rmtree删除目录子目录及所有文件的例子
2014/11/21 Python
使用Python对Excel进行读写操作
2017/03/30 Python
人工智能最火编程语言 Python大战Java!
2017/11/13 Python
python如何在列表、字典中筛选数据
2018/03/19 Python
Django实现单用户登录的方法示例
2019/03/28 Python
python实现两个经纬度点之间的距离和方位角的方法
2019/07/05 Python
python中的colorlog库使用详解
2019/07/05 Python
Python的in,is和id函数代码实例
2020/04/18 Python
Python应用实现处理excel数据过程解析
2020/06/19 Python
CSS3实现各种图形的示例代码
2016/10/19 HTML / CSS
业务经理岗位职责
2013/11/11 职场文书
大学生家政服务项目创业计划书
2014/01/30 职场文书
项目经理聘任书
2014/03/29 职场文书
2016年先进班集体事迹材料
2016/02/26 职场文书