Laravel Eloquent:在单个数据库事务中保存模型和关系

Posted

技术标签:

【中文标题】Laravel Eloquent:在单个数据库事务中保存模型和关系【英文标题】:Laravel Eloquent: Save a Model and a relation within a single Database Transaction 【发布时间】:2020-09-05 12:47:38 【问题描述】:

我有以下 2 个数据库 (psql) 表定义如下:

create table product
(
    date date default CURRENT_DATE not null,
    updated_at timestamp(0) default CURRENT_TIMESTAMP(0) not null,
    product_id integer not null
)


create table product_offer
(
    date date default CURRENT_DATE not null,
    updated_at timestamp(0) default CURRENT_TIMESTAMP(0) not null,
    product_id integer not null,
    offer_id integer not null,
    price decimal,
    constraint product_fkey
        foreign key (date, updated_at, product_id) references product
)

在 Laravel 中,我的模型设置和关系定义如下:

public function offers()
    
        return $this->belongsToMany('App\Offer', 'product_offer', 'product_id', 'offer_id')
                    ->withPivot('date', 'updated_at','price');
    

我正在尝试在单个交易中创建新产品并为其附加报价:

$product = new Product; 
$product->product_id = 1; 
$offers = [1 => ['price' => 10]];

DB::beginTransaction();  
try 
    $product->save();
    $product->offers()->attach($offers);
    DB::commit();  
 catch (\Exception $e) 
    DB::rollback();  

但我从数据库中得到以下错误:

SQLSTATE[23503]:外键违规:7 错误:插入或更新 表“product_offer”违反外键约束“product_fkey” DETAIL: Key (date, updated_at, product_id)=(2020-05-19, 2020-05-19 12:19:47, 1) 不在“产品”表中。

能否请您告诉我解决此问题的最佳方法是什么?事务中的语句是否有可能乱序执行?还是 save() 方法可能会过早地提交事务?

请注意,上面的代码有时有效。例如,如果我进行 10 次尝试,则 50% 的时间交易成功,其余的我得到上述错误。

【问题讨论】:

第一:我认为你的外键约束不正确,第二:为什么不使用 Laravel 迁移表更容易。 根据我的经验,在 $product->offer() 被触发之前,$product->save() 不会在数据库服务器级别完成。为了妥协,我在 $product->offer().... 脚本之前从数据库重新加载 $product。例如,我在 $product->save() 之后做了一个 $product->fresh() @nikistag 这就是我的想法,我将外键约束更改为可推迟到事务的提交,但问题仍然存在。此外,在没有任何更改的情况下,这有时会起作用,有时会不起作用,这让人认为 Laravel 事务处理不一致。 刷新我的模型解决了我的问题......你的呢? 【参考方案1】:

Laravel 会期望你的主键是 'id'。如果您使用的不是“id”,则需要在模型上定义它。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Product extends Model

    protected $primaryKey = 'product_id';

https://laravel.com/docs/7.x/eloquent#eloquent-model-conventions

【讨论】:

以上是关于Laravel Eloquent:在单个数据库事务中保存模型和关系的主要内容,如果未能解决你的问题,请参考以下文章

Laravel Eloquent ORM 事务

Laravel Eloquent ORM 事务:为啥我们需要 ROLLBACK?

Laravel 4 中的 Eloquent 调用:处理多个表中的单个列

Laravel/Eloquent 建议覆盖 trait 属性?

Laravel Eloquent ORM 中的 join()->where()

如何使用 Laravel 的 Eloquent/Fluent 将每一行设置为相同的值?