Skip to content

数据库:入门指南

介绍

Laravel 通过使用原生 SQL、流畅的查询构建器Eloquent ORM,使得与多种数据库后端的交互变得极其简单。目前,Laravel 支持四种数据库:

  • MySQL
  • PostgreSQL
  • SQLite
  • SQL Server

配置

应用程序的数据库配置位于 config/database.php。在此文件中,您可以定义所有的数据库连接,并指定默认使用哪个连接。此文件中提供了大多数支持的数据库系统的示例。

默认情况下,Laravel 的示例环境配置已准备好与 Laravel Homestead 一起使用,后者是一个方便的虚拟机,用于在本地机器上进行 Laravel 开发。您可以根据需要自由修改此配置以适应本地数据库。

SQLite 配置

在使用诸如 touch database/database.sqlite 的命令创建新的 SQLite 数据库后,您可以通过使用数据库的绝对路径轻松配置环境变量以指向此新创建的数据库:

php
DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqlite

要为 SQLite 连接启用外键约束,您应在 config/database.php 配置文件中添加 foreign_key_constraints 选项:

php
'sqlite' => [
    // ...
    'foreign_key_constraints' => true,
],

使用 URL 进行配置

通常,数据库连接是使用多个配置值进行配置的,例如 hostdatabaseusernamepassword 等。每个配置值都有其对应的环境变量。这意味着在生产服务器上配置数据库连接信息时,您需要管理多个环境变量。

一些托管数据库提供商(如 Heroku)提供了一个包含所有数据库连接信息的单一数据库“URL”。示例数据库 URL 可能如下所示:

php
mysql://root:password@127.0.0.1/forge?charset=UTF-8

这些 URL 通常遵循标准的模式约定:

php
driver://username:password@host:port/database?options

为了方便起见,Laravel 支持这些 URL 作为使用多个配置选项配置数据库的替代方法。如果存在 url(或相应的 DATABASE_URL 环境变量)配置选项,它将用于提取数据库连接和凭据信息。

读写连接

有时您可能希望为 SELECT 语句使用一个数据库连接,而为 INSERT、UPDATE 和 DELETE 语句使用另一个数据库连接。Laravel 使这变得轻而易举,无论您是使用原生查询、查询构建器还是 Eloquent ORM,都会始终使用正确的连接。

要查看如何配置读/写连接,让我们看一下这个示例:

php
'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'    => '',
],

请注意,配置数组中添加了三个键:readwritestickyreadwrite 键具有包含单个键的数组值:hostreadwrite 连接的其余数据库选项将从主 mysql 数组中合并。

如果您希望覆盖主数组中的值,只需将项目放入 readwrite 数组中即可。因此,在这种情况下,192.168.1.1 将用作“读”连接的主机,而 192.168.1.3 将用作“写”连接的主机。数据库凭据、前缀、字符集和主 mysql 数组中的所有其他选项将在两个连接之间共享。

sticky 选项

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

使用多个数据库连接

使用多个连接时,您可以通过 DB facade 上的 connection 方法访问每个连接。传递给 connection 方法的 name 应对应于 config/database.php 配置文件中列出的连接之一:

php
$users = DB::connection('foo')->select(...);

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

php
$pdo = DB::connection()->getPdo();

运行原生 SQL 查询

配置数据库连接后,您可以使用 DB facade 运行查询。DB facade 为每种类型的查询提供了方法:selectupdateinsertdeletestatement

运行选择查询

要运行基本查询,您可以在 DB facade 上使用 select 方法:

php
<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * 显示应用程序所有用户的列表。
     *
     * @return Response
     */
    public function index()
    {
        $users = DB::select('select * from users where active = ?', [1]);

        return view('user.index', ['users' => $users]);
    }
}

传递给 select 方法的第一个参数是原生 SQL 查询,而第二个参数是需要绑定到查询的任何参数绑定。通常,这些是 where 子句约束的值。参数绑定提供了对 SQL 注入的保护。

select 方法将始终返回一个结果的 array。数组中的每个结果将是一个 PHP stdClass 对象,允许您访问结果的值:

php
foreach ($users as $user) {
    echo $user->name;
}

使用命名绑定

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

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

运行插入语句

要执行 insert 语句,您可以在 DB facade 上使用 insert 方法。与 select 类似,此方法将原生 SQL 查询作为第一个参数,并将绑定作为第二个参数:

php
DB::insert('insert into users (id, name) values (?, ?)', [1, 'Dayle']);

运行更新语句

update 方法应用于更新数据库中的现有记录。语句影响的行数将被返回:

php
$affected = DB::update('update users set votes = 100 where name = ?', ['John']);

运行删除语句

delete 方法应用于从数据库中删除记录。与 update 类似,影响的行数将被返回:

php
$deleted = DB::delete('delete from users');

运行通用语句

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

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

监听查询事件

如果您希望接收应用程序执行的每个 SQL 查询,您可以使用 listen 方法。此方法对于记录查询或调试非常有用。您可以在服务提供者中注册查询监听器:

php
<?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 facade 上的 transaction 方法在数据库事务中运行一组操作。如果在事务 Closure 中抛出异常,事务将自动回滚。如果 Closure 成功执行,事务将自动提交。使用 transaction 方法时,您无需担心手动回滚或提交:

php
DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);

    DB::table('posts')->delete();
});

处理死锁

transaction 方法接受一个可选的第二个参数,该参数定义在发生死锁时应重新尝试事务的次数。一旦这些尝试耗尽,将抛出异常:

php
DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);

    DB::table('posts')->delete();
}, 5);

手动使用事务

如果您希望手动开始事务并完全控制回滚和提交,您可以使用 DB facade 上的 beginTransaction 方法:

php
DB::beginTransaction();

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

php
DB::rollBack();

最后,您可以通过 commit 方法提交事务:

php
DB::commit();
lightbulb

DB facade 的事务方法控制查询构建器Eloquent ORM 的事务。