はじめに
ほとんどすべての現代のウェブアプリケーションはデータベースと対話します。Laravelは、生のSQL、流暢なクエリビルダー、およびEloquent ORMを使用して、さまざまなサポートされているデータベースとの対話を非常に簡単にします。現在、Laravelは5つのデータベースに対してファーストパーティのサポートを提供しています:
- MariaDB 10.3+ (バージョンポリシー)
- MySQL 5.7+ (バージョンポリシー)
- PostgreSQL 10.0+ (バージョンポリシー)
- SQLite 3.26.0+
SQL Server 2017+ (バージョンポリシー)
設定
Laravelのデータベースサービスの設定は、アプリケーションのconfig/database.php
設定ファイルにあります。このファイルでは、すべてのデータベース接続を定義し、どの接続をデフォルトとして使用するかを指定できます。このファイル内のほとんどの設定オプションは、アプリケーションの環境変数の値によって駆動されます。Laravelがサポートするほとんどのデータベースシステムの例がこのファイルに提供されています。
デフォルトでは、Laravelのサンプル環境設定は、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
Laravelインストーラーを使用してLaravelアプリケーションを作成し、SQLiteをデータベースとして選択すると、Laravelは自動的にdatabase/database.sqlite
ファイルを作成し、デフォルトのデータベースマイグレーションを実行します。
Microsoft SQL Serverの設定
Microsoft SQL Serverデータベースを使用するには、sqlsrv
およびpdo_sqlsrv
PHP拡張がインストールされていることを確認し、Microsoft SQL ODBCドライバなどの依存関係も必要です。
URLを使用した設定
通常、データベース接続はhost
、database
、username
、password
などの複数の設定値を使用して構成されます。これらの設定値にはそれぞれ対応する環境変数があります。これは、プロダクションサーバーでデータベース接続情報を構成する際に、いくつかの環境変数を管理する必要があることを意味します。
AWSやHerokuなどの一部の管理されたデータベースプロバイダーは、データベースの接続情報を単一の文字列で含む単一のデータベース「URL」を提供します。データベースURLの例は次のようになります:
mysql://root:/forge?charset=UTF-8
これらのURLは通常、標準のスキーマ規約に従います:
driver://username:password@host:port/database?options
便利なことに、LaravelはこれらのURLを複数の設定オプションでデータベースを構成する代替手段としてサポートしています。url
(または対応するDB_URL
環境変数)設定オプションが存在する場合、それを使用してデータベース接続と資格情報情報を抽出します。
読み取りおよび書き込み接続
時には、SELECT文に1つのデータベース接続を使用し、INSERT、UPDATE、およびDELETE文に別の接続を使用したい場合があります。Laravelはこれを簡単にし、rawクエリ、クエリビルダー、または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'),
]) : [],
],
設定配列に3つのキーが追加されています:read
、write
、およびsticky
。read
およびwrite
キーには、単一のキーを含む配列値があります:host
。read
およびwrite
接続の残りのデータベースオプションは、メインのmysql
設定配列からマージされます。
メインのmysql
配列からの値を上書きしたい場合は、read
およびwrite
配列にアイテムを配置する必要があります。この場合、192.168.1.1
は「読み取り」接続のホストとして使用され、192.168.1.3
は「書き込み」接続のホストとして使用されます。データベースの資格情報、プレフィックス、文字セット、およびメインのmysql
配列内のすべての他のオプションは、両方の接続で共有されます。host
設定配列に複数の値が存在する場合、各リクエストに対してランダムにデータベースホストが選択されます。
スティッキーオプション
<a name="running-queries"></a>
## SQLクエリの実行
データベース接続を構成したら、`````DB`````ファサードを使用してクエリを実行できます。`````DB`````ファサードは、各タイプのクエリに対するメソッドを提供します:`````select`````、`````update`````、`````insert`````、`````delete`````、および`````statement`````。
<a name="running-a-select-query"></a>
#### SELECTクエリの実行
基本的なSELECTクエリを実行するには、`````select`````メソッドを`````DB`````ファサードで使用できます:
``````php
<?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`````メソッドは常に`````array`````の結果を返します。配列内の各結果は、データベースのレコードを表すPHP `````stdClass`````オブジェクトになります:
``````php
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
);
名前付きバインディングの使用
``````php
$results = DB::select('select * from users where id = :id', ['id' => 1]);
`
INSERT文の実行
``````php
use Illuminate\Support\Facades\DB;
DB::insert('insert into users (id, name) values (?, ?)', [1, 'Marc']);
`
UPDATE文の実行
``````php
use Illuminate\Support\Facades\DB;
$affected = DB::update(
'update users set votes = 100 where name = ?',
['Anita']
);
`
DELETE文の実行
``````php
use Illuminate\Support\Facades\DB;
$deleted = DB::delete('delete from users');
`
一般的な文の実行
一部のデータベース文は値を返しません。これらのタイプの操作には、statement
メソッドをDB
ファサードで使用できます:
DB::statement('drop table users');
未準備文の実行
時には、値をバインドせずにSQL文を実行したい場合があります。これを達成するために、DB
ファサードのunprepared
メソッドを使用できます:
DB::unprepared('update users set votes = 100 where name = "Dries"');
未準備文はパラメータをバインドしないため、SQLインジェクションに対して脆弱である可能性があります。未準備文内にユーザー制御の値を許可してはいけません。
暗黙のコミット
``````php
DB::unprepared('create table a (col varchar(1) null)');
`
暗黙のコミットを引き起こすすべての文のリストについては、MySQLマニュアルを参照してください[https://dev.mysql.com/doc/refman/8.0/en/implicit-commit.html]。
複数のデータベース接続の使用
アプリケーションがconfig/database.php
設定ファイルに複数の接続を定義している場合、DB
ファサードによって提供されるconnection
メソッドを介して各接続にアクセスできます。connection
メソッドに渡される接続名は、config/database.php
設定ファイルにリストされている接続の1つに対応する必要があります。または、config
ヘルパーを使用してランタイムで構成されます:
use Illuminate\Support\Facades\DB;
$users = DB::connection('sqlite')->select(/* ... */);
接続インスタンスのgetPdo
メソッドを使用して、接続の生の基盤となるPDOインスタンスにアクセスできます:
$pdo = DB::connection()->getPdo();
クエリエベントのリスニング
アプリケーションによって実行される各SQLクエリに対して呼び出されるクロージャを指定したい場合は、DB
ファサードの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...
});
}
}
データベーストランザクション
``````php
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
DB::update('update users set votes = 1');
DB::delete('delete from posts');
});
`
デッドロックの処理
``````php
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
DB::update('update users set votes = 1');
DB::delete('delete from posts');
}, 5);
`
トランザクションの手動使用
トランザクションを手動で開始し、ロールバックとコミットを完全に制御したい場合は、beginTransaction
メソッドをDB
ファサードで使用できます:
use Illuminate\Support\Facades\DB;
DB::beginTransaction();
トランザクションをrollBack
メソッドでロールバックできます:
DB::rollBack();
最後に、commit
メソッドでトランザクションをコミットできます:
DB::commit();
DB
ファサードのトランザクションメソッドは、クエリビルダーとEloquent ORMの両方のトランザクションを制御します。
データベースCLIへの接続
データベースのCLIに接続したい場合は、db
Artisanコマンドを使用できます:
php artisan db
必要に応じて、デフォルト接続ではないデータベース接続に接続するためにデータベース接続名を指定できます:
php artisan db mysql
データベースの検査
db:show
およびdb: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', '')
->notify(new DatabaseApproachingMaxConnections(
$event->connectionName,
$event->connections
));
});
}