数据库:入门

Introduction

几乎每个现代 Web 应用程序都与数据库交互。 Laravel 使用原始 SQL 在各种受支持的数据库中使与数据库的交互变得极其简单,流畅的查询生成器, 和雄辩的ORM.目前,Laravel 为五种数据库提供了第一方支持:

Configuration

Laravel 数据库服务的配置位于你的应用程序的config/database.php 配置文件。在此文件中,您可以定义所有数据库连接,并指定默认情况下应使用哪个连接。此文件中的大多数配置选项都由应用程序的环境变量值驱动。此文件中提供了大多数 Laravel 支持的数据库系统的示例。

默认情况下,Laravel 的示例环境配置 可以使用了Laravel 风帆,这是用于在本地计算机上开发 Laravel 应用程序的 Docker 配置。但是,您可以根据本地数据库的需要自由修改数据库配置。

SQLite配置

SQLite 数据库包含在文件系统上的单个文件中。您可以使用以下命令创建一个新的 SQLite 数据库touch 终端中的命令: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

微软 SQL 服务器配置

要使用 Microsoft SQL Server 数据库,您应该确保您拥有sqlsrvpdo_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 语句使用一个数据库连接,对 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,writesticky.这readwrite 键具有包含单个键的数组值:host.其余的数据库选项readwrite 连接将从主要合并mysql配置数组。

你只需要将物品放在readwrite 数组,如果你想覆盖主要的值mysql 大批。所以,在这种情况下,192.168.1.1 将用作“读取”连接的主机,而192.168.1.3 将用于“写”连接。主目录中的数据库凭据、前缀、字符集和所有其他选项mysql 数组将在两个连接之间共享。当多个值存在于host 配置数组,将为每个请求随机选择一个数据库主机。

sticky 选项

sticky 选项是optional 可用于允许立即读取在当前请求周期内已写入数据库的记录的值。如果sticky 选项已启用并且在当前请求周期内对数据库执行了“写入”操作,任何进一步的“读取”操作将使用“写入”连接。这确保了在请求周期内写入的任何数据都可以在同一个请求期间立即从数据库中读回。这是否是您的应用程序所需的行为由您决定。

运行 SQL 查询

配置数据库连接后,您可以使用DB 正面。这DB facade 为每种类型的查询提供方法:select,update,insert,delete, 和statement.

运行选择查询

要运行基本的 SELECT 查询,您可以使用select 上的方法DB 正面:

<?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 结果。数组中的每个结果都是一个 PHPstdClass 表示数据库记录的对象:

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"
);

使用命名绑定

而不是使用? 为了表示您的参数绑定,您可以使用命名绑定执行查询:

$results = DB::select('select * from users where id = :id', ['id' => 1]);

运行插入语句

执行一个insert 声明,你可以使用insert 上的方法DB 正面。喜欢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');

运行一般声明

一些数据库语句不返回任何值。对于这些类型的操作,您可以使用statement 上的方法DB 正面:

DB::statement('drop table users');

运行未准备好的语句

有时您可能希望在不绑定任何值的情况下执行 SQL 语句。您可以使用DB 门面的unprepared 方法来完成这个:

DB::unprepared('update users set votes = 100 where name = "Dries"');

Warning
由于未经准备的语句不绑定参数,因此它们可能容易受到 SQL 注入的攻击。您永远不应在未经准备的语句中允许用户控制值。

隐式提交

当使用DB 门面的statementunprepared 事务中的方法你必须小心避免导致隐式提交.这些语句会导致数据库引擎间接提交整个事务,让 Laravel 不知道数据库的事务级别。这种语句的一个例子是创建一个数据库表:

DB::unprepared('create table a (col varchar(1) null)');

请参考 MySQL 手册所有语句的列表 触发隐式提交。

使用多个数据库连接

如果您的应用程序在您的config/database.php 配置文件,您可以通过访问每个连接connection 提供的方法DB 正面。传递给的连接名称connection 方法应对应于您的config/database.php 配置文件或在运行时使用config帮手:

use Illuminate\Support\Facades\DB;

$users = DB::connection('sqlite')->select(/* ... */);

您可以使用以下方法访问连接的原始底层 PDO 实例getPdo 连接实例上的方法:

$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...
        });
    }
}

数据库事务

您可以使用transaction 提供的方法DB Facade 在数据库事务中运行一组操作。如果在事务闭包中抛出异常,事务将自动回滚并重新抛出异常。如果闭包执行成功,事务将自动提交。您无需担心在使用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);

手动使用事务

如果您想手动开始事务并完全控制回滚和提交,您可以使用beginTransaction 提供的方法DB 正面:

use Illuminate\Support\Facades\DB;

DB::beginTransaction();

您可以通过回滚事务rollBack 方法:

DB::rollBack();

最后,您可以通过commit 方法:

DB::commit();

Note
DB facade 的事务方法控制着两者的事务查询生成器雄辩的ORM.

连接到数据库 CLI

如果您想连接到数据库的 CLI,您可以使用db 工匠命令:

php artisan db

如果需要,您可以指定一个数据库连接名称以连接到不是默认连接的数据库连接:

php artisan db mysql

检查你的数据库

使用db:showdb:table Artisan 命令,您可以获得对数据库及其关联表的宝贵见解。要查看数据库的概览,包括其大小、类型、打开的连接数及其表的摘要,您可以使用db:show 命令:

php artisan db:show

您可以通过向命令提供数据库连接名称来指定应检查哪个数据库连接--database 选项:

php artisan db:show --database=pgsql

如果您想在命令的输出中包含表行数和数据库视图详细信息,您可以提供--counts--views 选项,分别。在大型数据库上,检索行数和查看详细信息可能很慢:

php artisan db:show --counts --views

表格概览

如果您想获得数据库中单个表的概览,您可以执行db:table 工匠命令。此命令提供数据库表的一般概述,包括其列、类型、属性、键和索引:

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 事件将被发送。您应该在应用程序的EventServiceProvider 为了向您或您的开发团队发送通知:

use App\Notifications\DatabaseApproachingMaxConnections;
use Illuminate\Database\Events\DatabaseBusy;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Notification;

/**
 * Register any other events for your application.
 */
public function boot(): void
{
    Event::listen(function (DatabaseBusy $event) {
        Notification::route('mail', 'dev@example.com')
                ->notify(new DatabaseApproachingMaxConnections(
                    $event->connectionName,
                    $event->connections
                ));
    });
}
豫ICP备18041297号-2