Laravel数据库事务:如何有效地实现和使用它们

Laravel数据库事务:如何有效地实现和使用它们

数据的准确性和一致性问题可能会导致从小的不便到大的企业关注。构建代码,安全地存储,更改和删除数据库中的数据是至关重要的。

进入Laravel数据库事务。

数据库事务是确保数据完整性的一个有效方法。Laravel简化了广泛的数据库的事务。

但它们到底是什么? 你怎么能在Laravel中解决它们?

在这个广泛的教程结束时, 你会了解到所有关于Laravel的数据库事务,以及如何在你的项目中有效地使用它们。

  1. 什么是Laravel数据库事务?
  2. Laravel数据库事务的选项
  3. 如何与你的Laravel数据库一起工作
  4. 在Laravel中使用原始数据库查询的另外5种方法

什么是Laravel数据库事务?

在我们进入技术层面之前, 让我们首先了解什么是Laravel数据库事务,以及你如何从它们中受益.

一个数据库事务是一组操作,你可以在你的应用程序的数据库结构中安全地进行,如修改数据的SQL查询(如更新,删除和插入)。

在任何时候,你都可以决定回滚所有事务的查询。此外,你所做的任何查询将被数据库视为一个单一的动作。

让我们看一下这个例子。

假设我们有一个让用户创建账户的应用。自然地,每个账户可以有一个或许多用户附属。如果这个应用程序同时生成一个账户和第一个用户,你就必须处理如果账户被正确生成,但用户没有被生成的情况。

请看一下这个示例代码:

// Create Account
$newAcct = Account::create([
'accountname' => Input::get('accountname'),
]);
// Create User
$newUser = User::create([
'username' => Input::get('username'),
'account_id' => $newAcct->id,
]);

这里有两种情况会导致不愉快的问题:

  1. 帐户没有生成
  2. 未能创建一个用户

让我们考虑后一种情况。

拥有一个没有可用用户的账户,会导致数据库中的数据不一致。为了解决这个问题,你可以通过艰巨的任务,围绕它进行编码,或者节省大量的代码,或者干脆用事务来包裹它,以快速完成工作。

虽然数据库事务存在于大多数SQL数据库中,但它们主要在实施和效率上有所不同。流行的系统如MySQL、SQLite、PostgreSQL和Oracle都支持事务,所以你在部署你喜欢的SQL数据库时不应该有困难。

迁移

迁移是Laravel的一个重要功能,它允许你在数据库中建立一个表,进行修改,并分享应用程序的数据库模式。你可以使用Laravel迁移来编辑表,添加新的列或删除现有的列。

假如你正在和一个团队讨论想法,需要对表进行调整。这个SQL文件必须由团队中的某个人分享和导入。他们有可能忘记导入SQL文件,导致应用程序的运行出现问题。

这就是Laravel迁移的用武之地。你可以在数据库中添加一个新的列,或者删除条目,而不影响已经存在的列。

数据填充器

数据填充是Laravel为开发者提供的一个工具,以方便测试不同的数据类型,修复错误,并调整性能。你可以通过数据库播种器在一个命令中自动添加多行假数据到你的数据库表中。

因此,你可以用一个新的数据库和样本值重新开始,而不是每次恢复数据库时都要手动输入。

Laravel数据库事务的选项

Laravel提供了不同的工具来管理你的数据,如Adminer。对于数据库交易, 在数据库端有三种方法可以手动启动交易并完全控制交易管理.

许多用户发现这些选项更灵活,可以准确地定义一个事务应该何时提交或回滚:

  • 创建一个事务:使用DB::beginTransaction(); 命令来启动一个事务。
  • 回滚一个事务:使用DB::rollBack(); 命令,如果你想进行修改或撤消操作。
  • 提交一个事务:如果一切按计划进行,使用DB::commit(); 命令。

一定要记住用提交或回滚动作来结束每个开放的事务,特别是循环。否则, 这个手动方法将失去同步性,你的记录将不会被更新。

如何使用你的Laravel数据库

迁移和播种机, 如前所述,是为Laravel开发人员设计的复杂的解决方案,通过减少差异,快速部署,删除和恢复一个应用程序的数据库。它是很方便的, 特别是当多个开发人员在同一个应用程序上工作时.

本节将向你展示如何使用artisan命令在你的Laravel数据库中轻松使用迁移和数据填充。

前提条件

以下是你需要开始使用的东西:

  1. 一个拥有sudo权限的非root用户在Ubuntu 18.04本地电脑或开发服务器上。如果你使用的是远程服务器,最好能设置一个有效的防火墙。
  2. 在你的机器上安装LEMP。你可以选择安装Docker和Docker Compose来运行你的应用程序,如果你觉得用它们工作更舒服的话。

