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 事务:为啥我们需要 ROLLBACK?
Laravel 4 中的 Eloquent 调用:处理多个表中的单个列
Laravel/Eloquent 建议覆盖 trait 属性?