数据库:入门
简介
几乎每个现代 Web 应用程序都与数据库交互。Laravel 使使用原始 SQL、流畅的查询构建器 和 Eloquent ORM 与各种支持的数据库进行交互变得极其简单。目前,Laravel 为五个数据库提供了原生支持
配置
Laravel 数据库服务的配置位于您的应用程序的 config/database.php
配置文件中。在这个文件中,您可以定义所有数据库连接,以及指定默认使用的连接。此文件中的大多数配置选项都由应用程序环境变量的值驱动。此文件中提供了 Laravel 支持的大多数数据库系统的示例。
默认情况下,Laravel 的样本 环境配置 适用于 Laravel Sail,它是用于在本地机器上开发 Laravel 应用程序的 Docker 配置。但是,您可以根据需要自由修改本地数据库的数据库配置。
SQLite 配置
SQLite 数据库包含在文件系统上的单个文件中。您可以使用终端中的 touch
命令创建一个新的 SQLite 数据库:touch database/database.sqlite
。创建数据库后,您可以通过将数据库的绝对路径放置在 DB_DATABASE
环境变量中来轻松配置您的环境变量以指向此数据库
DB_CONNECTION=sqliteDB_DATABASE=/absolute/path/to/database.sqlite
默认情况下,外键约束在 SQLite 连接中处于启用状态。如果您想禁用它们,应该将 DB_FOREIGN_KEYS
环境变量设置为 false
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 配置
通常,数据库连接是使用多个配置值(如 host
、database
、username
、password
等)进行配置的。每个配置值都有一个对应的环境变量。这意味着当在生产服务器上配置数据库连接信息时,您需要管理多个环境变量。
一些托管数据库提供商(如 AWS 和 Heroku)提供单个数据库“URL”,其中包含数据库的所有连接信息,在一个字符串中。一个示例数据库 URL 可能类似于以下内容
mysql://root:[email protected]/forge?charset=UTF-8
这些 URL 通常遵循标准的模式约定
driver://username:password@host:port/database?options
为了方便起见,Laravel 支持这些 URL 作为使用多个配置选项配置数据库的替代方法。如果存在 url
(或相应的 DB_URL
环境变量)配置选项,它将用于提取数据库连接和凭据信息。
读写连接
有时您可能希望对 SELECT 语句使用一个数据库连接,而对 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_unicode_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'), ]) : [],],
请注意,已向配置数组添加了三个键:read
、write
和 sticky
。read
和 write
键具有包含单个键的数组值:host
。read
和 write
连接的其余数据库选项将从主 mysql
配置数组中合并。
如果您希望覆盖来自主 mysql
数组的值,则只需要在 read
和 write
数组中放置项目。因此,在本例中,192.168.1.1
将用作“读”连接的主机,而 192.168.1.3
将用作“写”连接的主机。数据库凭据、前缀、字符集以及主 mysql
数组中的所有其他选项将在两个连接之间共享。当 host
配置数组中存在多个值时,将为每个请求随机选择一个数据库主机。
sticky
选项
sticky
选项是一个可选值,可用于允许立即读取在当前请求周期中写入数据库的记录。如果启用了 sticky
选项,并且在当前请求周期中对数据库执行了“写”操作,则任何后续的“读”操作都将使用“写”连接。这确保了在请求周期中写入的任何数据都可以在同一请求期间立即从数据库中读回。由您决定这是否是您的应用程序所需的 behaviour。
运行 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;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 查询,第二个参数是需要绑定到查询的任何参数绑定。通常,这些是 where
子句约束的值。参数绑定提供了防止 SQL 注入的保护。
select
方法将始终返回一个结果 array
。数组中的每个结果将是一个 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 查询作为第一个参数,并将绑定作为第二个参数
use Illuminate\Support\Facades\DB; DB::insert('insert into users (id, name) values (?, ?)', [1, 'Marc']);
运行 UPDATE 语句
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"');
由于未准备好的语句不绑定参数,因此它们可能容易受到 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
助手在运行时配置
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; // $query->toRawSql(); }); }}
监控累计查询时间
现代 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
命令调度到 每分钟运行一次。该命令接受您希望监视的数据库连接配置的名称,以及在派发事件之前应容忍的最大打开连接数
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) { ->notify(new DatabaseApproachingMaxConnections( $event->connectionName, $event->connections )); });}