イントロダクション
最近のほとんどすべてのWebアプリケーションは、データベースとやり取りします。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データベースを使用するには、sqlsrv
、pdo_sqlsrv
PHP拡張機能と、Microsoft
SQL
ODBCドライバーなど必要な依存関係パッケージを確実にインストールしてください。
URLを使用した設定
通常、データベース接続は、host
、database
、username
、password
などの複数の設定値により構成します。こうした設定値には、それぞれ対応する環境変数があります。これは、運用サーバでデータベース接続情報を設定するときに、複数の環境変数を管理する必要があることを意味します。
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' => '',
],
設定配列には、read
、write
、sticky
の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
ファサードは、クエリのタイプごとにselect
、update
、insert
、delete
、statement
メソッドを提供しています。
SELECTクエリの実行
基本的なSELECTクエリを実行するには、DB
ファサードでselect
メソッドを使用します。
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
class UserController extends Controller
{
/**
* アプリケーションの全ユーザーのリストを表示
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$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;
}
名前付きバインディングの使用
パラメータバインディングを表すために?
を使用する代わりに、名前付きバインディングを使用してクエリを実行できます。
$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"');
Note: プリペアドではない文はパラメーターをバインドしないため、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\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* アプリケーションの全サービスの登録
*
* @return void
*/
public function register()
{
//
}
/**
* アプリケーションの全サービスの起動初期処理
*
* @return void
*/
public function boot()
{
DB::listen(function ($query) {
// $query->sql;
// $query->bindings;
// $query->time;
});
}
}
データベーストランザクション
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();
Tip!!
DB
ファサードのトランザクションメソッドは、クエリビルダとEloquent ORMの両方のトランザクションを制御します。
データベースCLIへの接続
データベースのCLIに接続する場合は、db
Artisanコマンドを使用します。
php artisan db
必要に応じて、データベース接続名を指定して、デフォルト接続以外のデータベースへ接続できます。
php artisan db mysql