Laravel Eloquent ORM 事务

Posted

技术标签:

【中文标题】Laravel Eloquent ORM 事务【英文标题】:Laravel Eloquent ORM Transactions 【发布时间】:2013-02-12 21:06:12 【问题描述】:

Eloquent ORM 非常好,但我想知道是否有一种简单的方法可以使用 innoDB 以与 PDO 相同的方式设置 mysql 事务,或者我是否必须扩展 ORM 才能实现这一点?

【问题讨论】:

【参考方案1】:

你可以这样做:

DB::transaction(function() 
      //
);

闭包中的所有内容都在事务中执行。如果发生异常会自动回滚。

【讨论】:

在闭包内我可以在类中调用查询吗?它会起作用吗? 遗憾的是,如果我正在创建以自己的相关方法存储记录的不同模型的实例,这对我不起作用。 如果我在事务中捕获异常(用于生成错误消息等),是否需要重新发出异常才能发生回滚? 很好的答案,但有几件事让我感到困惑:1.您需要添加“use DB;”这样做例如在模型文件的顶部 2. 与 JS 不同,您无法访问父作用域中的局部变量,除非您明确将它们传入,因此您需要添加“use”构造... DB::transaction( function() use ($user) ...stuffs 引用 $user... ); 如文档所述:“DB 外观的事务方法控制查询构建器和 Eloquent ORM 的事务。” -> laravel.com/docs/8.x/database#database-transactions.【参考方案2】:

如果你不喜欢匿名函数:

try 
    DB::connection()->pdo->beginTransaction();
    // database queries here
    DB::connection()->pdo->commit();
 catch (\PDOException $e) 
    // Woopsy
    DB::connection()->pdo->rollBack();


更新:对于 laravel 4,pdo 对象不再是公开的,所以:

try 
    DB::beginTransaction();
    // database queries here
    DB::commit();
 catch (\PDOException $e) 
    // Woopsy
    DB::rollBack();

【讨论】:

也可以使用快捷方式DB::beginTransaction() & DB::commit() & DB::rollback()。这样会干净一些。 请更新以使用@Flori 建议。它更干净。此外,向上移动新答案将使您的答案不那么混乱。在返回第二种方法之前,我使用了第一种方法。 对于旧版本的 Laravel,您可能需要:DB::connection()->getPdo()->beginTransaction(); 我个人认为带有回调的DB::transaction 更简洁,但缺点是如果您需要为不同的异常指定不同的处理程序,您将不得不返回尝试/捕获技术【参考方案3】:

如果你想使用 Eloquent,你也可以使用这个

这只是我项目中的示例代码

        /* 
         * Saving Question
         */
        $question = new Question;
        $questionCategory = new QuestionCategory;

        /*
         * Insert new record for question
         */
        $question->title = $title;
        $question->user_id = Auth::user()->user_id;
        $question->description = $description;
        $question->time_post = date('Y-m-d H:i:s');

        if(Input::has('expiredtime'))
            $question->expired_time = Input::get('expiredtime');

        $questionCategory->category_id = $category;
        $questionCategory->time_added = date('Y-m-d H:i:s');

        DB::transaction(function() use ($question, $questionCategory) 

            $question->save();

            /*
             * insert new record for question category
             */
            $questionCategory->question_id = $question->id;
            $questionCategory->save();
        );

【讨论】:

事务回调中的question->id 表达式返回零。 @ChristosPapoulas 你的意思是,我们无法在交易中获取自动增量 ID? 这会自动提交吗? @user254153 确定 @Jonjie 我相信你可以,但是事务提交到数据库之后会更好【参考方案4】:

如果您想避免闭包并乐于使用外观,则以下内容可以保持整洁:

try 
    \DB::beginTransaction();

    $user = \Auth::user();
    $user->fill($request->all());
    $user->push();

    \DB::commit();

 catch (Throwable $e) 
    \DB::rollback();

如果任何语句失败,提交将永远不会命中,事务也不会处理。

【讨论】:

如果任何语句失败,后续语句将不会运行。您仍然需要显式回滚事务。 @Jason 我已经更新了答案。对于大多数(所有?)数据库引擎,我有两种想法,当连接终止时,任何未提交的事务查询都不会被提交。不过,我同意你的说法,最好是明确的【参考方案5】:

我确定你不是在寻找闭包解决方案,试试这个以获得更紧凑的解决方案

 try
    DB::beginTransaction();

    /*
     * Your DB code
     * */

    DB::commit();
catch(\Exception $e)
    DB::rollback();

【讨论】:

【参考方案6】:

由于某种原因,在任何地方都很难找到此信息,因此我决定将其发布在这里,因为我的问题虽然与 Eloquent 交易有关,但正在改变这一点。

阅读THIS*** 的答案后,我意识到我的数据库表使用的是 MyISAM 而不是 InnoDB。

要在 Laravel(或其他任何地方)上运行事务,您的表必须设置为使用 InnoDB

为什么?

引用 MySQL Transactions and Atomic Operations 文档 (here):

MySQL 服务器(版本 3.23-max 和所有版本 4.0 及以上)支持使用 InnoDB 和 BDB 事务存储引擎的事务。 InnoDB 提供完全的 ACID 合规性。请参阅第 14 章,存储引擎。有关 InnoDB 在事务错误处理方面与标准 SQL 的差异的信息,请参阅第 14.2.11 节,“InnoDB 错误处理”。

MySQL Server 中的其他非事务性存储引擎(例如 MyISAM)遵循不同的数据完整性范式,称为“原子操作”。在事务方面,MyISAM 表实际上总是在 autocommit = 1 模式下运行。原子操作通常提供可比的完整性和更高的性能。

由于 MySQL Server 支持这两种范式,您可以决定是通过原子操作的速度还是使用事务特性来最好地服务于您的应用程序。可以基于每个表进行此选择。

【讨论】:

这适用于 DML,但并不总是适用于 DDL。【参考方案7】:

如果发生异常,事务会自动回滚。

Laravel 基本交易格式

    try
    DB::beginTransaction();

    /* 
    * SQL operation one 
    * SQL operation two
    ..................     
    ..................     
    * SQL operation n */


    DB::commit();
   /* Transaction successful. */
catch(\Exception $e)       

    DB::rollback();
    /* Transaction failed. */

【讨论】:

以上是关于Laravel Eloquent ORM 事务的主要内容,如果未能解决你的问题,请参考以下文章

使用 Eloquent ORM 执行 MYSQL 事务

Laravel Eloquent—基本概念用法

Laravel Eloquent ORM 的本地作用域

Laravel Eloquent ORM 关系命名约定

Laravel Eloquent ORM--整理(未转)

Laravel Eloquent ORM 似乎很简单