添加到https://stackoverflow.com/a/57495773并回答 Q4:大多数用户不需要saveOrFail(). save()已经抛出异常,只是在新事务中saveOrFail()调用。save()
在我看来,该方法的名称具有误导性。其他 Eloquent 方法,例如find不抛出异常,但有一个findOrFail对应的方法。这不是这种情况,save并且saveOrFail可以在此处的代码中查看:https ://github.com/laravel/framework/blob/5.8/src/Illuminate/Database/Eloquent/Model.php#L693
public function saveOrFail(array $options = [])
{
return $this->getConnection()->transaction(function () use ($options) {
return $this->save($options);
});
}
的主要用途saveOrFail()是如果您想从失败的数据库端更新或插入中恢复。如果我们以下面的模式为例:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class SaveOrFailDemo extends Migration
{
public function up()
{
Schema::create('save_or_fails', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('word')->unique();
});
}
public function down()
{
Schema::dropIfExists('save_or_fails');
}
}
使用这个基本模型:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class SaveOrFail extends Model
{
}
这个测试命令:
<?php
namespace App\Console\Commands;
use App\SaveOrFail;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class TrySaveOrFail extends Command
{
protected $signature = 'try:save-or-fail {--fail}';
public function handle()
{
DB::transaction(function () {
// cleanup old tries
SaveOrFail::query()->delete();
$model = new SaveOrFail();
$saveFunction = $this->option('fail')
? fn () => $model->saveOrFail()
: fn () => $model->save();
$maxSaveAttempts = 3;
$word = 'demo';
// force a UNIQUE violation to occur
$duplicate = new SaveOrFail();
$duplicate->word = $word . '0';
$duplicate->save();
for ($currentSaveAttempt = 0; $currentSaveAttempt < $maxSaveAttempts; $currentSaveAttempt++) {
$model->word = $word . $currentSaveAttempt;
try {
$saveFunction();
$this->info("Saved! {$model->word}");
return $model;
} catch (\PDOException $ex) {
$this->warn($ex->getMessage());
}
}
});
}
}
php artisan try:save-or-fail使用 Postgres运行将永远不会保存$model. 第一次 UNIQUE 违规会导致事务进入中止状态:
application@f72fb45f3bfa:/app$ php artisan try:save-or-fail
SQLSTATE[23505]: Unique violation: 7 ERROR: duplicate key value violates unique constraint "save_or_fails_word_unique"
DETAIL: Key (word)=(demo0) already exists. (SQL: insert into "save_or_fails" ("word", "updated_at", "created_at") values (demo0, 2021-06-07 19:39:24, 2021-06-07 19:39:24) returning "id")
SQLSTATE[25P02]: In failed sql transaction: 7 ERROR: current transaction is aborted, commands ignored until end of transaction block (SQL: insert into "save_or_fails" ("word", "updated_at", "created_at") values (demo1, 2021-06-07 19:39:24, 2021-06-07 19:39:24) returning "id")
SQLSTATE[25P02]: In failed sql transaction: 7 ERROR: current transaction is aborted, commands ignored until end of transaction block (SQL: insert into "save_or_fails" ("word", "updated_at", "created_at") values (demo2, 2021-06-07 19:39:24, 2021-06-07 19:39:24) returning "id")
但是,由于saveOrFail()在它自己的事务中运行,我们能够从中恢复:
application@f72fb45f3bfa:/app$ php artisan try:save-or-fail --fail
SQLSTATE[23505]: Unique violation: 7 ERROR: duplicate key value violates unique constraint "save_or_fails_word_unique"
DETAIL: Key (word)=(demo0) already exists. (SQL: insert into "save_or_fails" ("word", "updated_at", "created_at") values (demo0, 2021-06-07 19:40:16, 2021-06-07 19:40:16) returning "id")
Saved! demo1
除非您期望您的数据库操作可能会失败并且您会从中恢复,否则使用saveOrFail().