数据库:入门

简介

Laravel 能使用原生 SQL、流畅的查询构造器Eloquent ORM 在各种数据库后台与数据库进行非常简单的交互。当前 Laravel 支持四种数据库:

  • MySQL
  • PostgreSQL
  • SQLite
  • SQL Server

配置

数据库的配置文件放置在 config/database.php 文件中,你可以在此定义所有的数据库连接,并指定默认使用的连接。此文件内提供了大部分 Laravel 能支持的数据库配置示例。

默认情况下,Laravel 的示例 环境配置 使用了 Laravel Homestead(这是一种小型虚拟机,能让你很方便地在本地进行 Laravel 的开发)。你可以根据本地数据库的需要修改这个配置。

SQLite 配置

使用类似 touch database/database.sqlite 之类命令创建一个新的 SQLite 数据库之后,可以使用数据库的绝对路径配置环境变量来指向这个新创建的数据库:

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

如果要开启 SQLite 连接的外键约束,您应该将 foreign_key_constraints 添加到 config / database.php 配置文件中:

  1. 'sqlite' => [
  2. // ...
  3. 'foreign_key_constraints' => true,
  4. ],

URLs 式配置

通常,数据库连接使用多个配置值,例如 host, database, username, password 等。这些配置值中的每一个都有其相应的环境变量。这意味着在生产服务器上配置数据库连接信息时,需要管理多个环境变量。

一些托管数据库提供程序(如 heroku )提供单个数据库「URL」,该 url 在单个字符串中包含数据库的所有连接信息。示例数据库 URL 可能如下所示:

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

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

  1. driver://username:password@host:port/database?options

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

读写分离

有时候你希望 SELECT 语句使用一个数据库连接,而 INSERT,UPDATE,和 DELETE 语句使用另一个数据库连接。在 Laravel 中,无论你是使用原生查询,查询构造器,或者是 Eloquent ORM,都能轻松的实现

为了弄明白读写分离是如何配置的,我们先来看个例子:

  1. 'mysql' => [
  2. 'read' => [
  3. 'host' => [
  4. '192.168.1.1',
  5. '196.168.1.2',
  6. ],
  7. ],
  8. 'write' => [
  9. 'host' => [
  10. '196.168.1.3',
  11. ],
  12. ],
  13. 'sticky' => true,
  14. 'driver' => 'mysql',
  15. 'database' => 'database',
  16. 'username' => 'root',
  17. 'password' => '',
  18. 'charset' => 'utf8mb4',
  19. 'collation' => 'utf8mb4_unicode_ci',
  20. 'prefix' => '',
  21. ],

注意在以上的例子中,配置数组中增加了三个键,分别是 readwritestickyreadwrite 的键都包含一个键为 host 的数组。而 readwrite 的其他数据库都在键为 mysql 的数组中。

如果你想重写主数组中的配置,只需要修改 readwrite 数组即可。所以,这个例子中: 192.168.1.1192.168.1.2 将作为 「读」 连接主机,而 192.168.1.3 将作为 「写」 连接主机。这两个连接会共享 mysql 数组的各项配置,如数据库的凭据(用户名 / 密码),前缀,字符编码等。

sticky 选项

sticky 是一个 可选值,它可用于立即读取在当前请求周期内已写入数据库的记录。若 sticky 选项被启用,并且当前请求周期内执行过 「写」 操作,那么任何 「读」 操作都将使用 「写」 连接。这样可确保同一个请求周期内写入的数据可以被立即读取到,从而避免主从延迟导致数据不一致的问题。不过是否启用它,取决于应用程序的需求。

使用多个数据库连接

当使用多个数据库连接时,你可以通过 DB Facade 的 connection 方法访问每一个连接。传递给 connection方法的参数 name 应该是 config/database.php 配置文件中 connections 数组中的一个值:

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

你也可以使用一个连接实例上的 getPdo 方法访问底层的 PDO 实例:

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

运行原生 SQL 查询

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

运行 Select 查询

你可以使用 DB Facade 的 select 方法来运行基础的查询语句:

  1. <?php
  2. namespace App\Http\Controllers;
  3. use Illuminate\Support\Facades\DB;
  4. use App\Http\Controllers\Controller;
  5. class UserController extends Controller
  6. {
  7. /**
  8. * 显示应用程序中所有用户的列表
  9. *
  10. * @return Response
  11. */
  12. public function index()
  13. {
  14. $users = DB::select('select * from users where active = ?', [1]);
  15. return view('user.index', ['users' => $users]);
  16. }
  17. }

传递给 select 方法的第一个参数就是一个原生的 SQL 查询,而第二个参数则是需要绑定到查询中的参数值。通常,这些值用于约束 where 语句。参数绑定用于防止 SQL 注入。

select 方法将始终返回一个数组,数组中的每个结果都是一个 StdClass 对象,可以像下面这样访问结果值:

  1. foreach ($users as $user) {
  2. echo $user->name;
  3. }

使用命名绑定

除了使用 ? 表示参数绑定外,你也可以使用命名绑定来执行一个查询:

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

运行插入语句

可以使用 DB Facade 的 insert 方法来执行 insert 语句。与 select 一样,该方法将原生 SQL 查询作为其第一个参数,并将绑定数据作为第二个参数:

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

运行更新语句

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

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

运行删除语句

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

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

运行普通语句

有些数据库语句不会有任何返回值。对于这些语句,你可以使用 DB Facade 的 statement 方法来运行:

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

监听查询事件

如果你想监控程序执行的每一个 SQL 查询,你可以使用 listen 方法。这个方法对于记录查询或调试非常有用。你可以在 服务提供器 中注册你的查询监听器:

  1. <?php
  2. namespace App\Providers;
  3. use Illuminate\Support\Facades\DB;
  4. use Illuminate\Support\ServiceProvider;
  5. class AppServiceProvider extends ServiceProvider
  6. {
  7. /**
  8. * 注册服务提供器
  9. *
  10. * @return void
  11. */
  12. public function register()
  13. {
  14. //
  15. }
  16. /**
  17. * 启动应用服务
  18. *
  19. * @return void
  20. */
  21. public function boot()
  22. {
  23. DB::listen(function ($query) {
  24. // $query->sql
  25. // $query->bindings
  26. // $query->time
  27. });
  28. }
  29. }

数据库事务

你可以使用 DB facade 的 transaction 方法在数据库事务中运行一组操作。如果事务的闭包 Closure 中出现一个异常,事务将会回滚。如果事务闭包 Closure 执行成功,事务将自动提交。一旦你使用了 transaction , 就不再需要担心手动回滚或提交的问题:

  1. DB::transaction(function () {
  2. DB::table('users')->update(['votes' => 1]);
  3. DB::table('posts')->delete();
  4. });

处理死锁

transaction 方法接受一个可选的第二个参数 ,该参数用来表示事务发生死锁时重复执行的次数。一旦定义的次数尝试完毕,就会抛出一个异常:

  1. DB::transaction(function () {
  2. DB::table('users')->update(['votes' => 1]);
  3. DB::table('posts')->delete();
  4. }, 5);

手动使用事务

如果你想要手动开始一个事务,并且对回滚和提交能够完全控制,那么你可以使用 DB Facade 的 beginTransaction 方法:

  1. DB::beginTransaction();

你可以使用 rollBack 方法回滚事务:

  1. DB::rollBack();

最后,你可以使用 commit 方法提交事务:

  1. DB::commit();

Tip:DB facade 的事务方法同样适用于 查询构造器Eloquent ORM

本文章首发在 LearnKu.com 网站上。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接 我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。