Laravel 10.x データベース:準備

イントロダクション

最近のウェブアプリケーションは、ほとんどすべてデータベースを操作します。Laravelは、素のSQL、FluentクエリビルダEloquent ORMを使用し、サポートしている様々なデータベースの操作をとてもシンプルにしています。現在、Laravelは5つのデータベースのファーストパーティーサポートを提供しています。

設定

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

デフォルトのLaravelのサンプル環境設定は、Laravel Sailで使用できるようにしています。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環境変数をtrueに設定する必要があります。

DB_FOREIGN_KEYS=true

Microsoft SQLサーバ設定

Microsoft SQL Serverデータベースを使用するには、sqlsrvpdo_sqlsrvPHP拡張機能と、Microsoft SQL ODBCドライバなど必要な依存関係パッケージを確実にインストールしてください。

URLを使用した設定

通常、データベース接続は、hostdatabaseusernamepasswordなどの複数の設定値により構成します。こうした設定値には、それぞれ対応する環境変数があります。つまり、運用サーバでデータベース接続情報を設定するときに、これら複数の環境変数を管理する必要があることを意味します。

AWSやHerokuなどの一部のマネージドデータベースプロバイダは、データベースのすべての接続情報を単一の文字カラムで含む単一のデータベース「URL」を提供しています。データベースURLの例は、次のようになります。

mysql://root:password@127.0.0.1/forge?charset=UTF-8

こうしたURLは通常、標準のスキーマ規約に従います。

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

便利が良いように、Laravelは複数の設定オプションを使用してデータベースを構成する代わりに、こうしたURLをサポートしています。url(または対応するDATABASE_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,
    'driver' => 'mysql',
    'database' => 'database',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
],

設定配列には、readwritestickyの3キーが追加されていることに注目してください。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ファサードは、クエリのタイプごとにselectupdateinsertdeletestatementメソッドを提供します。

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
{
    /**
     * アプリケーションの全ユーザーのリストを表示
     */
    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メソッドは常に結果の配列を返します。配列内の各結果は、データベースのレコードを表す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メソッドを使用する必要があります。メソッドは実行の影響を受けた行数を返します。

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"');

Warning!! プリペアドではない文はパラメーターをバインドしないため、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ヘルパを使用して設定した接続の1つに対応させる必要があります。

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
{
    /**
     * アプリケーションの全サービスの登録
     */
    public function register(): void
    {
        // ...
    }

    /**
     * アプリケーションの全サービスの起動初期処理
     */
    public function boot(): void
    {
        DB::listen(function (QueryExecuted $query) {
            // $query->sql;
            // $query->bindings;
            // $query->time;
        });
    }
}

累積クエリ時間の監視

モダンなWebアプリケーションの一般的なパフォーマンスボトルネックは、データベースのクエリに費やす時間の長さです。幸いなことに、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
{
    /**
     * アプリケーションの全サービスの登録
     */
    public function register(): void
    {
        // ...
    }

    /**
     * アプリケーションの全サービスの起動初期処理
     */
    public function boot(): void
    {
        DB::whenQueryingForLongerThan(500, function (Connection $connection, QueryExecuted $event) {
            // 開発チームへ通知を送る…
        });
    }
}

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

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();

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

データベースCLIへの接続

データベースのCLIに接続する場合は、db Artisanコマンドを使用します。

php artisan db

必要に応じて、データベース接続名を指定して、デフォルト接続以外のデータベースへ接続できます。

php artisan db mysql

データベースの調査

Artisanのdb:showコマンドと、db:tableコマンドを使用すると、データベースのサイズや種類、開いている接続の数、テーブルの概要など、データベースと関連するテーブルの貴重な情報を取得できます。データベースの概要を確認するには、db:showコマンドを使用します。

php artisan db:show

このコマンドで、どのデータベース接続を検査するかを--databaseオプションを使い接続名で指定できます。

php artisan db:show --database=pgsql

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

php artisan db:show --counts --views

テーブルの概要

データベース内の個々のテーブルの概要を知りたい場合には、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イベントを発行します。あなたや開発チームに通知を送るために、アプリケーションのEventServiceProvider内で、このイベントをリッスンする必要があります。

use App\Notifications\DatabaseApproachingMaxConnections;
use Illuminate\Database\Events\DatabaseBusy;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Notification;

/**
 * アプリケーションのその他の全イベントの登録
 */
public function boot(): void
{
    Event::listen(function (DatabaseBusy $event) {
        Notification::route('mail', 'dev@example.com')
                ->notify(new DatabaseApproachingMaxConnections(
                    $event->connectionName,
                    $event->connections
                ));
    });
}

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる