【问题标题】:$model->delete() or $model->save() crashes transaction process: 1305 SAVEPOINT trans3 does not exist$model->delete() 或 $model->save() 使事务进程崩溃:1305 SAVEPOINT trans3 不存在
【发布时间】:2019-06-06 07:45:31
【问题描述】:

现在已经 2 天了,我正在尝试解决一个问题,但仍然失败。感谢任何可以在此问题上提供帮助的人。

错误
我不断收到这条消息:
Doctrine\DBAL\Driver\PDOException : SQLSTATE[42000]: Syntax error or access violation: 1305 SAVEPOINT trans3 does not exist

一个动作有一个复杂的过程,我需要检查几个表。当它通过几个函数时,该过程会生成嵌套事务。

这不是我第一次使用事务,甚至是嵌套事务,到目前为止一切正常。只有这个函数会触发错误。
即使我从函数中删除 the DB::beginTransaction() 及其朋友,我仍然有错误。除了“trans3”变成“trans2”。

为了触发错误,我将函数代码简化为最简单的:

public function doStuff(Stuff $stuff, User $user)
    {
        $thing = Thing::where('user_id', $user->id)
            ->where('other_id', $stuff->id)
            ->get()
            ->first();
        $thing->delete();

        return false;
}

我已经尝试过的

  • 如简化代码所示,删除 DB::beginTransaction 等 不能防止错误。
  • 我还尝试在将属性从 true 更改为 false 后设置保存操作,$thing->fill(['property' => false]); $thing->save();,同样的错误。如果属性没有从数据库中的内容更改,则没有错误(例如$thing->fill(['property' => true]); $thing->save(); 不会触发错误,因为没有触发更新)。
  • 我试过用DB::raw('raw SQL'),没区别。
  • 我试过DB::delete('RAW SQL');,没区别。

技术环境
Laravel 5.5
mysql Ver 15.1 Distrib 10.0.36-MariaDB,用于 debian-linux-gnu (x86_64),使用 readline 5.2
PHP 7.0.32-0ubuntu0.16.04.1

我现在想到的唯一解决方案是删除所有父代码中的所有事务。即使我忽略它所代表的危险,所需的时间也超出了范围,所以我想确保没有其他选择。

有没有人有任何想法,领导,任何东西?
感谢您的宝贵时间。

【问题讨论】:

  • 您的代码在doStuff() 之前没有任何 DB::beginTransaction() 调用?
  • 是的,但我想保留它们,否则需要大量时间。
  • @Stéphane 你找到解决方案了吗?
  • @JonWhite 不,我实现了一个事务服务。我会写一个答案,但这不是修复,只是一种解决方法,我不喜欢它:/

标签: laravel-5 eloquent transactions


【解决方案1】:

这个答案可能来得太晚了,但我遇到了同样的问题。

只有当我决定尝试删除交易时,我才发现存在潜在错误。其中一个插入导致了完整性约束违规错误,我的测试报告为SQLSTATE[42000]: Syntax error or access violation: 1305 SAVEPOINT trans2 does not exist

一旦我解决了根本错误,我就恢复了我的交易并且一切正常。

【讨论】:

    【解决方案2】:

    就我而言,它在我的本地环境中工作,但在 CI 中失败。 最后,我找到了重点。 本地 MySQL

    sql_mode: NO_ZERO_IN_DATE, NO_ZERO_DATE, NO_ENGINE_SUBSTITUTION
    

    CI MySQL

    sql_mode: STRICT_TRANS_TABLES, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION
    

    发现创建表的时候没有给出varchar类型的默认值,赋值的时候忘记写了。

    因此,就我而言,主要原因是mysql严格模式

    可能对你有帮助。 (顺便说一下,我用的框架不是laravel。)

    【讨论】:

      【解决方案3】:

      这不是一个解决方案,只是一种解决方法,并不真正令人满意。但是,它仍然帮助我避免了几个问题。

      我创建了一个 TransactionService

      class TransactionService
      {
          /**
           * @return bool
           * @throws \Exception
           */
          public function beginTransaction() {
              if(DB::transactionLevel() === 0) {
                  DB::beginTransaction();
                  return true;
              }
              return false;
          }
      
          /**
           * @param bool $ongoingTransaction
           */
          public function commit($ongoingTransaction) {
              if($ongoingTransaction === true) {
                  DB::commit();
              }
          }
      
          /**
           * @param bool $ongoingTransaction
           */
          public function rollBack($ongoingTransaction) {
              if($ongoingTransaction === true) {
                  DB::rollBack();
              }
          }
      }
      

      我只通过它使用数据库事务:

      $sqlOngoingTransaction = Transaction::beginTransaction();
      try {
        // do stuff
      } catch (\Exception $e) {
        Transaction::rollBack($sqlOngoingTransaction);
        throw($e);
      }
      
      Transaction::commit($sqlOngoingTransaction);
      

      【讨论】:

        猜你喜欢
        • 2013-11-09
        • 2020-02-06
        • 2020-01-30
        • 2018-04-05
        • 1970-01-01
        • 1970-01-01
        • 2019-12-31
        • 1970-01-01
        • 2018-03-30
        相关资源
        最近更新 更多