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

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

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

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

<?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 方法。

百牛信息技术bainiu.ltd整理发布于博客园

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

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

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


Beanstalk

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

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

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

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

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

<?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 可能查询不到相应的数据,一旦我们分析到了这里,那么很可能会把写法修改成下面的样子:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

<?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 调用。 

?


1

2

3

4

5

6

7

8

9

<?php

protected function getRestoredPropertyValue($value)

{

  return $value instanceof ModelIdentifier

    ? (new $value->class)->findOrFail($value->id) : $value;

}

?>

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

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

<?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遇到的几个有代表性的报错以及解决方案,如果有问题欢迎大家一起交流。希望这篇文章对大家的学习或者工作能带来一定的帮助。

时间: 2024-08-02 06:59:29

Laravel中常见的错误与解决方法小结的相关文章

ArcMap中常见的错误及解决方法

来自:https://mp.weixin.qq.com/s?__biz=MzA4NjMxNzk1MQ==&mid=2247483736&idx=1&sn=1b21642d1f6e428679b0efba2ed26658&chksm=9fcbcf48a8bc465e93d33e7cbc00403a50785aad47cc2a0e62cecc11fe5a10e8f250f1cce290&mpshare=1&scene=23&srcid=&shar

SQLServer 报错:用户、组或角色&#39;XXX&#39; 在当前数据库中已存在. 错误:15023解决方法

背景: 最近在迁移SQLServer数据库2008时,新建用户后,做用户映射时. SQLServer 报错:用户.组或角色'XXX' 在当前数据库中已存在. 错误:15023. 下面讲一下解决的方法. 分析:    将数据库恢复到其他服务器时,数据库中包含一组用户和权限,但可能没有相应的登录或者登录所关联的用户可能不是相同的用户.    这种情况被称为存在"孤立用户".此时是不能通过新建登录或者是对同名登录授予对应数据库的"用户"权限来解决登录问题,    因为SQ

机器学习中常见的过拟合解决方法

在机器学习中,我们将模型在训练集上的误差称之为训练误差,又称之为经验误差,在新的数据集(比如测试集)上的误差称之为泛化误差,泛化误差也可以说是在模型在总体样本上的误差.对于一个好的模型应该是经验误差约等于泛化误差,也就是经验误差要收敛于泛化误差,根据霍夫丁不等式可知经验误差在一定条件下是可以收敛于泛化误差的. 当机器学习模型对训练集学习的太好的时候(再学习数据集的通性的时候,也学习了数据集上的特性,这些特性是会影响模型在新的数据集上的表达能力的,也就是泛化能力),此时表现为经验误差很小,当往往此

Directx11编程中遇到的错误/异常/解决方法

xnamath.h 报错: 在标识符“XMConvertToRadians”的前面 如下报错 1>d:\program files\microsoft directx sdk (june 2010)\include\xnamath.h(159): error C2146: 语法错误: 缺少“;”(在标识符“XMConvertToRadians”的前面) 1>d:\program files\microsoft directx sdk (june 2010)\include\xnamath.h(

directx11编程中遇到的错误及解决方法

(2016-05-10)xnamath.h 报错: 在标识符"XMConvertToRadians"的前面 报错如下: 1>d:\program files\microsoft directx sdk (june 2010)\include\xnamath.h(159): error C2146: 语法错误: 缺少";"(在标识符"XMConvertToRadians"的前面) 1>d:\program files\microsoft

Web服务器(容器)请求常见的错误及其解决方法

首先我们来看看容器如何找到service()方法?(1)当在浏览器中输入 http://localhost:8080/firstweb/sayHi 这个地址后,容器是如何找到 HelloServlet.class这个文件并执行的呢?(2)首先容器会根据firstweb这个应用名找到位于webapps下面对应的文件夹, (3)然后根据地址中的“/sayHi”到web.xml文件中寻找与之匹配的<url-pattern>节点,找到匹配的节点后会找到与该节点紧邻的<servlet-name&g

mysql中出现的错误及解决方法

一.mysql错误:ERROR 29 (HY000): File '/var/www/xiaoyou/static/upload/import/20130427105733.csv.txt' not found (Errcode: 13) -导入txt文件时出现的错误(LOAD DATA INFILE 'bj' INTO TABLE bjpi fields TERMINATED by ',' LINES TERMINATED BY '\n';) 解决方法: 1.如果不是root用户的话,先查看文

微信小程序在开发中遇到的错误与解决方法

1. 这种错误多半是该js文件中没有Page这个方法,就算是空的js也必须要把Page({ })写上去   √ 2. 这种错误多半是该json文件没有内容,所以必须要加上{ },就算是空内容也要加上{ }.√ 补一句:小程序里json文件中不允许有注释不然会报错. 3. 这个问题我不知道怎么解决了.iconClass在当前页面的js中的data里是一个数组,我只想让它使用第一个属性,但是这样不行.未解决 4. 这个错误就很明显了.小程序中的背景图片不能使用本地的路径,要么使用在服务器上的图片路径

phpstudy启用php_intl之后发生“计算机中丢失*.dll”错误的解决方法

最近新升级了新版的phpstudy,想试试php7感觉如何. 结果发现,安装完成之后,当开启了php_intl扩展的时候,让人头疼的问题来了. 每次启动phpstudy,都会报出一个错误"无法启动此程序,因为计算机中丢失icuio57.dll.尝试重新安装该程序以解决此问题". 然后就认为是系统中缺少这个dll文件,但是百度了一下竟然没有找到这个dll文件. 因为之前也报出过别的dll文件错误,都是直接百度找到,然后解压到C:/Windows/System32和C:\Windows\S