跳到內容

資料庫:開始使用

簡介

幾乎每個現代 Web 應用程式都會與資料庫互動。Laravel 讓跨各種支援資料庫的互動變得極為簡單,使用原始 SQL、流暢的查詢產生器Eloquent ORM。目前,Laravel 為五個資料庫提供第一方支援

此外,MongoDB 通過 mongodb/laravel-mongodb 套件提供支援,該套件由 MongoDB 官方維護。查看 Laravel MongoDB 文件以獲取更多資訊。

設定

Laravel 資料庫服務的設定位於您應用程式的 config/database.php 設定檔中。在此檔案中,您可以定義所有資料庫連線,並指定預設應使用的連線。此檔案中的大多數設定選項都由應用程式環境變數的值驅動。此檔案中提供了 Laravel 大多數支援的資料庫系統的範例。

預設情況下,Laravel 的範例 環境設定 已準備好與 Laravel Sail 一起使用,Laravel Sail 是用於在您的本機電腦上開發 Laravel 應用程式的 Docker 設定。但是,您可以根據本機資料庫的需要自由修改資料庫設定。

SQLite 設定

SQLite 資料庫包含在檔案系統上的單個檔案中。您可以使用終端機中的 touch 命令建立新的 SQLite 資料庫:touch database/database.sqlite。建立資料庫後,您可以輕鬆設定環境變數以指向此資料庫,方法是將資料庫的絕對路徑放置在 DB_DATABASE 環境變數中

1DB_CONNECTION=sqlite
2DB_DATABASE=/absolute/path/to/database.sqlite

預設情況下,外鍵約束對於 SQLite 連線是啟用的。如果您想停用它們,應將 DB_FOREIGN_KEYS 環境變數設定為 false

1DB_FOREIGN_KEYS=false

如果您使用 Laravel 安裝程式 建立您的 Laravel 應用程式並選擇 SQLite 作為您的資料庫,Laravel 將自動建立 database/database.sqlite 檔案並為您執行預設的 資料庫遷移

Microsoft SQL Server 設定

要使用 Microsoft SQL Server 資料庫,您應確保已安裝 sqlsrvpdo_sqlsrv PHP 擴充功能以及它們可能需要的任何相依性,例如 Microsoft SQL ODBC 驅動程式。

使用 URL 進行設定

通常,資料庫連線是使用多個設定值(例如 hostdatabaseusernamepassword 等)設定的。每個設定值都有其對應的環境變數。這意味著在生產伺服器上設定資料庫連線資訊時,您需要管理多個環境變數。

一些託管資料庫供應商(例如 AWS 和 Heroku)提供單個資料庫「URL」,其中包含資料庫的所有連線資訊在單個字串中。資料庫 URL 範例可能如下所示

1mysql://root:[email protected]/forge?charset=UTF-8

這些 URL 通常遵循標準結構描述慣例

1driver://username:password@host:port/database?options

為了方便起見,Laravel 支援這些 URL 作為使用多個設定選項設定資料庫的替代方案。如果存在 url(或對應的 DB_URL 環境變數)設定選項,它將用於提取資料庫連線和憑證資訊。

讀取和寫入連線

有時您可能希望使用一個資料庫連線用於 SELECT 語句,而另一個用於 INSERT、UPDATE 和 DELETE 語句。Laravel 使這變得輕而易舉,無論您使用原始查詢、查詢產生器還是 Eloquent ORM,都將始終使用正確的連線。

要了解應如何設定讀取/寫入連線,讓我們看看這個範例

1'mysql' => [
2 'read' => [
3 'host' => [
4 '192.168.1.1',
5 '196.168.1.2',
6 ],
7 ],
8 'write' => [
9 'host' => [
10 '196.168.1.3',
11 ],
12 ],
13 'sticky' => true,
14 
15 'database' => env('DB_DATABASE', 'laravel'),
16 'username' => env('DB_USERNAME', 'root'),
17 'password' => env('DB_PASSWORD', ''),
18 'unix_socket' => env('DB_SOCKET', ''),
19 'charset' => env('DB_CHARSET', 'utf8mb4'),
20 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
21 'prefix' => '',
22 'prefix_indexes' => true,
23 'strict' => true,
24 'engine' => null,
25 'options' => extension_loaded('pdo_mysql') ? array_filter([
26 PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
27 ]) : [],
28],