还有其他的网络开发工具,你可以根据你的技能和编码需求来使用。

Laravel迁移

在迁移类中有两种方法:向上和向下。向上的方法是用来在你的数据库中创建新的表,索引,或列。向下的方法应该是撤销向上方法的效果。

你可以使用Laravel模式构建器在这些方法中自由构建和编辑表。例如, 这个迁移生成了一个航班表:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateFlightsTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up() {
Schema::create('flights', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('airline');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down() {
Schema::drop('flights');
}

请记住, make:migration 命令需要明确表的名称。所以要确保 table_name 与你想要的一致。

你可以使用 --table--create 选项来指定表的名称以及迁移是否会创建一个新的表,如下所示:

php artisan make:migration create_users_table --create=users
php artisan make:migration add_votes_to_users_table --table=users

你的database/migrations目录现在将包括新的迁移。每个迁移文件名都包括一个时间戳, Laravel用它来确定迁移的顺序.

你也可以选择定义一个 --path, 它应该与你的安装的根目录有关。使用下面的命令:

php artisan migrate:make foo --path=app/migrations

运行迁移

在运行迁移时,你可以利用一些有用的命令。让我们来看看其中的几个:

  • php artisan migrate:这个命令将你所有的模式发布到数据库中。它还会在数据库中生成一个表。
  • php artisan migrate --path=app/foo/migrations:这条命令在一个目录下运行所有的迁移程序。如果你收到错误信息 “Nothing to migrate”,请运行 php artisan migrate --path=database/migrations/foo 命令,去掉app目录。
  • php artisan migrate --package=vendor/package:如果你想为一个包运行迁移,请使用此命令。

有时你可能会在执行迁移的时候遇到 “Class not found” 的错误。如果你遇到这种情况,请运行 composer dump-autoload 命令。

有些迁移可能是危险的,可能会导致你的数据丢失。因此, Laravel会提示你确认执行命令以保护你的数据。

如果你不希望被提示,可以使用 --force flag 来强制执行命令,如下所示:

php artisan migrate --force

回滚迁移

当你需要逆转上一个迁移批次时,请使用回滚命令,如下所示:

php artisan migrate:rollback

这里还有一些你可以使用的回滚命令:

  • php artisan migrate:reset:这个命令可以回滚所有的迁移操作,而不仅仅是最后一次的操作。
  • php artisan migrate:fresh:当你想重新安装你的数据库时,使用这个命令。它将删除所有现有的表并执行 migration 命令。
  • php artisan migrate:refresh:这是一条二合一的命令,同时执行 :rollback and migrate 命令。
  • php artisan migrate:fresh --seed:这条命令在向数据库播种之前执行 migrate:fresh 命令。当你在一个新的主机上安装应用程序时,你可以利用这个命令来播种(即上传数据到)数据库。

Laravel数据填充

数据填充器是一个创建和放置数据样本(seeds)到数据库的类。Laravel提供了一个简单的技术,在database/seeds目录下使用seed类来填充你的数据库中的测试数据。

你可以自由选择你的seed类的名字. 但我们建议你遵循一个明确的命名模式,如UsersTableSeeder。之后,一个 DatabaseSeeder 类会默认为你创建。

下面是一个Laravel中的数据库seed类的例子:

class DatabaseSeeder extends Seeder {
public function run() {
$this->call('UserTableSeeder');
$this->command->info('User table seeded!');
}
}
class UserTableSeeder extends Seeder {
public function run() {
DB::table('users')->delete();
User::create(array('email' => 'foo@bar.com'));
}
}

创建数据填充器

产生数据填充器就像派一样简单。你可以闭着眼睛做这件事(但请不要这样做)。

执行 make:seeder artisan命令来创建一个数据填充器。现在database/seeds将包括所有由框架产生的数据填充器:

php artisan make:seeder UsersTableSeeder

数据填充器类的默认方法是运行。这个过程是在你应用 db:seed artisan命令时发生的。你可以使用运行函数以任何你喜欢的方式将数据放入你的数据库。此外,你完全可以使用Eloquent模型工厂或Query Builder来手动插入数据。

无论如何,你应该记住,在数据库填充期间,大规模分配保护会自动停用。

在这里,我们将对基本的 DatabaseSeeder 类进行修改,并在运行方法中添加一个数据库插入语句:

<?php
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
class DatabaseSeeder extends Seeder {
/**
* Run the database seeds.
*
* @return void
*/
public function run() {
DB::table('users')->insert([
'name' => Str::random(10),
'email' => Str::random(10).'@gmail.com',
'password' => Hash::make('password'),
]);
}
}

如果你想在运行方法的代码中输入提示任何依赖性,Laravel服务容器将自动解决它们。

此外, 你可以使用 call 函数从这个类中执行不同的seed类, 允许你自定义播种顺序. 你可以将你的数据库数据填充分割到不同的文件中, 确保没有一个seeder类会过度膨胀.

输入你要使用的seeder类的名称,如下图所示:

/**
* Run the database seeds.
*
* @return void
*/
public function run() {
$this->call([
UsersTableSeeder::class,
PostsTableSeeder::class,
CommentsTableSeeder::class,
]);
}

运行数据填充器

生成数据填充器后,你可能需要使用 dump-autoload 命令来重新创建Composer的自动加载器:

composer dump-autoload

接下来,你需要执行 db:seed artisan 命令,为你的数据库播种:

php artisan db:seed

这个命令通过代理来执行 DatabaseSeeder 类,它可以用来运行其他seed类。然而,你可以使用 --class 参数来单独执行一个特定的seed机类,如下所示:

php artisan db:seed --class=UserTableSeeder

如果你想从头开始重建你的数据库,包括删除所有的表并重新运行所有的迁移,该怎么办?在这种情况下,请使用 migrate:fresh 命令为你的数据库填充数据。

php artisan migrate:fresh --seed

与迁移的情况一样,一些播种过程可能会导致数据丢失或不必要的改变。出于这个原因,在执行数据填充器之前,会提示你批准,以保护你不在主数据库上执行数据填充命令。

如果你有足够的信心,并且不希望被这个安全步骤打断,可以使用下面的 --force 标志:

php artisan db:seed --force

在Laravel中使用原始数据库查询的另外5种方法

虽然Laravel提供了方便的工具,如Eloquent和Query Builder,你仍然可以使用SQL进行原始查询。我们总结了五种不同的方法来实现。

但是在你开始之前, 你应该知道原始查询并不是自动安全的, 这使得它们成为一种危险的方法. 因此,如果你要给查询提供任何参数,请确保它们是正确的格式,并且有正确的值,例如数字而不是文本。

平均值/总和/计数的计算

如果你想创建 GROUP BY() ,你可以使用原始查询,然后利用MySQL的聚合函数,如 Count()SUM()AVG()MIN()MAX() ,如下例所示:

$users = DB::table('users')
->selectRaw('count(*) as user_count, status')
->where('status', '<>', 1)
->groupBy('status')
->get();

甚至可以在同一个SQL查询中同时进行 count()avg()

$salaries = DB::table('salaries')
->selectRaw('companies.name as company_name, avg(salary) as avg_salary, count(*) as people_count')
->join('companies', 'salaries.company_id', '=', 'companies.id')
->groupBy('companies.id')
->orderByDesc('avg_salary')
->get();

筛选年份

如果你需要在 GROUP BYORDER BY 中进行SQL计算,你可以使用 groupByRaw()orderByRaw() 查询。分组后,你也可以通过使用 having 带有 havingRaw() 的SQL查询来利用 where 语句。

例如,下面这个命令显示了如何按年份对一个日期/时间字段进行分组:

$results = User::selectRaw('YEAR(birth_date) as year, COUNT(id) as amount')
->groupByRaw('YEAR(birth_date)')
->havingRaw('YEAR(birth_date) > 2000')
->orderByRaw('YEAR(birth_date)')
->get();

计算单个字段(子查询)

假设你想从另一列计算出一个列,并在SQL查询中返回结果。你怎样才能做到这一点呢?

让我们来看看:

$products = Product::select('id', 'name')
->selectRaw('price - discount_price AS discount')
->get();

下面是另一个SQL CASE 语句的例子:

$users = DB::table('users')
->select('name', 'surname')
->selectRaw("(CASE WHEN (gender = 1) THEN 'M' ELSE 'F' END) as gender_text")
->get();

转换旧的SQL

有一个SQL语句需要转换为Eloquent或Query Builder,这是一种常见的情况,特别是来自你所做的一个老项目。

那么,你真的不需要这么做。相反,你可以简单地使用 DB::select() 语句,如图所示:

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

执行没有结果的查询

DB::statement 可以运行一个SQL查询,得到没有变量的 INSERTUPDATE 等结果。

这在数据库迁移中经常使用,当一个表的结构发生变化,旧的数据必须用新的数据来改变:

DB::statement('UPDATE users SET role_id = 1 WHERE role_id IS NULL AND YEAR(created_at) > 2020');

此外, DB::statement() 可以运行任何带有模式的SQL查询,不限于数值或列。这里有一个例子:

DB::statement('DROP TABLE users');
DB::statement('ALTER TABLE projects AUTO_INCREMENT=123');

小结

到现在,你应该对Laravel中的数据库事务有了深刻的理解,以及如何实现它们。它们不仅有助于数据的完整性,而且还有助于优化Laravel的性能,使你的开发过程更容易。

评论留言