データベース:入門
はじめに
ほとんどの現代的なウェブアプリケーションはデータベースとやり取りします。Laravelでは、生のSQL、流暢なクエリビルダー、およびEloquent ORM を使用して、さまざまなサポートされているデータベースとのデータベースのやり取りを非常に簡単に行えます。現在、Laravelは5つのデータベースを第一級でサポートしています。
さらに、MongoDBは、MongoDBによって公式に保守されているmongodb/laravel-mongodb
パッケージを介してサポートされています。Laravel MongoDB のドキュメントで詳細を確認してください。
設定
Laravelのデータベースサービスの設定は、アプリケーションのconfig/database.php
設定ファイルにあります。このファイルでは、すべてのデータベース接続を定義し、デフォルトで使用される接続を指定できます。このファイル内の設定オプションの大部分は、アプリケーションの環境変数の値によって決まります。Laravelがサポートするほとんどのデータベースシステムの例がこのファイルに記載されています。
デフォルトでは、Laravelのサンプル環境設定は、ローカルマシンでLaravelアプリケーションを開発するためのDocker設定であるLaravel Sail で使用できます。ただし、必要に応じてローカルデータベースのデータベース設定を変更できます。
SQLite設定
SQLiteデータベースは、ファイルシステム上の単一ファイルに格納されます。ターミナルでtouch
コマンドを使用して、新しいSQLiteデータベースを作成できます:touch database/database.sqlite
。データベースの作成後、DB_DATABASE
環境変数にデータベースの絶対パスを配置することで、環境変数をこのデータベースを指すように簡単に設定できます。
DB_CONNECTION=sqliteDB_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:[email protected]/forge?charset=UTF-8
これらのURLは通常、標準のスキーマ規約に従います。
driver://username:password@host:port/database?options
便宜上、LaravelはこれらのURLを、複数の設定オプションを使用してデータベースを設定する代わりにサポートしています。url
(または対応するDB_URL
環境変数)設定オプションが存在する場合は、データベース接続と資格情報の抽出に使用されます。
読み取りと書き込み接続
SELECT文には1つのデータベース接続を使用し、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'), ]) : [],],
設定配列に3つのキーが追加されています:read
、write
、sticky
。read
とwrite
キーには、単一のキーを含む配列値があります:host
。read
とwrite
接続のその他のデータベースオプションは、メインのmysql
設定配列からマージされます。
メインのmysql
配列の値を上書きしたい場合にのみ、read
とwrite
配列に項目を配置する必要があります。したがって、この場合、「読み取り」接続のホストとして192.168.1.1
が使用され、「書き込み」接続には192.168.1.3
が使用されます。データベースの資格情報、プレフィックス、文字セット、メインのmysql
配列のその他のすべてのオプションは、両方の接続で共有されます。host
設定配列に複数の値が存在する場合、各リクエストに対してデータベースホストがランダムに選択されます。
sticky
オプション
sticky
オプションは、現在のリクエストサイクル中にデータベースに書き込まれたレコードをすぐに読み取ることを可能にする、オプションの値です。sticky
オプションが有効になっていて、現在のリクエストサイクル中にデータベースに対して「書き込み」操作が行われた場合、それ以降の「読み取り」操作では「書き込み」接続が使用されます。これにより、リクエストサイクル中に書き込まれたデータは、同じリクエスト中にデータベースからすぐに読み取ることができます。これがアプリケーションで必要な動作かどうかは、ユーザー自身が決める必要があります。
SQLクエリの実行
データベース接続を設定したら、DB
ファサードを使用してクエリを実行できます。DB
ファサードは、各タイプのクエリ(select
、update
、insert
、delete
、statement
)のメソッドを提供します。
SELECTクエリの実行
基本的なSELECTクエリを実行するには、DB
ファサードで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クエリで、2番目の引数はクエリにバインドする必要があるパラメーターバインディングです。通常、これらは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文の実行
insert
文を実行するには、DB
ファサードのinsert
メソッドを使用できます。select
と同様に、このメソッドはSQLクエリを最初の引数として、バインディングを2番目の引数として受け付けます。
use Illuminate\Support\Facades\DB; DB::insert('insert into users (id, name) values (?, ?)', [1, 'Marc']);
UPDATE文の実行
update
メソッドは、データベース内の既存のレコードを更新するために使用します。ステートメントによって影響を受けた行数がメソッドによって返されます。
use Illuminate\Support\Facades\DB; $affected = DB::update( 'update users set votes = 100 where name = ?', ['Anita']);
DELETE文の実行
delete
メソッドは、データベースからレコードを削除するために使用します。update
と同様に、影響を受けた行数がメソッドによって返されます。
use Illuminate\Support\Facades\DB; $deleted = DB::delete('delete from users');
一般ステートメントの実行
一部のデータベースステートメントは値を返しません。これらのタイプの操作には、DB
ファサードのstatement
メソッドを使用できます。
DB::statement('drop table users');
準備済みでないステートメントの実行
値をバインドせずにSQLステートメントを実行したい場合があります。これを実現するには、DB
ファサードのunprepared
メソッドを使用できます。
DB::unprepared('update users set votes = 100 where name = "Dries"');
準備済みでないステートメントはパラメータをバインドしないため、SQLインジェクションの脆弱性がある可能性があります。準備済みでないステートメント内にユーザー制御値を含めることは決してしないでください。
暗黙的コミット
トランザクション内でDB
ファサードのstatement
メソッドとunprepared
メソッドを使用する場合、暗黙的コミットを引き起こすステートメントを避けるために注意する必要があります。これらのステートメントは、データベースエンジンに間接的にトランザクション全体をコミットさせ、Laravelがデータベースのトランザクションレベルを認識できなくなります。このようなステートメントの例としては、データベーステーブルの作成があります。
DB::unprepared('create table a (col varchar(1) null)');
暗黙的コミットをトリガーするすべてのステートメントのリストについては、MySQLマニュアルを参照してください。
複数のデータベース接続の使用
アプリケーションがconfig/database.php
構成ファイルに複数の接続を定義している場合、DB
ファサードによって提供されるconnection
メソッドを使用して、各接続にアクセスできます。connection
メソッドに渡される接続名は、config/database.php
構成ファイルにリストされている接続のいずれか、またはconfig
ヘルパーを使用して実行時に構成された接続に対応している必要があります。
use Illuminate\Support\Facades\DB; $users = DB::connection('sqlite')->select(/* ... */);
接続の生の基になるPDOインスタンスには、接続インスタンスのgetPdo
メソッドを使用できます。
$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... }); }}
データベーストランザクション
DB
ファサードによって提供されるtransaction
メソッドを使用して、データベーストランザクション内で一連の操作を実行できます。トランザクションクロージャ内で例外がスローされると、トランザクションは自動的にロールバックされ、例外が再スローされます。クロージャが正常に実行されると、トランザクションは自動的にコミットされます。transaction
メソッドを使用する際には、手動でロールバックまたはコミットする必要はありません。
use Illuminate\Support\Facades\DB; DB::transaction(function () { DB::update('update users set votes = 1'); DB::delete('delete from posts');});
デッドロックの処理
transaction
メソッドは、デッドロックが発生した場合にトランザクションを再試行する回数を定義するオプションの2番目の引数を受け入れます。これらの試行が使い果たされると、例外がスローされます。
use Illuminate\Support\Facades\DB; DB::transaction(function () { DB::update('update users set votes = 1'); DB::delete('delete from posts');}, 5);
トランザクションの手動使用
トランザクションを手動で開始し、ロールバックとコミットを完全に制御したい場合は、DB
ファサードによって提供されるbeginTransaction
メソッドを使用できます。
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) { ->notify(new DatabaseApproachingMaxConnections( $event->connectionName, $event->connections )); });}