請注意,配置陣列中已新增三個鍵:readwritestickyreadwrite 鍵具有包含單個鍵的陣列值:hostreadwrite 連線的其餘資料庫選項將從主 mysql 配置陣列合併。

只有在您希望覆蓋主 mysql 陣列中的值時,才需要在 readwrite 陣列中放置項目。因此,在本例中,192.168.1.1 將用作「讀取」連線的主機,而 192.168.1.3 將用於「寫入」連線。主 mysql 陣列中的資料庫憑證、前綴、字元集和所有其他選項將在兩個連線之間共用。當 host 設定陣列中存在多個值時,將為每個請求隨機選擇一個資料庫主機。

sticky 選項

sticky 選項是一個可選值,可用於允許立即讀取在當前請求週期中已寫入資料庫的記錄。如果啟用了 sticky 選項,並且在當前請求週期中已對資料庫執行「寫入」操作,則任何進一步的「讀取」操作都將使用「寫入」連線。這確保了在請求週期中寫入的任何資料都可以立即在同一個請求中從資料庫讀回。是否希望應用程式具有此行為由您決定。

執行 SQL 查詢

設定資料庫連線後,您可以使用 DB facade 執行查詢。DB facade 為每種類型的查詢提供方法:selectupdateinsertdeletestatement

執行 Select 查詢

要執行基本的 SELECT 查詢,您可以使用 DB facade 上的 select 方法

1<?php
2 
3namespace App\Http\Controllers;
4 
5use App\Http\Controllers\Controller;
6use Illuminate\Support\Facades\DB;
7use Illuminate\View\View;
8 
9class UserController extends Controller
10{
11 /**
12 * Show a list of all of the application's users.
13 */
14 public function index(): View
15 {
16 $users = DB::select('select * from users where active = ?', [1]);
17 
18 return view('user.index', ['users' => $users]);
19 }
20}

傳遞給 select 方法的第一個引數是 SQL 查詢,而第二個引數是需要繫結到查詢的任何參數繫結。通常,這些是 where 子句約束的值。參數繫結提供防止 SQL 注入的保護。

select 方法將始終返回結果的 array。陣列中的每個結果都將是一個 PHP stdClass 物件,表示資料庫中的一條記錄

1use Illuminate\Support\Facades\DB;
2 
3$users = DB::select('select * from users');
4 
5foreach ($users as $user) {
6 echo $user->name;
7}

選取純量值

有時,您的資料庫查詢可能會產生單個純量值。Laravel 允許您直接使用 scalar 方法檢索此值,而無需從記錄物件中檢索查詢的純量結果

1$burgers = DB::scalar(
2 "select count(case when food = 'burger' then 1 end) as burgers from menu"
3);

選取多個結果集

如果您的應用程式調用返回多個結果集的預存程序,您可以使用 selectResultSets 方法檢索預存程序返回的所有結果集

1[$options, $notifications] = DB::selectResultSets(
2 "CALL get_user_options_and_notifications(?)", $request->user()->id
3);

使用具名繫結

您可以通過使用具名繫結執行查詢,而不是使用 ? 來表示參數繫結

1$results = DB::select('select * from users where id = :id', ['id' => 1]);

執行 Insert 語句

要執行 insert 語句,您可以使用 DB facade 上的 insert 方法。與 select 類似,此方法將 SQL 查詢作為其第一個引數,繫結作為其第二個引數

1use Illuminate\Support\Facades\DB;
2 
3DB::insert('insert into users (id, name) values (?, ?)', [1, 'Marc']);

執行 Update 語句

update 方法應用於更新資料庫中的現有記錄。該方法返回語句影響的行數

1use Illuminate\Support\Facades\DB;
2 
3$affected = DB::update(
4 'update users set votes = 100 where name = ?',
5 ['Anita']
6);

