Database: Getting Started
Table of Contents
Introduction
ほぼ全ての現代の web application は、 database とやり取りを行います。 Laravel は、生の SQL、流れるような query builder、そしてEloquent ORMを使用して、さまざまなサポートされているデータベースとの対話を非常に簡単にします。現在、 Laravel は 5 つのデータベースに対して一次サポートを提供しています:
Configuration
Laravel の database services の設定は、アプリケーションのconfig/database.php
設定ファイルに置かれています。このファイルでは、すべての database 接続を定義するとともに、どの connection を default として使用するべきかを指定することもできます。このファイル内の設定 options のほとんどは、アプリケーションの environment 変数の values によって制御されています。このファイルには、Laravel がサポートしているほとんどの database システムの例が提供されています。
default として、Laravel のサンプル環境設定は、ローカルマシンで Laravel applications を development するための Docker 設定であるLaravel Sailを使用する準備ができています。しかし、ローカルの database に必要な設定を自由に変更することができます。
SQLite 設定
SQLite データベースは、ファイルシステム上の single ファイルに格納されています。端末のtouch
command を使用して、新しい SQLite database を作成することができます:touch database/database.sqlite
。 database が作成された後、DB_DATABASE
environment 変数に database への絶対 path を指定することにより、この database へ簡単に environment 変数を設定できます。
DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqlite
default で、SQLite 接続に対する外部キー制約が有効になっています。それらを無効にしたい場合は、DB_FOREIGN_KEYS
environment variables をfalse
に設定するべきです:
DB_FOREIGN_KEYS=false
NOTE
Laravel インストーラを使用して Laravel アプリケーションを作成し、SQLite を database として選択すると、Laravel は自動的に
database/database.sqlite
ファイルを作成し、あなたのために default のdata ベース migrationを実行します。
Microsoft SQL Server の構成
Microsoft SQL Server の database を使用するには、sqlsrv
およびpdo_sqlsrv
PHP エクステンションがインストールされており、それらが必要とする依存関係がすべて満たされていること、例えば、Microsoft SQL ODBC の driver などを確認してください。
URL を使用した設定
通常、database 接続はhost
、database
、username
、password
、etc などの複数の設定 values を使用して構成されます。これらの各設定 values にはそれぞれ対応する environment 変数があります。これは、production サーバーで database connection 情報を設定する際に、複数の environment 変数を管理する必要があることを意味します。
いくつかの管理された database providers 、例えば AWS や Heroku は、"URL"内にすべての connection 情報を含む一つの single database を提供します。" database の全体の情報が single string で記述されています。 その一例として、以下のような database URL が考えられます。
mysql://root:password@127.0.0.1/forge?charset=UTF-8
これらの URL は通常、標準的な schema の慣習に従っています:
driver://username:password@host:port/database?options
便宜上、Laravel は複数の設定 options を使用して database を構成する代わりに、これらの URL をサポートしています。url
(または対応するDB_URL
environment 変数)設定オプションが存在する場合、それは database connection および認証情報を抽出するために使用されます。
読み書きの接続
時折、あなたは SELECT 文に対して一つの database connection を使用し、他の INSERT 、 UPDATE 、そして DELETE 文には別のものを使用したいと思うかもしれません。 Laravel ではこれが breeze であり、生のクエリを使用しているか、 query ビルダーを使用しているか、または Eloquent ORM を使用しているかに関わらず、常に適切な接続が使用されます。
read / write 接続がどのように設定されるべきかを確認するために、この例を見てみましょう:
'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'),
]) : [],
],
設定の array には三つの keys が追加されていることに注意してください:read
、write
、およびsticky
です。read
とwrite
の keys は、 single のキーを含む array values を持っています:host
。read
とwrite
の接続のための残りの database options は、主要なmysql
設定の array からマージされます。
メインのmysql
array から values を上書きしたい場合のみ、read
とwrite
の配列にアイテムを配置する必要があります。したがって、この場合、192.168.1.1
は"read" connection 用のホストとして使用され、192.168.1.3
は"write" connection 用として使用されます。database の資格情報、プレフィックス、文字セット、およびその他の options はメインのmysql
array で両方の接続間で共有されます。host
設定 array に複数の values が存在する場合、database ホストは各 request ごとにランダムに選択されます。
sticky
オプション
sticky
オプションは、オプショナルな value で、現在の request サイクル中に database に書き込まれたレコードを即座に読み取ることを許可するために使用できます。sticky
オプションが有効になっていて、現在の request サイクル中に database に対して"write"操作が行われた場合、任意のさらなる"read"操作は"write" connection を使用します。これにより、 request サイクル中に書き込まれた任意の data を、その同じ request の間に database から直ちに読み戻すことができます。これがあなたの application にとって望ましい動作であるかどうかは、あなたが判断することです。
Running SQL Queries
database 接続を設定したら、DB
facade を使ってクエリを実行できます。DB
facade は、各種類の query:select
、update
、insert
、delete
、そしてstatement
用の methods を提供しています。
Select Query の実行
基本的な SELECT query を実行するためには、DB
facade のselect
method を利用することができます:
<?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
の method へ渡される最初の引数は、SQL の query であり、2 番目の引数は、 query にバインドする必要があるパラメーター・バインディングです。通常、これらはwhere
句の制約の values です。パラメーター・バインディングは SQL インジェクションからの保護を提供します。
select
method は常に結果のarray
を返します。 array 内の各結果は、 database からのレコードを表す PHP のstdClass
object になります。
use Illuminate\Support\Facades\DB;
$users = DB::select('select * from users');
foreach ($users as $user) {
echo $user->name;
}
Scalar Values の選択
時々、あなたの database query は single 、 scalar value を結果として生じるかもしれません。レコードの object からクエリの scalar 結果を取得するために required とされる代わりに、 Laravel はあなたがこのscalar
method を使って value を直接取得することを許可します:
$burgers = DB::scalar(
"select count(case when food = 'burger' then 1 end) as burgers from menu"
);
複数の結果セットの選択
もし、あなたの application が複数の結果セットを返すストアドプロシージャを呼び出す場合、selectResultSets
method を使用して、ストアドプロシージャによって返されるすべての結果セットを取得することができます:
[$options, $notifications] = DB::selectResultSets(
"CALL get_user_options_and_notifications(?)", $request->user()->id
);
名前付きバインディングの使用
パラメータバインディングを表すために?
を使用する代わりに、名前付きバインディングを使用して query を実行することができます:
$results = DB::select('select * from users where id = :id', ['id' => 1]);
Insert Statement の実行
insert
の statement を実行するには、DB
facade 上でinsert
の method を使用することができます。select
と同様に、この method は SQL の query を第一引数とし、バインディングを第二引数として受け入れます。
use Illuminate\Support\Facades\DB;
DB::insert('insert into users (id, name) values (?, ?)', [1, 'Marc']);
Update Statement の実行
update
の method は、database 内の既存のレコードをアップデートするために使用されるべきです。statement によって影響を受ける行の数は、method によって返されます。
use Illuminate\Support\Facades\DB;
$affected = DB::update(
'update users set votes = 100 where name = ?',
['Anita']
);
Delete Statement の実行
delete
method は、database からレコードを削除するために使用するべきです。update
と同様に、影響を受ける行の数は method によって返されます:
use Illuminate\Support\Facades\DB;
$deleted = DB::delete('delete from users');
一般的な Statement の実行
一部の database ステートメントは何も value を返さない可能性があります。この種の操作の場合、DB
facade 上のstatement
method を使用することができます:
DB::statement('drop table users');
準備されていない Statement の実行
時には何の values もバインドせずに SQL の statement を実行したい場合があるかもしれません。そのような場合は、DB
ファサードのunprepared
method を用いることで実現できます。
DB::unprepared('update users set votes = 100 where name = "Dries"');
WARNING
未準備のステートメントではパラメータがバインドされないため、SQL インジェクションに対して脆弱になる可能性があります。決して user が制御する values を未準備の statement 内に許可してはなりません。
暗黙的なコミット
DB
facade の statement
および unprepared
methods を transaction 内で使用する際には、暗黙のコミット を引き起こす statement を避ける必要があります。これらの statement は、database エンジンが間接的に全体の transaction をコミットし、Laravel が database の transaction レベルを認識できなくなります。statement の例としては、database テーブルの作成があります:
DB::unprepared('create table a (col varchar(1) null)');
すべてのステートメントのリスト が含まれている MySQL マニュアルを参照してください。これらのステートメントは暗黙のコミットをトリガーします。
複数の Database 接続を使用する
もし、application がconfig/database.php
の設定ファイルで複数の接続を定義している場合、DB
の facade が提供するconnection
method を通じて、各々の接続にアクセスすることができます。connection
method に渡される接続名は、config/database.php
の設定ファイルにリストされている接続の一つか、config
helper を使用して実行時に設定されたものに対応しているべきです。
use Illuminate\Support\Facades\DB;
$users = DB::connection('sqlite')->select(/* ... */);
connection のインスタンスでgetPdo
method を使用して、生の、基礎となる PDO インスタンスにアクセスすることができます。
$pdo = DB::connection()->getPdo();
Query Events のリスニング
あなたの application によって実行されたすべての SQL の query に対して呼び出されるクロージャを指定したい場合は、DB
ファサードのlisten
method を使用することができます。この method は、 logging のクエリや debugging に便利です。あなたは自分の query リスナークロージャを、service providerのboot
method で register することができます。
<?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 時間の監視
現代の webapplications の一般的なパフォーマンスのボトルネックは、database の query にかかる時間です。ありがたいことに、Laravel は、database への query 時間が single request の間に過ぎてしまったときに、あなたの選んだクロージャまたはコールバックを実行することができます。始めるには、query の時間閾 values(ミリ秒)とクロージャをwhenQueryingForLongerThan
method に提供します。あなたはこの method を service provider の boot
method で呼び出すことができます。
<?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...
});
}
}
Database Transactions
DB
facade によって提供されるtransaction
method を使用すると、一連の操作を database transaction 内で実行することができます。 transaction クロージャ内で例外が throw された場合、 transaction は自動的にロールバックされ、例外は再 throw されます。クロージャが正常に実行された場合、 transaction は自動的にコミットされます。transaction
method を使用する際に、手動でロールバックやコミットをする心配は必要ありません。
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
DB::update('update users set votes = 1');
DB::delete('delete from posts');
});
デッドロックの処理
transaction
の method は、デッドロックが発生したときに transaction を再試行する回数を定義する任意の第二引数を受け入れます。これらの試行が全て失敗した場合、例外がスローされます:
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
DB::update('update users set votes = 1');
DB::delete('delete from posts');
}, 5);
手動で Transactions を使用する
ロールバックとコミットに完全にコントロールを持つために、手動で transaction を開始したい場合は、DB
facade が提供するbeginTransaction
method を使用することができます:
use Illuminate\Support\Facades\DB;
DB::beginTransaction();
rollBack
method を通じて transaction を rollback することができます:
DB::rollBack();
最後に、commit
method を使用して transaction をコミットすることができます:
DB::commit();
NOTE
DB
ファサードの transaction メソッドは、query builderとEloquent ORMの両方の transactions を制御します。
Connecting to the Database CLI
データベースの CLI に接続したい場合は、db
Artisan command を使用することができます:
php artisan db
必要に応じて、 default connection ではない database connection に接続するための database connection 名を指定することができます。
php artisan db mysql
Inspecting Your Databases
db:show
とdb:table
の Artisan コマンドを使用すると、 database とそれに関連するテーブルについて貴重な洞察を得ることができます。 database の概要、そのサイズ、 type 、開いている接続の数、テーブルの概要を見るには、db:show
の command を使用できます。
php artisan db:show
--database
option を使用して command に database 接続名を指定することで、どの database 接続を検査するかを指定できます。
php artisan db:show --database=pgsql
command の output 内にテーブル行のカウントと database view の詳細を含めたい場合は、それぞれ--counts
と--views
options を提供できます。大規模な database では、行のカウントと view の詳細の取得が遅くなる可能性があります。
php artisan db:show --counts --views
また、以下の Schema
も数ある database を検査するために使用することができます:
use Illuminate\Support\Facades\Schema;
$tables = Schema::getTables();
$views = Schema::getViews();
$columns = Schema::getColumns('users');
$indexes = Schema::getIndexes('users');
$foreignKeys = Schema::getForeignKeys('users');
あなたのアプリケーションの default connection ではない database connection を検査したい場合は、connection
method を使用することができます。
$columns = Schema::connection('sqlite')->getColumns('users');
表の概要
あなたの database 内の個々のテーブルの概要を得たい場合は、db:table
Artisan command を実行することができます。 この command は、 database テーブルの一般的な概要を提供します。これには、そのカラム、タイプ、 attributes 、 keys 、およびインデックスが含まれます:
php artisan db:table users
Monitoring Your Databases
db:monitor
の Artisan command を使用すると、 Laravel に対して、 database が指定された数以上のオープン接続を管理している場合にIlluminate\Database\Events\DatabaseBusy
の event を dispatch するように指示することができます。
始めるには、db:monitor
command を毎分実行するように schedule する必要があります。この command は、監視したい database connection の設定名と、 event をディスパッチする前に許容すべき最大の開放接続数を受け入れます。
php artisan db:monitor --databases=mysql,pgsql --max=100
この command だけをスケジューリングするだけでは、オープンしている connection の数を知らせる notification をトリガーするのに十分ではありません。 command がオープンしている connection の数があなたのしきい values を超える database に遭遇した場合、 DatabaseBusy
event が発行されます。 あなた自身または development チームに notification を送るために、application 内の AppServiceProvider
でこの event を待ち受けるべきです。
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
));
});
}