// 原生SQL
(SELECT)
$users = DB::select('select * from users where active = ?', [1]);
$results = DB::select('select * from users where id = :id', ['id' => 1]);
(INSERT)
DB::insert('insert into users (id, name) values (?, ?)', [1, '学院君']);
(UPDATE)
$affected = DB::update('update users set votes = 100 where name = ?', ['学院君']);
(DELETE)
$deleted = DB::delete('delete from users');
(运行一个通用语句)
有些数据库语句不返回任何值,比如新增表,修改表,删除表等,对于这种类型的操作,可以使用 DB 门面的 statement 方法
DB::statement('drop table users');
// 查询构造器
(从一张表中取出所有行)
$users = DB::table('users')->get(); // get 方法获取表中所有记录
(从一张表中获取一行/一列)
$user = DB::table('users')->where('name', 'John')->first(); // 返回单个 StdClass 对象
$email = DB::table('users')->where('name', 'John')->value('email'); // 返回指定列的值
(获取数据列值列表)
$titles = DB::table('roles')->pluck('title'); // 获取包含单个列值的数组
$roles = DB::table('roles')->pluck('title', 'name');
(组块结果集)
处理成千上百条数据库记录,可以考虑使用 chunk 方法,该方法一次获取结果集的一小块,然后传递每一小块数据到闭包函数进行处理,该方法在编写处理大量数据库记录的 Artisan 命令的时候非常有用
DB::table('users')->orderBy('id')->chunk(100, function($users) {
foreach ($users as $user) {
//
}
});
你可以通过从闭包函数中返回 false 来终止组块的运行
DB::table('users')->orderBy('id')->chunk(100, function($users) {
// 处理结果集...
return false;
});
(聚合函数)
count, max, min, avg 和 sum ...
$users = DB::table('users')->count();
$price = DB::table('orders')->max('price');
(SELECT)
* 指定查询子句
$users = DB::table('users')->select('name', 'email as user_email')->get();
$users = DB::table('users')->distinct()->get(); // distinct 方法允许你强制查询返回不重复的结果集
* Where子句
$users = DB::table('users')->where('votes', '=', 100)->get();
$users = DB::table('users')->where([
['status', '=', '1'],
['subscribed', '<>', '1'],
])->get();
$users = DB::table('users')
->whereBetween('votes', [1, 100])->get();
$users = DB::table('users')
->whereNotBetween('votes', [1, 100])
->get();
$users = DB::table('users')
->whereIn('id', [1, 2, 3])
->get();
$users = DB::table('users')
->whereNotIn('id', [1, 2, 3])
->get();
$users = DB::table('users')
->whereNull('updated_at')
->get();
$users = DB::table('users')
->whereNotNull('updated_at')
->get();
$users = DB::table('users')
->whereDate('created_at', '2016-10-10')
->get();
$users = DB::table('users')
->whereMonth('created_at', '10')
->get();
$users = DB::table('users')
->whereDay('created_at', '10')
->get();
$users = DB::table('users')
->whereYear('created_at', '2017')
->get();
$users = DB::table('users')
->whereColumn('first_name', 'last_name')
->get();
* or 语句
$users = DB::table('users')
->where('votes', '>', 100)
->orWhere('name', 'John')
->get();
* 排序、分组、限定
$users = DB::table('users')
->orderBy('name', 'desc')
->get();
$user = DB::table('users')
->latest()
->first(); // latest 和 oldest 方法允许你通过日期对结果进行排序,默认情况下,结果集根据 created_at 字段进行排序,或者,你可以按照你想要排序的字段作为字段名传入
$randomUser = DB::table('users')
->inRandomOrder()
->first(); // inRandomOrder 方法可用于对查询结果集进行随机排序,比如,你可以用该方法获取一个随机用户
$users = DB::table('users')
->groupBy('account_id')
->having('account_id', '>', 100)
->get();
$users = DB::table('users')->skip(10)->take(5)->get(); // 限定查询返回的结果集的数目,查询中跳过给定数目的结果
(INSERT)
DB::table('users')->insert(
['email' => 'john@example.com', 'votes' => 0]
);
DB::table('users')->insert([
['email' => 'taylor@example.com', 'votes' => 0],
['email' => 'dayle@example.com', 'votes' => 0]
]);
$id = DB::table('users')->insertGetId(
['email' => 'john@example.com', 'votes' => 0]
);
(UPDATE)
DB::table('users')
->where('id', 1)
->update(['votes' => 1]);
DB::table('users')->increment('votes');
DB::table('users')->increment('votes', 5); // 参数二为步长
DB::table('users')->decrement('votes');
DB::table('users')->decrement('votes', 5); // 参数二为步长
DB::table('users')->increment('votes', 1, ['name' => 'John']); // 在操作过程中你还可以指定额外的列进行更新
(DELETE)
DB::table('users')->delete();
DB::table('users')->where('votes', '>', 100)->delete();
DB::table('users')->truncate(); // 清除整张表,并将自增 ID 置为 0
(悲观锁 & 乐观锁)
* 悲观锁
DB::table('users')->where('votes', '>', 100)->sharedLock()->get();
DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get();
// Eloquent ORM
(获取单个模型/聚合结果)
$flight = App\Flight::find(1); // 通过主键获取模型...
$flights = App\Flight::find([1, 2, 3]);
$flight = App\Flight::where('active', 1)->first(); // 获取匹配查询条件的第一个模型...
$model = App\Flight::findOrFail(1); // 获取查询到的第一个结果,如果没有任何查询结果,异常将会被抛出
$count = App\Flight::where('active', 1)->count();
$max = App\Flight::where('active', 1)->max('price');
...
(插入/更新模型)
* 插入
$flight = new Flight;
$flight->name = $request->name;
$flight->save();
* 批量更新
App\Flight::where('active', 1)
->where('destination', 'San Diego')
->update(['delayed' => 1]);
* 批量复制
$flight = App\Flight::create(['name' => 'Flight 10']);
* 其他创建方法
firstOrNew 方法和 firstOrCreate 方法一样先尝试在数据库中查找匹配的记录,如果没有找到,则返回一个新的模型实例。需要注意的是,通过 firstOrNew 方法返回的模型实例并没有持久化到数据库中,你还需要调用 save 方法手动持久化
$flight = App\Flight::firstOrCreate(['name' => 'Flight 10']); // 通过属性获取航班, 如果不存在则创建...
$flight = App\Flight::firstOrNew(['name' => 'Flight 10']); // 通过属性获取航班, 如果不存在初始化一个新的实例...
$flight = App\Flight::updateOrCreate(
['departure' => 'Oakland', 'destination' => 'San Diego'],
['price' => 99]
); // 如果模型已存在则更新,否则创建新模型的场景, updateOrCreate 方法会持久化模型,所以无需调用 save()
(删除模型)
$flight = App\Flight::find(1);
$flight->delete();
* 通过主键删除模型
App\Flight::destroy(1);
App\Flight::destroy([1, 2, 3]);
App\Flight::destroy(1, 2, 3);
* 通过查询删除模型
$deletedRows = App\Flight::where('active', 0)->delete();
(软删除)
$table->softDeletes(); // 添加 deleted_at 列到数据表
if ($flight->trashed()) {
// 判断给定模型实例是否被软删除
}
* 查询被软删除的模型
// 包含软删除模型
$flights = App\Flight::withTrashed()
->where('account_id', 1)
->get();
$flight->history()->withTrashed()->get();
// 只获取软删除模型
$flights = App\Flight::onlyTrashed()
->where('airline_id', 1)
->get();
// 恢复软删除模型
$flight->restore();
App\Flight::withTrashed()
->where('airline_id', 1)
->restore();
$flight->history()->restore();
// 永久删除模型
$flight->forceDelete();
$flight->history()->forceDelete();
// 查询作用域
* 全局作用域
全局作用域可以提供一种方便的、简单的方式来确保给定模型的每个查询都有特定的条件约束。
// 编写全局作用域
自定义全局作用域很简单,首先定义一个实现 Illuminate\Database\Eloquent\Scope 接口的类,该接口要求你实现一个方法:apply。需要的话可以在 apply 方法中添加 where 条件到查询:
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class AgeScope implements Scope
{
/**
* 应用作用域到给定的Eloquent查询构建器.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
* @translator laravelacademy.org
*/
public function apply(Builder $builder, Model $model)
{
return $builder->where('age', '>', 200);
}
}
// 应用全局作用域
要将全局作用域应用到模型,需要重写给定模型的 boot 方法并使用 addGlobalScope 方法:
<?php
namespace App;
use App\Scopes\AgeScope;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* 模型的“启动”方法.
*
* @return void
*/
protected static function boot()
{
parent::boot();
static::addGlobalScope(new AgeScope);
}
}
*本地作用域
本地作用域允许我们定义通用的约束集合以便在应用中复用
// 创建本地作用域
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* 只包含活跃用户的查询作用域
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}
/**
* 只包含激活用户的查询作用域
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeActive($query)
{
return $query->where('active', 1);
}
}
// 使用本地作用域
$users = App\User::popular()->active()->orderBy('created_at')->get();
// 关联关系
$user->posts()->where('active', 1)->get();
* 关联方法 Vs. 动态属性
$user = App\User::find(1);
foreach ($user->posts as $post) {
//
}
* 查询存在的关联关系
$posts = App\Post::has('comments')->get(); // 获取所有至少有一条评论的文章...
$posts = Post::has('comments', '>=', 3)->get(); // 获取所有至少有三条评论的文章...
$posts = Post::has('comments.votes')->get(); // 获取所有至少有一条评论获得投票的文章...
$posts = Post::whereHas('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get(); // 获取所有至少有一条评论包含foo字样的文章
* 无关联结果查询
$posts = App\Post::doesntHave('comments')->get();
$posts = Post::whereDoesntHave('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
* 统计关联模型
$posts = App\Post::withCount('comments')->get();
foreach ($posts as $post) {
echo $post->comments_count;
}
* 渴求式加载
渴求式加载缓解 N+1 查询问题
$books = App\Book::with('author')->get();
foreach ($books as $book) {
echo $book->author->name;
}
$books = App\Book::with('author', 'publisher')->get(); // 渴求式加载多个关联关系
$books = App\Book::with('author.contacts')->get(); // 嵌套的渴求式加载
$users = App\Book::with('author:id,name')->get(); // 渴求式加载指定字段,使用这个特性时,id 字段是必须列出的。
$users = App\User::with(['posts' => function ($query) {
$query->where('title', 'like', '%first%');
}])->get(); // 带条件约束的渴求式加载
$books = App\Book::all(); // 懒惰渴求式加载
if ($someCondition) {
$books->load('author', 'publisher');
}
* 插入 & 更新关联模型
· save 方法
$comment = new App\Comment(['message' => 'A new comment.']);
$post = App\Post::find(1);
$post->comments()->save($comment);
$post = App\Post::find(1);
$post->comments()->saveMany([
new App\Comment(['message' => 'A new comment.']),
new App\Comment(['message' => 'Another comment.']),
]);
· create 方法
$post = App\Post::find(1);
$comment = $post->comments()->create([
'message' => 'A new comment.',
]);
$post = App\Post::find(1);
$post->comments()->createMany([
[
'message' => 'A new comment.',
],
[
'message' => 'Another new comment.',
],
]);
* 多对多关联
// 数据库迁移
(检查表/列是否存在)
if (Schema::hasTable('users')) {
//
}
if (Schema::hasColumn('users', 'email')) {
//
}
(重命名/删除表)
Schema::rename($from, $to); // 重命名
Schema::drop('users'); // 删除表
Schema::dropIfExists('users'); // 删除表
(修改数据列)
$table->string('name', 50)->change();
$table->renameColumn('from', 'to');
(删除数据列)
$table->dropColumn('votes');
$table->dropColumn(['votes', 'avatar', 'location']);
// 数据库事务
(DB门面)
想要在一个数据库事务中运行一连串操作,可以使用 DB 门面的 transaction 方法,使用 transaction 方法时不需要手动回滚或提交:如果事务闭包中抛出异常,事务将会自动回滚;如果闭包执行成功,事务将会自动提交
DB::transaction(function () {
DB::table('users')->update(['votes' => 1]);
DB::table('posts')->delete();
});
(手动使用事务)
如果你想要手动开启事务从而对回滚和提交有更好的控制,可以使用 DB 门面的 beginTransaction 方法
DB::beginTransaction();
DB::rollBack();
DB::commit();
(处理死锁)
数据库死锁指的是有两个或两个以上数据库操作相互依赖,一方需要等待另一方退出才能获取资源,但是没有一方提前退出,就会造成死锁,数据库事务容易造成的一个副作用就是死锁。为此 transaction 方法接收一个可选参数作为第二个参数,用于定义死锁发生时事务的最大重试次数。如果尝试次数超出指定值,会抛出异常
DB::transaction(function () {
DB::table('users')->update(['votes' => 1]);
DB::table('posts')->delete();
}, 5);