執行 Delete 語句

delete 方法應用於從資料庫中刪除記錄。與 update 類似,將返回受影響的行數

1use Illuminate\Support\Facades\DB;
2 
3$deleted = DB::delete('delete from users');

執行 General 語句

某些資料庫語句不返回任何值。對於這些類型的操作,您可以使用 DB facade 上的 statement 方法

1DB::statement('drop table users');

執行 Unprepared 語句

有時您可能希望執行 SQL 語句而不繫結任何值。您可以使用 DB facade 的 unprepared 方法來完成此操作

1DB::unprepared('update users set votes = 100 where name = "Dries"');

由於 unprepared 語句不繫結參數,因此它們可能容易受到 SQL 注入的攻擊。您絕不應在 unprepared 語句中允許使用者控制的值。

隱式提交

在交易中使用 DB facade 的 statementunprepared 方法時,您必須小心避免導致 隱式提交 的語句。這些語句將導致資料庫引擎間接提交整個交易,使 Laravel 無法感知資料庫的交易級別。建立資料庫表就是這樣一個語句的範例

1DB::unprepared('create table a (col varchar(1) null)');

請參閱 MySQL 手冊,了解 觸發隱式提交的所有語句的列表

使用多個資料庫連線

如果您的應用程式在 config/database.php 設定檔中定義了多個連線,您可以通過 DB facade 提供的 connection 方法訪問每個連線。傳遞給 connection 方法的連線名稱應與 config/database.php 設定檔中列出的連線之一或使用 config helper 在運行時設定的連線之一相對應

1use Illuminate\Support\Facades\DB;
2 
3$users = DB::connection('sqlite')->select(/* ... */);

您可以使用連線實例上的 getPdo 方法訪問連線的原始底層 PDO 實例

1$pdo = DB::connection()->getPdo();

監聽查詢事件

如果您想指定一個閉包,該閉包針對應用程式執行的每個 SQL 查詢調用,您可以使用 DB facade 的 listen 方法。此方法對於記錄查詢或除錯很有用。您可以在 服務提供者boot 方法中註冊您的查詢監聽器閉包

1<?php
2 
3namespace App\Providers;
4 
5use Illuminate\Database\Events\QueryExecuted;
6use Illuminate\Support\Facades\DB;
7use Illuminate\Support\ServiceProvider;
8 
9class AppServiceProvider extends ServiceProvider
10{
11 /**
12 * Register any application services.
13 */
14 public function register(): void
15 {
16 // ...
17 }
18 
19 /**
20 * Bootstrap any application services.
21 */
22 public function boot(): void
23 {
24 DB::listen(function (QueryExecuted $query) {
25 // $query->sql;
26 // $query->bindings;
27 // $query->time;
28 // $query->toRawSql();
29 });
30 }
31}

監控累積查詢時間

現代 Web 應用程式的常見效能瓶頸是它們花費在查詢資料庫上的時間。值得慶幸的是,當 Laravel 在單個請求期間花費太多時間查詢資料庫時,它可以調用您選擇的閉包或回調。要開始使用,請向 whenQueryingForLongerThan 方法提供查詢時間閾值(以毫秒為單位)和閉包。您可以在 服務提供者boot 方法中調用此方法

1<?php
2 
3namespace App\Providers;
4 
5use Illuminate\Database\Connection;
6use Illuminate\Support\Facades\DB;
7use Illuminate\Support\ServiceProvider;
8use Illuminate\Database\Events\QueryExecuted;
9 
10class AppServiceProvider extends ServiceProvider
11{
12 /**
13 * Register any application services.
14 */
15 public function register(): void
16 {
17 // ...
18 }
19 
20 /**
21 * Bootstrap any application services.
22 */
23 public function boot(): void
24 {
25 DB::whenQueryingForLongerThan(500, function (Connection $connection, QueryExecuted $event) {
26 // Notify development team...
27 });
28 }
29}

資料庫交易

您可以使用 DB facade 提供的 transaction 方法在資料庫交易中運行一組操作。如果在交易閉包中拋出異常,則交易將自動回滾,並且異常將重新拋出。如果閉包成功執行,則交易將自動提交。使用 transaction 方法時,您無需擔心手動回滾或提交

