数据库操作 —— 使用进阶:通过查询构建器实现高级功能
<h3 id="toc_0">简介 数据库查询构建器提供了一个方便的流接口用于创建和执行数据库查询。查询构建器可以用于执行应用中绝大部分数据库操作,并且能够在 Laravel 支持的所有数据库系统上工作。
Laravel 查询构建器使用 PDO 参数绑定来避免 SQL 注入攻击,不再需要过滤以绑定方式传递的字符串。 从一张表中取出所有行 我们可以从?
UserController
= DB::table('users')-> view('user.index',['users' => }
你可以像访问对象的属性一样访问字段的值: ( -> }
从一张表中获取一行/一列 如果你只是想要从数据表中获取一行数据,可以使用? = DB::table('users')->where('name','John')-> ->name;
如果你不需要完整的一行,可以使用? = DB::table('users')->where('name','John')->value('email');
获取数据列值列表 如果想要获取包含单个列值的数组,可以使用? = DB::table('roles')->pluck('title'<span style="color: #0000ff">foreach (<span style="color: #800080">$titles <span style="color: #0000ff">as <span style="color: #800080">$title<span style="color: #000000">) {
<span style="color: #0000ff">echo <span style="color: #800080">$title<span style="color: #000000">; } 还可以在返回数组中为列值指定自定义键(该自定义键必须是该表的其它字段列名,否则会报错): = DB::table('roles')->pluck('title','name'<span style="color: #0000ff">foreach (<span style="color: #800080">$roles <span style="color: #0000ff">as <span style="color: #800080">$name => <span style="color: #800080">$title<span style="color: #000000">) {
<span style="color: #0000ff">echo <span style="color: #800080">$title<span style="color: #000000">; } 如果你需要处理成千上百条数据库记录,可以考虑使用? DB::table('users')->orderBy('id')->chunk(100,( (
你可以通过从闭包函数中返回? DB::table('users')->orderBy('id')->chunk(100,(
查询构建器还提供了多个聚合方法,如 = DB::table('users')-><span style="color: #800080">$price = DB::table('orders')-><span style="color: #008080">max('price');
当然,你可以联合其它查询子句和聚合函数来构建查询: = DB::table('orders'->where('finalized',1->avg('price');
指定查询子句 当然,我们并不总是想要获取数据表的所有列,使用? = DB::table('users')->select('name','email as user_email')->get();
= DB::table('users')->distinct()->get();
如果你已经有了一个查询构建器实例并且希望添加一个查询列到已存在的 select 子句,可以使用? = DB::table('users')->select('name' = ->addSelect('age')->get();
有时候你希望在查询中使用原生表达式,这些表达式将会以字符串的形式注入到查询中,所以要格外小心避免 SQL 注入。想要创建一个原生表达式,可以使用? = DB::table('users'->select(DB::raw('count(*) as user_count,status'->where('status','<>',1->groupBy('status'->get();
除了使用? selectRaw
= DB::table('orders'->selectRaw('price * ? as price_with_tax',[1.0825->get();
whereRaw / orWhereRaw
= DB::table('orders'->whereRaw('price > IF(state = "TX",?,100)',[200->get();
= DB::table('orders'->select('department',DB::raw('SUM(price) as total_sales'->groupBy('department'->havingRaw('SUM(price) > 2500'->get();
orderByRaw
= DB::table('orders'->orderByRaw('updated_at - created_at DESC'->get();
查询构建器还可以用于编写连接语句,关于 SQL 的几种连接类型,通过下图可以一目了然: 内连接(等值连接) 要实现一个简单的"内连接",你可以使用查询构建器实例上的? = DB::table('users'->('contacts','users.id','=','contacts.user_id'->('orders','orders.user_id'->select('users.*','contacts.phone','orders.price'->get();
左连接 如果你是想要执行“左连接”而不是“内连接”,可以使用? = DB::table('users'->leftJoin('posts','posts.user_id'->get();
交叉连接 要执行“交叉连接”可以使用? = DB::table('sizes'->crossJoin('colours'->get();
高级连接语句 你还可以指定更多的高级连接子句,传递一个闭包到? DB::table('users'->('contacts', (->on('users.id','contacts.user_id')->orOn(...->get();
如果你想要在连接中使用“where”风格的子句,可以在查询中使用? DB::table('users'->('contacts','contacts.user_id'->where('contacts.user_id','>',5->get();
查询构建器还提供了“联合”两个查询的快捷方式,比如,你可以先创建一个查询,然后使用? = DB::table('users'->whereNull('first_name'<span style="color: #800080">$users = DB::table('users'<span style="color: #000000">)
->whereNull('last_name'<span style="color: #000000">) ->union(<span style="color: #800080">$first<span style="color: #000000">) ->get();
使用查询构建器上的? 例如,下面是一个验证“votes”列的值是否等于 100 的查询: = DB::table('users')->where('votes',100)->get();
为了方便,如果你只是简单比较列值和给定数值是否相等,可以将数值直接作为 = DB::table('users')->where('votes',100)->get();
当然,你还可以使用其它操作符来编写? = DB::table('users'->where('votes','>=',100-><span style="color: #800080">$users = DB::table('users'<span style="color: #000000">)
->where('votes',100<span style="color: #000000">) -><span style="color: #000000">get(); <span style="color: #800080">$users = DB::table('users'<span style="color: #000000">) 还可以传递条件数组到? = DB::table('users')->'status','1'],'subscribed',->get();
你可以通过方法链将多个? = DB::table('users'->where('votes',100->orWhere('name','John'->get();
whereBetween
= DB::table('users'->whereBetween('votes',[1,100])->get();
whereNotBetween
= DB::table('users'->whereNotBetween('votes',100->get();
whereIn/whereNotIn
= DB::table('users'->whereIn('id',2,3->get();
= DB::table('users'->whereNotIn('id',3->get();
whereNull/whereNotNull
= DB::table('users'->whereNull('updated_at'->get();
= DB::table('users'->whereNotNull('updated_at'->get();
whereDate / whereMonth / whereDay / whereYear
= DB::table('users'->whereDate('created_at','2016-10-10'->get();
= DB::table('users'->whereMonth('created_at','10'->get();
= DB::table('users'->whereDay('created_at','10'->get();
= DB::table('users'->whereYear('created_at','2017'->get();
whereColumn
= DB::table('users'->whereColumn('first_name','last_name'->get();
还可以传递一个比较运算符到该方法: = DB::table('users'->whereColumn('updated_at','created_at'->get();
还可以传递多条件数组到? = DB::table('users'->'first_name','last_name'],'updated_at','created_at'->get();
有时候你需要创建更加高级的 where 子句,比如“where exists”或者嵌套的参数分组。Laravel 查询构建器也可以处理这些。作为开始,让我们看一个在括号中进行分组约束的例子: DB::table('users'->where('name','John'->orWhere( (->where('votes',100->where('title','Admin'->get();
正如你所看到的,传递闭包到? select * from users where name = 'John' or (votes > 100 and title <> 'Admin')
DB::table('users'->whereExists( (->select(DB::raw(1->from('orders'->whereRaw('orders.user_id = users.id'->get();
上述查询等价于下面的 SQL 语句: select *1 from orders where orders.user_id = users.
Laravel 还支持在提供 JSON 字段类型的数据库(目前是 MySQL 5.7 和 PostgresSQL)上使用操作符? = DB::table('users'->where('options->language','en'-><span style="color: #800080">$users = DB::table('users'<span style="color: #000000">)
->where('preferences->dining->meal','salad'<span style="color: #000000">) ->get(); orderBy
= DB::table('users'->orderBy('name','desc'->get();
latest / oldest
= DB::table('users'->->first();
inRandomOrder
= DB::table('users'->->first();
groupBy / having
= DB::table('users'->groupBy('account_id'->having('account_id',100->get();
关于? skip / take 想要限定查询返回的结果集的数目,或者在查询中跳过给定数目的结果,可以使用 = DB::table('users')->skip(10)->take(5)->get();
作为替代方法,还可以使用? = DB::table('users'->offset(10->limit(5->get();
有时候你可能想要某些条件为? = ->input('role'<span style="color: #800080">$users = DB::table('users'<span style="color: #000000">)
->when(<span style="color: #800080">$role,<span style="color: #0000ff">function (<span style="color: #800080">$query) <span style="color: #0000ff">use (<span style="color: #800080">$role<span style="color: #000000">) { <span style="color: #0000ff">return <span style="color: #800080">$query->where('role_id',<span style="color: #800080">$role<span style="color: #000000">); }) ->get();
你可以传递另一个闭包作为? = <span style="color: #800080">$users = DB::table('users'<span style="color: #000000">)
->when(<span style="color: #800080">$sortBy,<span style="color: #0000ff">function (<span style="color: #800080">$query) <span style="color: #0000ff">use (<span style="color: #800080">$sortBy<span style="color: #000000">) { <span style="color: #0000ff">return <span style="color: #800080">$query->orderBy(<span style="color: #800080">$sortBy<span style="color: #000000">); },<span style="color: #0000ff">function (<span style="color: #800080">$query<span style="color: #000000">) { <span style="color: #0000ff">return <span style="color: #800080">$query->orderBy('name'<span style="color: #000000">); }) ->get(); 查询构建器还提供了? DB::table('users')->'email' => 'john@example.com','votes' => 0
你甚至可以一次性通过传入多个数组来插入多条记录,每个数组代表要插入数据表的记录: DB::table('users')->'email' => 'taylor@example.com','votes' => 0],'email' => 'dayle@example.com','votes' => 0
自增ID 如果数据表有自增ID,使用? = DB::table('users')->'email' => 'john@example.com','votes' => 0
当然,除了插入记录到数据库,查询构建器还可以通过使用? DB::table('users'->where('id',1->update(['votes' => 1]);
更新 JSON 字段的时候,需要使用? DB::table('users'->where('id',1->update(['options->enabled' => ]);
查询构建器还为增减给定字段名对应数值提供方便。相较于编写? 这两个方法都至少接收一个参数:需要修改的列。第二个参数是可选的,用于控制列值增加/减少的数目。 DB::table('users')->increment('votes'DB::table('users')->increment('votes',5<span style="color: #000000">);
DB::table('users')->decrement('votes'<span style="color: #000000">); DB::table('users')->decrement('votes',5); 在操作过程中你还可以指定额外的列进行更新: DB::table('users')->increment('votes',1,['name' => 'John']);
当然,查询构建器还可以通过? DB::table('users')->DB::table('users')->where('votes',100)->delete();
如果你希望清除整张表,也就是删除所有列并将自增 ID 置为 0,可以使用? DB::table('users')->truncate();
悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁、表锁、读锁、写锁等,都是在做操作之前先上锁。 乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于? 下面我们看下悲观锁和乐观锁在 Laravel 中的使用: Laravel 查询构建器提供了一些方法帮助你在? DB::table('users')->where('votes',100)->sharedLock()->get();
上面这个查询等价于下面这条 SQL 语句: select * from `users` where `votes` > '100' lock in share mode
此外你还可以使用? DB::table('users')->where('votes',100)->lockForUpdate()->get();
上面这个查询等价于下面这条 SQL 语句: select * from `users` where `votes` > '100' update
这么说比较抽象,我们举个计数器的例子:在一条语句中读取一个值,然后在另一条语句中更新这个值。使用? 乐观锁,大多是基于数据版本 ( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。 读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。 两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行重试,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |