数据库:入门

简介

Laravel 可以非常简单地和各种数据库后端进行交互,无论是使用原生 SQL、流畅的查询构造器,还是使用 Eloquent ORM。目前,Laravel 支持四种数据库:

  • MySQL
  • PostgreSQL
  • SQLite
  • SQL Server

配置

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

默认情况下,Laravel 的示例 环境配置Laravel Homestead 一起使用,Laravel Homestead 是一个在本地计算机上进行 Laravel 开发的方便的虚拟机。当然,您可以根据本地数据库需要自由修改此配置。

SQLite 配置

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

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

读 & 写连接

有时可能希望 SELECT 语句使用一个连接,而 INSERT、UPDATE 和 DELETE 语句使用另一个连接。Laravel 中可以轻松实现,无论您使用原生查询语句、查询构造器或者 Eloquent ORM,都会始终使用正确的连接。

要了解如何配置读/写连接,我们看一个示例:

'mysql' => [
    'read' => [
        'host' => ['192.168.1.1'],
    ],
    'write' => [
        'host' => ['196.168.1.2'],
    ],
    '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.2 作为主机。以上两个连接会共享主数组 mysql 的数据库用户密码、前缀、字符集和所有其它选项。

sticky 选项

sticky 选项是一个 可选 值,用于允许立即读取当前请求周期写入到数据库的记录。启用 sticky 选项后,如果当前请求周期对数据库执行「写」操作,后面的任何「读」操作都会使用「写」连接。以确保请求周期写入的任何数据可以在同一请求中从数据库立即读取到。您可以决定,这是否是应用所需的行为。

使用多个数据库连接

使用多个连接时,可以通过 DB Facade 的 connection 方法获取每个连接。传递给 connection 方法的 name 应该与在 config/database.php 配置文件中列出的连接之一相对应:

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

也可以在连接实例上使用 getPdo 方法获取底层的原生 PDO 实例:

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

运行原生 SQL 语句

配置数据库连接后,就可以使用 DB Facade 运行语句了。DB Facade 为每种类型的语句都提供了方法:selectupdateinsertdeletestatement

运行查询语句

要运行基本的查询语句,可以使用 DB Facade 的 select 方法:

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 方法会始终返回一个包含查询结果的数组。数组中的每个结果都是一个 PHP stdClass 对象,允许您获取结果中的值:

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

使用参数绑定

除了使用 ? 表示参数绑定外,还可以使用命名绑定执行语句:

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

运行插入语句

要运行 insert 语句,可以使用 DB Facade 的 insert 方法。与 select 一样,此方法使用原生 SQL 语句作为其第一个参数,绑定作为其第二个参数:

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

运行更新语句

update 可用于更新数据库中已存在的记录。会返回该语句影响的行数:

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

运行删除语句

delete 方法可用于删除数据库中的记录。与 update 一样,会返回受影响的行数:

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

运行普通语句

有些数据库语句不返回任何值。对于这类操作,可以使用 DB Facade 的 statement 方法:

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

监听查询事件

如果要接收应用执行的每条 SQL 语句,可以使用 listen 方法。此方法在记录语句或调试时很有用。可以在 服务提供者 中注册语句监听器:

namespace App\Providers;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * 启动任何应用服务
     *
     * @return void
     */
    public function boot()
    {
        DB::listen(function ($query) {
            // $query->sql
            // $query->bindings
            // $query->time
        });
    }

    /**
     * 注册服务提供者
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

数据库事务

可以使用 DB Facade 的 transaction 方法运行数据库事务中一组操作。如果事务闭包中抛出了异常,事务将自动回滚。如果闭包成功执行,事务将自动提交。使用 transaction 方法时不用担心手动回滚或提交:

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

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

处理死锁

transaction 方法接收一个可选的第二个参数,它定义了当死锁发生时事务应该重新尝试的次数。尝试次数用完后,会抛出异常:

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

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

手动使用事务

如果要手动开启事务并完全控制回滚和提交,可以使用 DB Facade 的 beginTransaction 方法:

DB::beginTransaction();

可以通过 beginTransaction 方法回滚事务:

DB::rollBack();

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

DB::commit();

DB Facade 的事务方法同时控制 查询构造器Eloquent ORM 的事务。