1use Illuminate\Support\Facades\DB;
2 
3DB::transaction(function () {
4 DB::update('update users set votes = 1');
5 
6 DB::delete('delete from posts');
7});

處理死鎖

transaction 方法接受一個可選的第二個引數,該引數定義在發生死鎖時應重試交易的次數。一旦這些嘗試用盡,將拋出異常

1use Illuminate\Support\Facades\DB;
2 
3DB::transaction(function () {
4 DB::update('update users set votes = 1');
5 
6 DB::delete('delete from posts');
7}, 5);

手動使用交易

如果您想手動開始交易並完全控制回滾和提交,您可以使用 DB facade 提供的 beginTransaction 方法

1use Illuminate\Support\Facades\DB;
2 
3DB::beginTransaction();

您可以通過 rollBack 方法回滾交易

1DB::rollBack();

最後,您可以通過 commit 方法提交交易

1DB::commit();

DB facade 的交易方法控制 查詢產生器Eloquent ORM 的交易。

連線到資料庫 CLI

如果您想連線到資料庫的 CLI,您可以使用 db Artisan 命令

1php artisan db

如果需要,您可以指定資料庫連線名稱以連線到非預設連線的資料庫連線

1php artisan db mysql

檢查您的資料庫

使用 db:showdb:table Artisan 命令,您可以深入了解您的資料庫及其關聯的表。要查看資料庫的概述,包括其大小、類型、開啟連線數以及表摘要,您可以使用 db:show 命令

1php artisan db:show

您可以通過 --database 選項將資料庫連線名稱提供給命令,從而指定應檢查哪個資料庫連線

1php artisan db:show --database=pgsql

如果您希望在命令的輸出中包含表行數和資料庫視圖詳細資訊,您可以分別提供 --counts--views 選項。在大型資料庫上,檢索行數和視圖詳細資訊可能會很慢

1php artisan db:show --counts --views

此外,您可以使用以下 Schema 方法來檢查您的資料庫

1use Illuminate\Support\Facades\Schema;
2 
3$tables = Schema::getTables();
4$views = Schema::getViews();
5$columns = Schema::getColumns('users');
6$indexes = Schema::getIndexes('users');
7$foreignKeys = Schema::getForeignKeys('users');

如果您想檢查非應用程式預設連線的資料庫連線,您可以使用 connection 方法

1$columns = Schema::connection('sqlite')->getColumns('users');

表概述

如果您想獲取資料庫中單個表的概述,您可以執行 db:table Artisan 命令。此命令提供資料庫表的一般概述,包括其列、類型、屬性、鍵和索引

1php artisan db:table users

監控您的資料庫

使用 db:monitor Artisan 命令,您可以指示 Laravel 在資料庫管理的開啟連線數超過指定數量時分派 Illuminate\Database\Events\DatabaseBusy 事件。

要開始使用,您應排程 db:monitor 命令 每分鐘運行一次。該命令接受您希望監控的資料庫連線設定的名稱,以及在分派事件之前應容忍的最大開啟連線數

1php artisan db:monitor --databases=mysql,pgsql --max=100

僅排程此命令不足以觸發通知,提醒您開啟連線數。當命令遇到開啟連線計數超過閾值的資料庫時,將分派 DatabaseBusy 事件。您應在應用程式的 AppServiceProvider 中監聽此事件,以便向您或您的開發團隊發送通知

1use App\Notifications\DatabaseApproachingMaxConnections;
2use Illuminate\Database\Events\DatabaseBusy;
3use Illuminate\Support\Facades\Event;
4use Illuminate\Support\Facades\Notification;
5 
6/**
7 * Bootstrap any application services.
8 */
9public function boot(): void
10{
11 Event::listen(function (DatabaseBusy $event) {
12 Notification::route('mail', '[email protected]')
13 ->notify(new DatabaseApproachingMaxConnections(
14 $event->connectionName,
15 $event->connections
16 ));
17 });
18}