はじめに

ほとんどすべての現代のウェブアプリケーションはデータベースと対話します。Laravelは、生のSQL、流暢なクエリビルダー、およびEloquent ORMを使用して、さまざまなサポートされているデータベースとの対話を非常に簡単にします。現在、Laravelは5つのデータベースに対してファーストパーティのサポートを提供しています:

設定

Laravelのデータベースサービスの設定は、アプリケーションのconfig/database.php設定ファイルにあります。このファイルでは、すべてのデータベース接続を定義し、どの接続をデフォルトとして使用するかを指定できます。このファイル内のほとんどの設定オプションは、アプリケーションの環境変数の値によって駆動されます。Laravelがサポートするほとんどのデータベースシステムの例がこのファイルに提供されています。

デフォルトでは、Laravelのサンプル環境設定は、Laravel Sailと共に使用する準備が整っています。これは、ローカルマシンでLaravelアプリケーションを開発するためのDocker設定です。ただし、ローカルデータベースに必要に応じてデータベース設定を変更することができます。

SQLiteの設定

SQLiteデータベースは、ファイルシステム上の単一のファイル内に含まれています。ターミナルでtouchコマンドを使用して新しいSQLiteデータベースを作成できます:touch database/database.sqlite。データベースが作成された後、DB_DATABASE環境変数にデータベースへの絶対パスを配置することで、環境変数を簡単に設定できます:

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

デフォルトでは、SQLite接続に対して外部キー制約が有効になっています。これを無効にしたい場合は、DB_FOREIGN_KEYS環境変数をfalseに設定する必要があります:

  1. 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を使用した設定

通常、データベース接続はhostdatabaseusernamepasswordなどの複数の設定値を使用して構成されます。これらの設定値にはそれぞれ対応する環境変数があります。これは、プロダクションサーバーでデータベース接続情報を構成する際に、いくつかの環境変数を管理する必要があることを意味します。

AWSやHerokuなどの一部の管理されたデータベースプロバイダーは、データベースの接続情報を単一の文字列で含む単一のデータベース「URL」を提供します。データベースURLの例は次のようになります:

  1. mysql://root:/forge?charset=UTF-8

これらのURLは通常、標準のスキーマ規約に従います:

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

便利なことに、LaravelはこれらのURLを複数の設定オプションでデータベースを構成する代替手段としてサポートしています。url(または対応するDB_URL環境変数)設定オプションが存在する場合、それを使用してデータベース接続と資格情報情報を抽出します。

読み取りおよび書き込み接続

時には、SELECT文に1つのデータベース接続を使用し、INSERT、UPDATE、およびDELETE文に別の接続を使用したい場合があります。Laravelはこれを簡単にし、rawクエリ、クエリビルダー、または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. 'database' => env('DB_DATABASE', 'laravel'),
  15. 'username' => env('DB_USERNAME', 'root'),
  16. 'password' => env('DB_PASSWORD', ''),
  17. 'unix_socket' => env('DB_SOCKET', ''),
  18. 'charset' => env('DB_CHARSET', 'utf8mb4'),
  19. 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
  20. 'prefix' => '',
  21. 'prefix_indexes' => true,
  22. 'strict' => true,
  23. 'engine' => null,
  24. 'options' => extension_loaded('pdo_mysql') ? array_filter([
  25. PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
  26. ]) : [],
  27. ],

設定配列に3つのキーが追加されています:readwrite、およびstickyreadおよびwriteキーには、単一のキーを含む配列値があります:hostreadおよびwrite接続の残りのデータベースオプションは、メインのmysql設定配列からマージされます。

メインのmysql配列からの値を上書きしたい場合は、readおよびwrite配列にアイテムを配置する必要があります。この場合、192.168.1.1は「読み取り」接続のホストとして使用され、192.168.1.3は「書き込み」接続のホストとして使用されます。データベースの資格情報、プレフィックス、文字セット、およびメインのmysql配列内のすべての他のオプションは、両方の接続で共有されます。host設定配列に複数の値が存在する場合、各リクエストに対してランダムにデータベースホストが選択されます。

スティッキーオプション

  1. <a name="running-queries"></a>
  2. ## SQLクエリの実行
  3. データベース接続を構成したら、`````DB`````ファサードを使用してクエリを実行できます。`````DB`````ファサードは、各タイプのクエリに対するメソッドを提供します:`````select`````、`````update`````、`````insert`````、`````delete`````、および`````statement`````。
  4. <a name="running-a-select-query"></a>
  5. #### SELECTクエリの実行
  6. 基本的なSELECTクエリを実行するには、`````select`````メソッドを`````DB`````ファサードで使用できます:
  7. ``````php
  8. <?php
  9. namespace App\Http\Controllers;
  10. use App\Http\Controllers\Controller;
  11. use Illuminate\Support\Facades\DB;
  12. use Illuminate\View\View;
  13. class UserController extends Controller
  14. {
  15. /**
  16. * Show a list of all of the application's users.
  17. */
  18. public function index(): View
  19. {
  20. $users = DB::select('select * from users where active = ?', [1]);
  21. return view('user.index', ['users' => $users]);
  22. }
  23. }
  24. `
  1. `````select`````メソッドは常に`````array`````の結果を返します。配列内の各結果は、データベースのレコードを表すPHP `````stdClass`````オブジェクトになります:
  2. ``````php
  3. use Illuminate\Support\Facades\DB;
  4. $users = DB::select('select * from users');
  5. foreach ($users as $user) {
  6. echo $user->name;
  7. }
  8. `

