欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

在Laravel中如何使用數(shù)據(jù)庫事務(wù)

小編給大家分享一下在Laravel中如何使用數(shù)據(jù)庫事務(wù),希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

創(chuàng)新互聯(lián)主要從事網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)丹陽,十年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18980820575

什么是數(shù)據(jù)庫事務(wù)?

在我們開始研究 Laravel 的數(shù)據(jù)庫事務(wù)之前,讓我們先看看它們是什么以及它們?nèi)绾斡幸妗?/p>

對(duì)于什么是數(shù)據(jù)庫事務(wù),有許多聽起來復(fù)雜的技術(shù)解釋。但是,對(duì)于大多數(shù) web 開發(fā)人員來說,我們只需要知道事務(wù)是完成數(shù)據(jù)庫中整個(gè)工作單元的方式。

為了理解這實(shí)際上意味著什么,讓我們來看一個(gè)基本的例子,它將給出一點(diǎn)上下文。

假設(shè)我們有一個(gè)允許用戶注冊(cè)的應(yīng)用程序。每當(dāng)用戶注冊(cè)時(shí),我們都希望為他們創(chuàng)建一個(gè)新帳戶,然后為他們分配一個(gè)默認(rèn)角色“ general”。

我們的代碼可能是這樣的:

$user = User::create([
    'email' => $request->email,
]);

$user->roles()->attach(Role::where('name', 'general')->first());

乍一看,這段代碼似乎完全沒問題。但是,當(dāng)我們仔細(xì)觀察的時(shí)候,我們可以發(fā)現(xiàn)實(shí)際上有一些事情可能會(huì)出錯(cuò)。我們可以創(chuàng)建用戶,但是不能為他們分配角色。這可能是由許多不同的原因造成的,比如分配角色的代碼中的錯(cuò)誤,或者甚至是阻止我們到達(dá)數(shù)據(jù)庫的硬件問題。

由于這種情況的發(fā)生,這將意味著系統(tǒng)中將有一個(gè)沒有角色的用戶。正如您可以想象的那樣,這可能會(huì)在您的應(yīng)用程序中的其他地方引起異常和 bug,因?yàn)槟偸羌僭O(shè)用戶有一個(gè)角色(這是正確的)。

因此,為了解決這個(gè)問題,我們可以使用數(shù)據(jù)庫事務(wù)。通過使用事務(wù),它可以確保在執(zhí)行代碼時(shí),如果出現(xiàn)任何錯(cuò)誤,事務(wù)內(nèi)部對(duì)數(shù)據(jù)庫的任何更改都將回滾。例如,如果用戶被插入到數(shù)據(jù)庫中,但是由于任何原因分配角色的查詢失敗,那么事務(wù)將被回滾,用戶行將被刪除。通過這樣做,它意味著我們不能創(chuàng)建沒有分配角色的用戶。

換句話說,它“要么全有,要么全沒有”。

在 Laravel 中使用數(shù)據(jù)庫事務(wù)

現(xiàn)在我們對(duì)事務(wù)是什么以及它們實(shí)現(xiàn)了什么有了一個(gè)簡單的概念,讓我們來看看如何在 Laravel 中使用它們。

在 Laravel 中,由于我們可以在 DB 門面上訪問 transaction() 方法,因此開始使用事務(wù)實(shí)際上是很容易的事。繼續(xù)使用之前的示例代碼,讓我們看看在創(chuàng)建用戶并為其分配角色時(shí)如何使用事務(wù)。

use Illuminate\Support\Facades\DB;

DB::transaction(function () use ($user, $request): void {
    $user = User::create([
        'email' => $request->email,
    ]);

    $user->roles()->attach(Role::where('name', 'general')->first());
});

現(xiàn)在我們的代碼被包裹在一個(gè)數(shù)據(jù)庫事務(wù)中,如果在其中的任意一點(diǎn)拋出異常,對(duì)數(shù)據(jù)庫的任何更改都將返回到事務(wù)開始之前的狀態(tài)。

在 Laravel 中手動(dòng)使用數(shù)據(jù)庫事務(wù)

