浅谈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 UTF-8、Unicode和BOM问题
May 18 PHP
PHP 5.3.1 安装包 VC9 VC6不同版本的区别是什么
Jul 04 PHP
php xml 入门学习资料
Jan 01 PHP
PHP+FFMPEG实现将视频自动转码成H264标准Mp4文件
Sep 24 PHP
PHP获取ip对应地区和使用网络类型的方法
Mar 11 PHP
PHP实现的简单网络硬盘
Jul 29 PHP
PHP并发多进程处理利器Gearman使用介绍
May 16 PHP
PHP简单获取网站百度搜索和搜狗搜索收录量的方法
Aug 23 PHP
PHP编程实现csv文件导入mysql数据库的方法
Apr 29 PHP
Laravel给生产环境添加监听事件(SQL日志监听)
Jun 19 PHP
PhpStorm本地断点调试的方法步骤
May 21 PHP
PHP中通过getopt解析GNU C风格命令行选项
Nov 18 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
【COS正片】蕾姆睡衣cos,纯洁可爱被治愈了 cn名濑弥七
2020/03/02 日漫
免费的ip数据库淘宝IP地址库简介和PHP调用实例
2014/04/08 PHP
PHP实现的方程求解示例分析
2016/11/11 PHP
PHP重定向与伪静态区别
2017/02/19 PHP
Thinkphp结合AJAX长轮询实现PC与APP推送详解
2017/07/31 PHP
jQuery获取css z-index在各种浏览器中的返回值
2010/09/15 Javascript
C#中TrimStart,TrimEnd,Trim在javascript上的实现
2011/01/17 Javascript
dtree 网页树状菜单及传递对象集合到js内,动态生成节点
2012/04/14 Javascript
js中数组(Array)的排序(sort)注意事项说明
2014/01/24 Javascript
JS方法调用括号的问题探讨
2014/01/24 Javascript
SuperSlide标签切换、焦点图多种组合插件
2015/03/14 Javascript
jQuery实现自定义事件的方法
2015/04/17 Javascript
javascript实现完美拖拽效果
2015/05/06 Javascript
微信小程序实战之上拉(分页加载)效果(2)
2017/04/17 Javascript
vue 2.8.2版本配置刚进入时候的默认页面方法
2018/09/21 Javascript
vue项目前端埋点的实现
2019/03/06 Javascript
jquery实现垂直手风琴导航栏
2020/02/18 jQuery
详解javascript void(0)
2020/07/13 Javascript
探究一道价值25k的蚂蚁金服异步串行面试题
2020/08/21 Javascript
[43:41]OG vs Newbee 2019国际邀请赛淘汰赛 胜者组 BO3 第一场 8.21.mp4
2020/07/19 DOTA
python多线程抓取天涯帖子内容示例
2014/04/03 Python
Python内置的HTTP协议服务器SimpleHTTPServer使用指南
2016/03/30 Python
Python连接数据库学习之DB-API详解
2017/02/07 Python
python使用多进程的实例详解
2018/09/19 Python
利用python GDAL库读写geotiff格式的遥感影像方法
2018/11/29 Python
使用Python画股票的K线图的方法步骤
2019/06/28 Python
用Python绘制漫步图实例讲解
2020/02/26 Python
美国糖果店:Sugarfina
2019/02/21 全球购物
俄罗斯大型在线书店:Читай-город
2019/10/10 全球购物
策划主管的工作职责
2013/11/24 职场文书
团队精神演讲稿
2013/12/31 职场文书
空气的环保标语
2014/06/12 职场文书
中学社团活动总结
2015/05/07 职场文书
创业计划书之家教托管
2019/09/25 职场文书
导游词之张家口
2019/12/13 职场文书
Vue+Flask实现图片传输功能
2022/04/01 Vue.js