跳至內容

資料庫:開始使用

簡介

幾乎每個現代網路應用程式都會與資料庫互動。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 環境變數中來指向此資料庫

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

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

DB_FOREIGN_KEYS=false
lightbulb

如果您使用 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 的範例可能如下所示

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

這些 URL 通常遵循標準架構慣例

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

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

讀取和寫入連線

有時您可能希望使用一個資料庫連線來執行 SELECT 陳述式,而另一個連線則用於 INSERT、UPDATE 和 DELETE 陳述式。Laravel 使這一切變得輕而易舉,無論您使用的是原始查詢、查詢建構器還是 Eloquent ORM,都會始終使用正確的連線。

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

'mysql' => [
'read' => [
'host' => [
'192.168.1.1',
'196.168.1.2',
],
],
'write' => [
'host' => [
'196.168.1.3',
],
],
'sticky' => true,
 
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],

請注意,已將三個鍵新增至設定陣列:readwritestickyreadwrite 鍵具有包含單一鍵 host 的陣列值。readwrite 連線的其餘資料庫選項將從主要的 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 方法

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
 
class UserController extends Controller
{
/**
* Show a list of all of the application's users.
*/
public function index(): View
{
$users = DB::select('select * from users where active = ?', [1]);
 
return view('user.index', ['users' => $users]);
}
}

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

select 方法將永遠回傳一個結果的 array。陣列中的每個結果都會是一個 PHP stdClass 物件,代表資料庫中的一筆記錄。

use Illuminate\Support\Facades\DB;
 
$users = DB::select('select * from users');
 
foreach ($users as $user) {
echo $user->name;
}

選取純量值

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

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

選取多個結果集

如果您的應用程式呼叫會回傳多個結果集的預存程序,您可以使用 selectResultSets 方法來擷取預存程序回傳的所有結果集。

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

使用具名繫結

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

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

執行插入語句

若要執行 insert 語句,您可以使用 DB facade 的 insert 方法。如同 select,此方法的第一個參數接受 SQL 查詢,第二個參數接受繫結。

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

執行更新語句

應該使用 update 方法來更新資料庫中的現有記錄。該方法會回傳受該語句影響的列數。

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

執行刪除語句

應該使用 delete 方法從資料庫中刪除記錄。如同 update,該方法會回傳受影響的列數。

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

執行一般語句

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

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

執行未準備的語句

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

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

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

隱式提交

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

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

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

使用多個資料庫連線

如果您的應用程式在 config/database.php 設定檔中定義了多個連線,您可以使用 DB facade 提供的 connection 方法來存取每個連線。傳遞給 connection 方法的連線名稱應對應到您 config/database.php 設定檔中列出的其中一個連線,或是使用 config 輔助函式在執行階段設定的連線。

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

您可以使用連線實例上的 getPdo 方法來存取連線的原始、底層 PDO 實例。

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

監聽查詢事件

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

<?php
 
namespace App\Providers;
 
use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;
 
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// ...
}
 
/**
* Bootstrap any application services.
*/
public function boot(): void
{
DB::listen(function (QueryExecuted $query) {
// $query->sql;
// $query->bindings;
// $query->time;
// $query->toRawSql();
});
}
}

監控累計查詢時間

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

<?php
 
namespace App\Providers;
 
use Illuminate\Database\Connection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Events\QueryExecuted;
 
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// ...
}
 
/**
* Bootstrap any application services.
*/
public function boot(): void
{
DB::whenQueryingForLongerThan(500, function (Connection $connection, QueryExecuted $event) {
// Notify development team...
});
}
}

資料庫事務

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

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

處理死鎖

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

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

手動使用交易

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

use Illuminate\Support\Facades\DB;
 
DB::beginTransaction();

您可以透過 rollBack 方法回滾交易。

DB::rollBack();

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

DB::commit();
lightbulb

DB facade 的交易方法控制查詢建立器Eloquent ORM 的交易。

連線到資料庫 CLI

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

php artisan db

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

php artisan db mysql

檢查您的資料庫

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

php artisan db:show

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

php artisan db:show --database=pgsql

如果您想在指令的輸出中包含表格列數和資料庫視圖詳細資訊,您可以分別提供 --counts--views 選項。在大型資料庫上,擷取列數和視圖詳細資訊可能會很慢。

php artisan db:show --counts --views

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

use Illuminate\Support\Facades\Schema;
 
$tables = Schema::getTables();
$views = Schema::getViews();
$columns = Schema::getColumns('users');
$indexes = Schema::getIndexes('users');
$foreignKeys = Schema::getForeignKeys('users');

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

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

表格概觀

如果您想要取得資料庫中個別表格的概觀,您可以執行 db:table Artisan 指令。此指令提供資料庫表格的一般概觀,包括其欄位、類型、屬性、索引鍵和索引。

php artisan db:table users

監控您的資料庫

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

若要開始使用,您應該排程 db:monitor 指令每分鐘執行一次。此指令接受您要監控的資料庫連線設定名稱,以及在發送事件之前應容許的最大開啟連線數。

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

單獨排程此指令不足以觸發警示您開啟連線數量的通知。當指令遇到開啟連線數超過您閾值的資料庫時,將會發送 DatabaseBusy 事件。您應該在應用程式的 AppServiceProvider 中監聽此事件,以便向您或您的開發團隊發送通知。

use App\Notifications\DatabaseApproachingMaxConnections;
use Illuminate\Database\Events\DatabaseBusy;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Notification;
 
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Event::listen(function (DatabaseBusy $event) {
Notification::route('mail', '[email protected]')
->notify(new DatabaseApproachingMaxConnections(
$event->connectionName,
$event->connections
));
});
}