有時(shí),您可能希望對(duì)事務(wù)進(jìn)行更精細(xì)的控制。例如,假設(shè)您正在與第三方服務(wù)集成,比如 Mailchinp 或 Xero。我們會(huì)說,每當(dāng)您創(chuàng)建一個(gè)新用戶時(shí),您還需要向他們的 API 發(fā)出 HTTP 請(qǐng)求,以將他們也創(chuàng)建為該系統(tǒng)中的用戶。

我們可能想要更新我們的代碼,以便如果我們無法在我們自己的系統(tǒng) 在第三方系統(tǒng)中創(chuàng)建用戶,則兩個(gè)系統(tǒng)都不創(chuàng)建用戶。 如果您正在與第三方系統(tǒng)交互,那么您可能有一個(gè)可用于發(fā)出請(qǐng)求的類。 或者,可能有一個(gè)您可以使用的包。 有時(shí),當(dāng)某些請(qǐng)求無法完成時(shí),發(fā)出請(qǐng)求的類可能會(huì)拋出異常。 然而,其中一些類可能會(huì)消除錯(cuò)誤,而只是從您調(diào)用的方法中返回 false,并將錯(cuò)誤放置在類的字段中。

因此,我們假設(shè)我們有以下調(diào)用 API 的基本示例類:

class ThirdPartyService
{
    private $errors;

    public function createUser($userData)
    {
        $request = $this->makeRequest($userData);

        if ($request->successful()) {
            return $request->body();
        }

        $errors = $request->errors();

        return false;
    }

    public function getErrors()
    {
        return $this->errors;
    }
}

當(dāng)然,上面的請(qǐng)求類代碼是不完整的,我下面的代碼示例也不是很清楚,但它應(yīng)該能讓您大致了解我要表達(dá)的觀點(diǎn)。所以讓我們使用這個(gè)請(qǐng)求類并將其添加到我們之前的代碼示例中:

use Illuminate\Support\Facades\DB;
use App\Services\ThirdPartyService;

DB::beginTransaction();

$thirdPartyService = new ThirdPartyService();

$userData = [
    'email' => $request->email,
];

$user = User::create($userData);

$user->roles()->attach(Role::where('name', 'general')->first());

if ($thirdPartyService->createUser($userData)) {
    DB::commit();

    return;
}

DB::rollBack();

report($thirdPartyService->getErrors());

查看上面的代碼,我們可以看到我們啟動(dòng)了一個(gè)事務(wù),創(chuàng)建了用戶并為他們分配了一個(gè)角色,然后我們調(diào)用了第三方服務(wù)。如果在外部服務(wù)中成功創(chuàng)建了用戶,知道所有內(nèi)容都已正確創(chuàng)建,我們就可以安全地提交數(shù)據(jù)庫更改。但是,如果沒有在外部服務(wù)中創(chuàng)建用戶,則回滾數(shù)據(jù)庫中的更改(刪除用戶及其角色分配),然后報(bào)告錯(cuò)誤。

與第三方服務(wù)交互的技巧

作為一個(gè)額外的技巧,我通常建議將任何影響第三方系統(tǒng)、文件存儲(chǔ)或緩存的代碼放在數(shù)據(jù)庫調(diào)用之后

為了更深入地理解這一點(diǎn),讓我們以上面的代碼示例為例。請(qǐng)注意,在向第三方服務(wù)發(fā)出請(qǐng)求之前,我們是如何首先對(duì)數(shù)據(jù)庫進(jìn)行所有更改的。這意味著,如果從第三方請(qǐng)求返回任何錯(cuò)誤,將回滾我們自己數(shù)據(jù)庫中的用戶和角色分配。

