$ model-> delete()或$ model-> save()使事务处理崩溃:1305 SAVEPOINT trans3不存在

时间:2019-01-11 11:29:04

标签: laravel-5 eloquent transactions

已经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
适用于使用readline 5.2的debian-linux-gnu(x86_64)的mysql Ver 15.1 Distrib 10.0.36-MariaDB PHP 7.0.32-0ubuntu0.16.04.1

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

有人有什么主意,领导力吗?
谢谢您的宝贵时间。

3 个答案:

答案 0 :(得分:1)

就我而言,它在我的本地环境中工作,但在 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。)

答案 1 :(得分:0)

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

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

解决基本错误后,我恢复了交易,一切正常。

答案 2 :(得分:0)

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

我创建了一个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);