Laravel中常见的错误与解决方法小结


Posted in Javascript onAugust 30, 2016

一、报错: 「Can't swap PDO instance while within transaction」

通过查询 Laravel 源代码,可以确认异常是在 setPdo 方法中抛出的: 

<?php

public function setPdo($pdo)
{
  if ($this->transactions >= 1) {
    throw new RuntimeException("
      Can't swap PDO instance while within transaction.
    ");
  }

  $this->pdo = $pdo;

  return $this;
}

?>

按字面意思理解,出现此错误是因为在开启了事务的情况下,切换了数据库连接。不过有时候,即便代码里没有显式的切换数据库连接,也有可能出现此错误。比如说在执行查询语句出错的时候,系统会通过 tryAgainIfCausedByLostConnection 方法判断问题是不是因为丢失连接导致的,如果是,那么系统会通过 reconnect 方法重新连接,在重新连接的时候,系统会通过 disconnect 方法执行一些清理工作,其中调用了 setPdo 方法。

理清了前因后果,自然就知道如何解决问题了:检查网络情况,确认数据库连接丢失的原因,这可能是某个设备有问题,也可能是某个 timeout 设置不当所致。一个相对 dirty 的处理方法是在查询前执行一下 DB::reconnect() 方法重新连接一下数据库。

二、报错:「Cannot delete job: NOT_FOUND」

此问题实际上和 Laravel 没太大关系,而是队列服务 Beanstalk 导致的。

Laravel中常见的错误与解决方法小结
Beanstalk

要解决这个问题,需要先理解一个消息的生命周期:当一个消息被放入队列的时候,它就进入了 READY 状态,与此同时,它会关联一个 TTR(time to run) 计时器,表示此消息允许运行的时间,当此消息被消费时,它就进入了 RESERVED 状态,消费完后,此消息就会被删除,如果消费的时间过长,比 TTR 还长,那么系统会认为认为此消费者已经挂了,进而会把消息从 RESERVED 状态退回到 READY 状态,交给另一个消费者重新处理。于是乎同一个消息可能会被多个消费者处理,第一个处理完的消费者可以正常的删除消息,而其余的消费者在删除消息的时候就会报无法删除的错误。

解决方法很简单,首先,需要确保 TTR 的设置不能太小;其次,实际上 Beanstalk 提供了一个专门的 touch 命令来解决执行时间过长的问题,此外,有些时候我们可能需要在应用层面上通过加锁来规避同一个消息被多个消费者同时处理的情况。

三、报错:「No query results for model」

在激活了 Laravel 读写分离的前提下,当消费者处理消息的时候,可能会收到类似错误。一个有潜在问题的队列命令大概如下所示: 

<?php

class Foo extends Command implements SelfHandling, ShouldBeQueued
{
  use InteractsWithQueue, SerializesModels;

  protected $bar;

  public function __construct($id)
  {
    $this->bar = Bar::find($id);
  }

  public function handle()
  {
    // $this->bar
  }
}

?>

很明显,当开启了 Laravel 读写分离的时候,因为主从延迟的缘故,所以 find 可能查询不到相应的数据,一旦我们分析到了这里,那么很可能会把写法修改成下面的样子:

<?php

class Foo extends Command implements SelfHandling, ShouldBeQueued
{
  use InteractsWithQueue, SerializesModels;

  protected $bar;

  public function __construct($id)
  {
    $this->bar = Bar::onWriteConnection()->find($id);
  }

  public function handle()
  {
    // $this->bar
  }
}

?>

也就是说,通过 Laravel 的 onWriteConnection 方法把查询固定在主服务器上,不过实际上无效。问题症结在于反序列化的时候,系统会在从服务器上一次 findOrFail 调用。 

<?php

protected function getRestoredPropertyValue($value)
{
  return $value instanceof ModelIdentifier
    ? (new $value->class)->findOrFail($value->id) : $value;
}

?>

因为我们无法 HACK 到框架内部,所以 onWriteConnection 就没有意义了。其实换个角度看问题,只要在系列化的时候,保证别用数据库对象做属性即可:

<?php

class Foo extends Command implements SelfHandling, ShouldBeQueued
{
  use InteractsWithQueue, SerializesModels;

  protected $id;

  public function __construct($id)
  {
    $this->id = $id;
  }

  public function handle()
  {
    $bar = Bar::onWriteConnection()->find($this->id);
  }
}

?>

四、总结

以上就是我在使用Laravel遇到的几个有代表性的报错以及解决方案,如果有问题欢迎大家一起交流。希望这篇文章对大家的学习或者工作能带来一定的帮助。

Javascript 相关文章推荐
基于jquery的一个浮动框(扩展性比较好 )
Aug 27 Javascript
JS上传图片前的限制包括(jpg jpg gif及大小高宽)等
Dec 19 Javascript
javascript字母大小写转换的4个函数详解
May 09 Javascript
JS和jQuery使用submit方法无法提交表单的原因分析及解决办法
May 17 Javascript
纯JS实现弹性导航条效果
Mar 06 Javascript
React中使用collections时key的重要性详解
Aug 07 Javascript
利用JavaScript的%做隔行换色的实例
Nov 25 Javascript
Vue开发实现吸顶效果的示例代码
Aug 21 Javascript
微信小程序实现两个页面传值的方法分析
Dec 11 Javascript
JS实现的A*寻路算法详解
Dec 14 Javascript
浅谈react-router@4.0 使用方法和源码分析
Jun 04 Javascript
如何通过Proxy实现JSBridge模块化封装
Oct 22 Javascript
js中常用的Tab切换效果(推荐)
Aug 30 #Javascript
基于cssSlidy.js插件实现响应式手机图片轮播效果
Aug 30 #Javascript
JavaScript探测CSS动画是否已经完成的方法
Aug 30 #Javascript
基于JavaScript实现鼠标箭头移动图片跟着移动
Aug 30 #Javascript
很棒的js Tab选项卡切换效果
Aug 30 #Javascript
js改变透明度实现轮播图的算法
Aug 24 #Javascript
标准的js无缝滚动效果
Aug 30 #Javascript
You might like
PHP5 面向对象程序设计
2008/02/13 PHP
PHPMyAdmin 快速配置方法
2009/05/11 PHP
Drupal7连接多个数据库及常见问题解决
2014/03/02 PHP
Centos下升级php5.2到php5.4全记录(编译安装)
2015/04/03 PHP
[原创]smarty简单模板变量输出方法
2016/07/09 PHP
PHP后台微信支付和支付宝支付开发
2017/04/28 PHP
PHP生成腾讯云COS接口需要的请求签名
2018/05/20 PHP
js直接编辑当前cookie的脚本
2008/09/14 Javascript
javascript Prototype 对象扩展
2009/05/15 Javascript
JQuery 解析多维的Json数据格式
2009/11/02 Javascript
将Datatable转化成json发送前台实现思路
2013/09/06 Javascript
JS按回车键实现登录的方法
2014/08/25 Javascript
JS实现兼容性较好的随屏滚动效果
2015/11/09 Javascript
javascript图片预加载完整实例
2015/12/10 Javascript
Angularjs 实现分页功能及示例代码
2016/09/14 Javascript
JS ES6中setTimeout函数的执行上下文示例
2017/04/27 Javascript
jQuery实现手势解锁密码特效
2017/08/14 jQuery
jQuery实现图片上传预览效果功能完整实例【测试可用】
2018/05/28 jQuery
Vue的自定义组件不能使用click方法的解决
2020/07/28 Javascript
[56:00]2018DOTA2亚洲邀请赛 4.6 淘汰赛 VP vs TNC 第二场
2018/04/10 DOTA
如何在Django中设置定时任务的方法示例
2019/01/18 Python
python选取特定列 pandas iloc,loc,icol的使用详解(列切片及行切片)
2019/08/06 Python
python可视化篇之流式数据监控的实现
2019/08/07 Python
解决python replace函数替换无效问题
2020/01/18 Python
Python标准库:内置函数max(iterable, *[, key, default])说明
2020/04/25 Python
python自动化测试三部曲之request+django实现接口测试
2020/10/07 Python
python使用selenium爬虫知乎的方法示例
2020/10/28 Python
HTML5 与 XHTML2
2008/10/17 HTML / CSS
Antonioli美国在线商店:时尚前卫奢华
2019/07/29 全球购物
运动员获奖感言
2014/08/15 职场文书
小学师德师风演讲稿
2014/09/02 职场文书
2014县委书记四风对照检查材料思想汇报
2014/09/21 职场文书
个人融资协议书
2014/10/02 职场文书
工作失职检讨书(精华篇)
2014/10/15 职场文书
css 边框添加四个角的实现代码
2021/10/16 HTML / CSS
最新动漫情报:2022年7月新番定档超过30部, OVERLORD骨王第四季也在其中噢
2022/05/04 日漫