然而, 如果我們反過來做,我們?cè)谛薷臄?shù)據(jù)庫之前發(fā)出請(qǐng)求,那就不是這種情況了。出于任何原因,如果我們?cè)跀?shù)據(jù)庫中創(chuàng)建用戶時(shí)發(fā)生任何錯(cuò)誤,我們會(huì)在第三方系統(tǒng)中創(chuàng)建一個(gè)新用戶,但是在我們系統(tǒng)中卻沒有創(chuàng)建。如你所想, 這可能會(huì)導(dǎo)致更多問題。通過編寫一個(gè)清理方法將用戶從第三方系統(tǒng)中刪除,可以降低這個(gè)問題的嚴(yán)重性。 但是,正如您可以想象的那樣, 這可能會(huì)導(dǎo)致更多的問題,并導(dǎo)致編寫、維護(hù)和測(cè)試更多的代碼。

所以,我總是建議把數(shù)據(jù)庫調(diào)用放在API調(diào)用之前。但并不總是這樣,有時(shí)可能需要將第三方請(qǐng)求返回的值保存到數(shù)據(jù)庫中。如果是這種情況,就需要API調(diào)用放到數(shù)據(jù)庫調(diào)用之前了,只要您確保有一些代碼可以處理任何失敗,這是完全可以的。

使用自動(dòng)或手動(dòng)事務(wù)

同樣值得注意的是,因?yàn)槲覀冏畛醯氖纠褂?code>DB:transaction()方法,在拋出異常時(shí)回滾事務(wù),所以我們也可以使用這種方法向我們的第三方服務(wù)發(fā)出請(qǐng)求。相反,我們可以這樣更新類:

use Illuminate\Support\Facades\DB;
use App\Services\ThirdPartyService;

DB::transaction(function () use ($user, $request): void {
    $user = User::create([
        'email' => $request->email,
    ]);

    $user->roles()->attach(Role::where('name', 'general')->first());

    if (! $thirdPartyService->createUser($userData)) {
        throw new \Exception('User could not be created');
    }
});

這絕對(duì)是一個(gè)可行的解決方案,并將按照預(yù)期成功回滾事務(wù)。事實(shí)上,就我個(gè)人的偏好而言,我實(shí)際上更喜歡這種方式,而不是手動(dòng)使用事務(wù)。我認(rèn)為它看起來更容易閱讀和理解。

然而,與手動(dòng)提交或回滾事務(wù)時(shí)使用 'if' 語句相比,異常處理在時(shí)間和性能方面可能會(huì)比較昂貴。

因此,舉個(gè)例子,如果這段代碼用于導(dǎo)入包含10,000個(gè)用戶數(shù)據(jù)的 CSV 文件,您可能會(huì)發(fā)現(xiàn)拋出異常會(huì)大大減慢導(dǎo)入速度。

但是,如果它只是在一個(gè)用戶可以注冊(cè)的簡單web請(qǐng)求中使用,那么拋出異常可能沒有問題。當(dāng)然,這取決于應(yīng)用程序的大小,性能是關(guān)鍵因素;所以你需要根據(jù)具體情況來決定。

在數(shù)據(jù)庫事務(wù)中調(diào)度隊(duì)列

每當(dāng)您在事務(wù)中處理隊(duì)列時(shí),您都需要注意一個(gè)“陷阱”。

為了提供一些上下文,讓我們繼續(xù)使用之前的代碼示例。我們可以想象,在我們創(chuàng)建了我們的用戶之后,我們想要運(yùn)行一個(gè)任務(wù)來提醒管理員通知他們新注冊(cè)并向新用戶發(fā)送歡迎電子郵件。我們將通過分派一個(gè)名為 AlertNewUser 的隊(duì)列任務(wù)來做到這一點(diǎn),如下所示:

use Illuminate\Support\Facades\DB;
use App\Jobs\AlertNewUser;
use App\Services\ThirdPartyService;

DB::transaction(function () use ($user, $request): void {
    $user = User::create([
        'email' => $request->email,
    ]);

    $user->roles()->attach(Role::where('name', 'general')->first());

    AlertNewUser::dispatch($user);
});

