几乎每个现代 Web 应用程序都与数据库交互。Laravel 通过使用原始 SQL、一个流畅查询构建器和 Eloquent ORM,使得与各种支持的数据库交互变得极其简单。目前,Laravel 对五种数据库提供第一方支持:
此外,MongoDB 通过 mongodb/laravel-mongodb 包提供支持,该包由 MongoDB 官方维护。请查阅 Laravel MongoDB 文档以获取更多信息。
Laravel 数据库服务的配置位于你的应用程序的 config/database.php 配置文件中。在此文件中,你可以定义所有数据库连接,并指定应默认使用哪个连接。此文件中的大多数配置选项都由你的应用程序的环境变量的值驱动。此文件中提供了大多数 Laravel 支持的数据库系统的示例。
默认情况下,Laravel 的示例 环境配置 已准备好与 Laravel Sail 配合使用,这是一个用于在本地机器上开发 Laravel 应用程序的 Docker 配置。但是,您可以根据本地数据库的需要自由修改数据库配置。
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 安装器 来创建你的 Laravel 应用并选择 SQLite 作为你的数据库,Laravel 将会自动创建一个database/database.sqlite文件并为你运行默认的 数据库迁移。
要使用 Microsoft SQL Server 数据库,您应确保已安装 sqlsrv 和 pdo_sqlsrv PHP 扩展,以及它们可能需要的任何依赖项,例如 Microsoft SQL ODBC 驱动程序。
通常,数据库连接使用多个配置值进行配置,例如 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 (或相应的 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 选项被启用,并且在当前请求周期内已对数据库执行了 "写入" 操作,任何后续的 "读取" 操作将使用 "写入" 连接。这确保了在请求周期内写入的任何数据可以在同一个请求中立即从数据库中读回。由您决定这是否是您的应用程序的期望行为。
配置好数据库连接后,您可以使用 DB 外观运行查询。DB 外观为每种查询类型提供了方法:select、update、insert、delete 和 statement。
要运行基本的 SELECT 查询,您可以使用 DB facade 上的 select 方法:
<?php
namespace App\Http\Controllers;
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 语句时,你可以在 DB facade 上使用 insert 方法。像 select,这个方法接受 SQL 查询作为它的第一个参数,以及绑定作为它的第二个参数:
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 facade 上的 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 助手配置的:
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');
}, attempts: 5);如果您希望手动开始事务并完全控制回滚和提交,您可以使用由 DB facade 提供的 beginTransaction 方法:
use Illuminate\Support\Facades\DB;
DB::beginTransaction();您可以通过 rollBack 方法回滚事务:
DB::rollBack();最后,你可以通过 commit 方法提交一个事务:
DB::commit();[!NOTE]
DB门面的事务方法控制着 查询构造器 和 Eloquent ORM 的事务。
Connecting to the Database 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) {
Notification::route('mail', 'dev@example.com')
->notify(new DatabaseApproachingMaxConnections(
$event->connectionName,
$event->connections
));
});
}