スカラー値の選択

時には、データベースクエリが単一のスカラー値を返すことがあります。クエリのスカラー結果をレコードオブジェクトから取得する必要がある代わりに、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. ``````php
  2. $results = DB::select('select * from users where id = :id', ['id' => 1]);
  3. `

INSERT文の実行

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

UPDATE文の実行

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

DELETE文の実行

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

一般的な文の実行

一部のデータベース文は値を返しません。これらのタイプの操作には、statementメソッドをDBファサードで使用できます:

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

未準備文の実行

時には、値をバインドせずにSQL文を実行したい場合があります。これを達成するために、DBファサードのunpreparedメソッドを使用できます:

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

未準備文はパラメータをバインドしないため、SQLインジェクションに対して脆弱である可能性があります。未準備文内にユーザー制御の値を許可してはいけません。

暗黙のコミット

  1. ``````php
  2. DB::unprepared('create table a (col varchar(1) null)');
  3. `

暗黙のコミットを引き起こすすべての文のリストについては、MySQLマニュアルを参照してください[https://dev.mysql.com/doc/refman/8.0/en/implicit-commit.html]。

複数のデータベース接続の使用

アプリケーションがconfig/database.php設定ファイルに複数の接続を定義している場合、DBファサードによって提供されるconnectionメソッドを介して各接続にアクセスできます。connectionメソッドに渡される接続名は、config/database.php設定ファイルにリストされている接続の1つに対応する必要があります。または、configヘルパーを使用してランタイムで構成されます:

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

接続インスタンスのgetPdoメソッドを使用して、接続の生の基盤となるPDOインスタンスにアクセスできます:

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

クエリエベントのリスニング

アプリケーションによって実行される各SQLクエリに対して呼び出されるクロージャを指定したい場合は、DBファサードのlistenメソッドを使用できます。このメソッドは、クエリのログ記録やデバッグに役立ちます。クエリリスナーのクロージャをサービスプロバイダーbootメソッドに登録できます:

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

累積クエリ時間の監視

現代のウェブアプリケーションの一般的なパフォーマンスボトルネックは、データベースをクエリするのに費やす時間です。幸いなことに、Laravelは、単一のリクエスト中にデータベースをクエリするのに時間がかかりすぎると、選択したクロージャまたはコールバックを呼び出すことができます。始めるには、whenQueryingForLongerThanメソッドにクエリ時間のしきい値(ミリ秒単位)とクロージャを提供します。このメソッドは、サービスプロバイダーbootメソッドで呼び出すことができます:

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

データベーストランザクション

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

デッドロックの処理

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

トランザクションの手動使用

トランザクションを手動で開始し、ロールバックとコミットを完全に制御したい場合は、beginTransactionメソッドをDBファサードで使用できます:

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

トランザクションをrollBackメソッドでロールバックできます:

  1. DB::rollBack();

最後に、commitメソッドでトランザクションをコミットできます:

  1. DB::commit();

DBファサードのトランザクションメソッドは、クエリビルダーEloquent ORMの両方のトランザクションを制御します。

データベースCLIへの接続

データベースのCLIに接続したい場合は、db Artisanコマンドを使用できます:

  1. php artisan db

必要に応じて、デフォルト接続ではないデータベース接続に接続するためにデータベース接続名を指定できます:

  1. php artisan db mysql

データベースの検査

db:showおよびdb:table Artisanコマンドを使用して、データベースとその関連テーブルに関する貴重な洞察を得ることができます。データベースの概要を表示するには、そのサイズ、タイプ、オープン接続の数、およびテーブルの概要を含めて、db:showコマンドを使用できます:

  1. php artisan db:show

どのデータベース接続を検査するかを指定するには、--databaseオプションを介してコマンドにデータベース接続名を提供します:

  1. php artisan db:show --database=pgsql

コマンドの出力にテーブル行数とデータベースビューの詳細を含めたい場合は、それぞれ--countsおよび--viewsオプションを提供できます。大規模なデータベースでは、行数とビューの詳細を取得するのに時間がかかることがあります:

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

さらに、Schemaメソッドを使用してデータベースを検査できます:

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

アプリケーションのデフォルト接続ではないデータベース接続を検査したい場合は、connectionメソッドを使用できます:

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

テーブルの概要

データベース内の個々のテーブルの概要を取得したい場合は、db:table Artisanコマンドを実行できます。このコマンドは、テーブルの列、タイプ、属性、キー、およびインデックスを含むデータベーステーブルの一般的な概要を提供します:

  1. php artisan db:table users

データベースの監視

db:monitor Artisanコマンドを使用して、データベースが指定された数のオープン接続を管理している場合にLaravelにIlluminate\Database\Events\DatabaseBusyイベントを発行するよう指示できます。

始めるには、db:monitorコマンドを毎分実行するようにスケジュールする必要があります。このコマンドは、監視したいデータベース接続設定の名前と、イベントを発行する前に許容されるオープン接続の最大数を受け取ります:

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

このコマンドをスケジュールするだけでは、オープン接ッションの数を通知するアラートをトリガーするには不十分です。コマンドがしきい値を超えるオープン接続数を持つデータベースに遭遇すると、DatabaseBusyイベントが発行されます。このイベントをアプリケーションのAppServiceProvider内でリッスンして、あなたや開発チームに通知を送信する必要があります:

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