當(dāng)您開始一個(gè)事務(wù)并對(duì)其中的任何數(shù)據(jù)進(jìn)行更改時(shí),這些更改僅對(duì)正在運(yùn)行事務(wù)的請(qǐng)求/進(jìn)程可用。對(duì)于任何其他訪問您更改的數(shù)據(jù)的請(qǐng)求或進(jìn)程,必須先提交事務(wù)。因此,這意味著如果我們從事務(wù)內(nèi)部分派任何排隊(duì)的隊(duì)列、事件監(jiān)聽器、郵件,通知或廣播事件。由于競(jìng)爭條件,我們的數(shù)據(jù)更改可能在事務(wù)內(nèi)部不可用。

如果隊(duì)列在事務(wù)提交之前開始處理排隊(duì)的代碼,就會(huì)發(fā)生這種情況。因此,這可能導(dǎo)致您的排隊(duì)代碼可能試圖訪問不存在的數(shù)據(jù),并可能導(dǎo)致錯(cuò)誤。在我們的例子中,如果在事務(wù)提交之前運(yùn)行隊(duì)列AlertNewUser作業(yè),那么我們的作業(yè)將嘗試訪問一個(gè)尚未實(shí)際存儲(chǔ)在數(shù)據(jù)庫中的用戶。如您所料,這將導(dǎo)致作業(yè)失敗。

為了防止這種競(jìng)爭條件的發(fā)生,我們可以對(duì)我們的代碼和/或我們的配置進(jìn)行一些更改,以確保僅在事務(wù)成功提交后才調(diào)度隊(duì)列。

我們可以更新 config/queue.php 并添加 after commit 字段。讓我們想象一下,我們正在使用 redis 隊(duì)列驅(qū)動(dòng)程序,所以我們可以這樣更新配置:

<?php

return [

    // ...

    'connections' => [

        // ...

        'redis' => [
            'driver' => 'redis',
            // ...
            'after_commit' => true,
        ],

        // ...

    ],

    // ...
];

通過進(jìn)行此更改,如果我們嘗試在事務(wù)內(nèi)調(diào)度隊(duì)列,則隊(duì)列將在實(shí)際調(diào)度隊(duì)列之前等待事務(wù)提交。 方便的是,如果事務(wù)回滾,它也會(huì)阻止隊(duì)列被調(diào)度。

然而,可能有一個(gè)原因,您不希望在配置中全局設(shè)置此選項(xiàng)。 如果是這種情況,Laravel 仍然提供了一些很好的助手方法,我們可以根據(jù)具體情況使用它們。
如果我們想更新事務(wù)中的代碼,只在任務(wù)提交后才分派任務(wù),可以使用afterCommit()方法,如下所示:

use Illuminate\Support\Facades\DB;
use App\Jobs\AlertNewUser;
use App\Services\ThirdPartyService;

DB::transaction(function () use ($user, $request): void {
    $user = User::create([
        'email' => $request->email,
    ]);

    $user->roles()->attach(Role::where('name', 'general')->first());

    AlertNewUser::dispatch($user)->afterCommit();
});

Laravel 還提供了另一個(gè)我們可以使用的方便的beforeCommit()方法。 如果我們?cè)陉?duì)列配置中設(shè)置了全局after_commit => true,但不關(guān)心等待事務(wù)被提交,就可以使用這個(gè)。 要做到這一點(diǎn),我們可以簡單地像這樣更新我們的代碼:

use Illuminate\Support\Facades\DB;
use App\Jobs\AlertNewUser;
use App\Services\ThirdPartyService;

DB::transaction(function () use ($user, $request): void {
    $user = User::create([
        'email' => $request->email,
    ]);

    $user->roles()->attach(Role::where('name', 'general')->first());

    AlertNewUser::dispatch($user)->beforeCommit();
});

看完了這篇文章,相信你對(duì)“在Laravel中如何使用數(shù)據(jù)庫事務(wù)”有了一定的了解,如果想了解更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!

分享文章:在Laravel中如何使用數(shù)據(jù)庫事務(wù)
分享鏈接:http://chinadenli.net/article10/jgpcgo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作微信公眾號(hào)服務(wù)器托管全網(wǎng)營銷推廣企業(yè)建站品牌網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

營銷型網(wǎng)站建設(shè)