メインコンテンツまでスキップ

データベース: 初めてのステップ

はじめに

ほとんどの現代の Web アプリケーションはデータベースとやり取りします。Laravel は、サポートされているさまざまなデータベースを使用して、生の SQL、フルエントクエリビルダー、およびEloquent ORMを使ってデータベースとのやり取りを非常に簡単にします。現在、Laravel は以下の 5 つのデータベースに対して第一級のサポートを提供しています:

設定

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

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

SQLite Configuration

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 installerを使用してLaravelアプリケーションを作成し、データベースとしてSQLiteを選択した場合、Laravelは自動的にdatabase/database.sqliteファイルを作成し、デフォルトのデータベースマイグレーションを実行します。

Microsoft SQL Server Configuration

Microsoft SQL Serverデータベースを使用するには、sqlsrvおよびpdo_sqlsrv PHP拡張機能がインストールされていることを確認する必要があります。また、Microsoft SQL ODBCドライバーなど、それらが必要とする依存関係もインストールする必要があります。

Configuration Using URLs

通常、データベース接続はhostdatabaseusernamepasswordなどの複数の構成値を使用して構成されます。これらの構成値のそれぞれに対応する環境変数があります。つまり、本番サーバーでデータベース接続情報を構成する際には、複数の環境変数を管理する必要があります。

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

mysql://root:password@127.0.0.1/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_0900_ai_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'),
]) : [],
],

構成配列に readwritesticky の3つのキーが追加されていることに注意してください。readwrite キーには、host を含む単一のキーを持つ配列値があります。read および write 接続の残りのデータベースオプションは、メインの mysql 構成配列からマージされます。

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

sticky オプション

sticky オプションは、現在のリクエストサイクル中にデータベースに書き込まれたレコードの直ちに読み取りを許可するために使用できるオプション値です。sticky オプションが有効になっており、現在のリクエストサイクル中に "write" 操作がデータベースに対して実行された場合、さらなる "read" 操作は "write" 接続を使用します。これにより、リクエストサイクル中に書き込まれたデータは、その同じリクエスト中にデータベースから直ちに読み取ることができます。これがアプリケーションで望ましい動作であるかどうかは、あなたが決定することです。

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
{
/**
* 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;
}

スカラー値の選択

データベースクエリの結果が1つのスカラー値になる場合があります。レコードオブジェクトからクエリのスカラー結果を取得する必要がなく、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 メソッドは、データベースからレコードを削除するために使用されるべきです。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` 構成ファイルにリストされている接続の1つに対応するか、`config` ヘルパーを使用して実行時に構成されたものである必要があります:

```php
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;
});
}
}

累積クエリ時間の監視

現代の 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
{
/**
* 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 メソッドは、デッドロックが発生した場合にトランザクションを再試行する回数を定義するオプションの第二引数を受け入れます。これらの試行が尽きると、例外がスローされます:

    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 コマンドを 1分ごとに実行 するようにスケジュールしてください。このコマンドは、監視したいデータベース接続構成の名前と、イベントをディスパッチする前に許容される最大オープン接続数を受け入れます:

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', 'dev@example.com')
->notify(new DatabaseApproachingMaxConnections(
$event->connectionName,
$event->connections
));
});
}