laravel - 查询构造器

获取数据

1,从数据表中获取所有行

<?php

class UserController extends Controller{

       public function index(){

                  $users = DB::table('users')->get();

      }

}

从数据表中获取一行数据你可以使用 first() 方法。该方法返回一个stdclass对象

$user = DB::table("users")->where(“name”,"John")->first()

如果不需要正行数据,则可以使用 value() 方法从记录中获取单个值。该方法直接返回该字段得值:

$email = DB::table('users')->where("name","John")->value("email");

获取一列得值,则可以使用 pluck() 方法。在下面得例子中,我们将获取角色表中得标题得集合

$titles = DB::table("roles")->pluck("title");

foreach($titles as $title){

       echo $title;  

}

你还可以在返回得集合中指定字段得自定义键值:

$roles = DB::table("roles")->pluck("title","name")

foreach($roles as $name=>$title){

            echo $title;

}

2,分块结果

如果你需要处理上千条数据库记录。你可以考虑使用 chunk 方法。该方法一次获取结果集得一小块,并将其传递给 闭包 函数进行处理。该方法在 Artisan命令 编写数千条处理数据得时候非常有用。力图我们可以将全部表数据切割成一次处理100条记录得一小块:

DB::table("users)->orderBy("id")->chunk(100,function($users){

          foreach($users as $user){

          }

})

你可以通过在 闭包 中返回 false 来终止继续获取分块结果:

DB::table('users')->orderBy('id')->chunk(100,function(){

        return false;

})

聚合

查询构造器还提供了各种聚合方法,比如count 、max 、min 、 avg 还有 sum。 你可以在构造查询后调用任何方法:

$user = DB:table("users")->count():

$price = DB::table('orders')->max("price");

当然,你也可以将这些聚合方法和其他得查询语句结合:

$price = DB::table('orders')->where("finalized",1)->avg('price');

3,判断记录是否存在

除了count 方法可以确定查询条件得结果是否存在之外,还可以使用existsdoesntExist方法:

return DB::table('orders')->where("finalized",1)->exists();

return DB::table("orders")->where('finalized',1)->doesntExist();

selects 语句

指定一个select语句

当然你可能并不总是希望从数据表中获取所有列。使用 select  方法,你可以自定义一个 select 查询语句来查询指定的字段:

$users = DB::table('users')->select("name","emal as user_email ")->get();

distinct 方法会强制让查询返回得结果不重复:

$users = DB::table('users')->distinct()->get();

如果你已经有了一个查询构造器实例,并且希望在现有得查询语句中加入一个字段,那么你可以使用addSelect方法

$query = DB::table('users')->select('name');

$users = $query->addSelect('age')->get();

4,原生表达式

有时候你可能需要在查询中使用原生表达式。你可以使用DB:raw创建一个原生表达式:

$users = DB::table('users')

              ->select(DB::raw(‘count(*) as user_count , status ’))

              ->where('status' , '<>' , 1)

               ->groupBy("status")

               ->get();

注:原生表达式将会被当做字符串注入到查询中,因此你应该小心使用,避免创建SQL注入得漏洞

原生方法

可以使用以下方法代替 DB::raw  ,将原生表达式插入查询得各个部分。

selectRow 方法可以代替 select(DB::raw(...))。该方法得第二个参数是可选项,值是一个绑定参数得数组:

$order = DB::table('orders')

               ->selectRaw('price * ? as price_with_tax ' , [1.0825])

               ->get();

whereRaw/orWhereRaw

whereRaw 和 orWhereRaw 方法将原生得where

注入到你得查询中。这两个方法得第二个参数还是可选项,值还是绑定参数得数组:

$orders = DB::table('orders')

                ->whereRaw(' price > IF(state = "TX" , ? , 100) ' , [200] )

                ->get();

内连接(等值连接) json方法,json方法得第一个参数是你需要连接到得表名,剩余得其他参数则是为连接指定得列约束

$order = Orders::select("order_goods.order_id","user_name","order_sn","goods_name")
->join("users","ecs_users.user_id","=","order_info.user_id")
->join("order_goods","order_info.order_id","=","order_goods.order_id")
->get();
左连接 leftJoin方法,用法和join一样
$order_user = Orders::select("order_sn","user_name")
->leftJoin("users","users.user_id","=","order_info.user_id")
->get();

交叉连接 crossJoin 方法,传递你想要交叉连接得表名到该方法即可。交叉连接在第一张表和被连接表之间生成一个笛卡尔积:
$cross_list = Orders::crossJoin("ecs_users")->get();
高级连接语句 
你还可以指定更多得高级连接子句,传递一个闭包到join
where子句 可以添加where子句到查询中,调用where最基本得方式需要传递三个参数,第一个参数是列名,第二个参数是任意一个数据库支持得操作符,,
第三个参数是该列要比较得值
$user = Users::where("is_status",">=","2")
->get()->toArray();

为了方便,如果只是简单比较列值和给定数值是否相等,可以将数值直接作为where方法得第二个参数
$user = Users::where("is_status","2")
->get()->toArray();
还可以传递条件数组到where函数
$user = Users::where([["is_status",">=",2],["is_forten",">" ,0]])->get()->toArray();
or语句
你可以通过方法链将多个约束连接到一起,也可以添加or子句到查询,orwhere方法和where方法接收参数一样:
$user = Users::select('user_name',"is_status")->where("is_status",1)
->orWhere("is_status",2)
->orderBy("user_id"," desc")
->get()->toArray();
更多的where子句
whereBetween 方法验证列值是否在给定值之间
$user = Users::select('user_name',"is_status")
->whereBetween("is_status",[1,2])
->get()->toArray();
whereNotBetween 方法验证列值不在给定值之间
$user = Users::select('user_name',"is_status")
->whereNotBetween("is_status",[1,2])
->get()->toArray();
whereIn/whereNotIn
whereIn 方法验证给定列的值是否在给定数组中
$user = Users::select('user_name',"is_status")
->whereIn("is_status",[1,2])
->get()->toArray();
whereNotIn 方法验证给定列的值不在给定数组中
$user = Users::select('user_name',"is_status")
->whereNotIn("is_status",[1,2])
->get()->toArray();
whereNUll/whereNotNull
whereNull 方法验证给定列的值为Null
$user = Users::select('user_name',"is_status")
->whereNull("is_forten")
->get()->toArray();
whereNotNUll 方法验证给定列的值不是NUll
$user = Users::select('user_name',"is_status","is_forten")
->whereNotNull("is_forten")
->get()->toArray();
whereDate/whereMonth/WhereDay/whereYear/WhereTime
whereDate 方法用于比较字段值和日期
$user = Users::select('user_name',"is_status","is_forten")
->whereDate("last_time","2019-09-10")
->get()->toArray();
whereMonth 方法用于比较字段值和一年中的指定月份
$user = Users::select('user_name',"is_status","is_forten")
->whereMonth("last_time","9")
->get()->toArray();
whereDay 方法用于比较字段和一月中的指定日期
$user = Users::select('user_name','last_time')
->whereDay("last_time","24")
->get()->toArray();
whereYear 方法用于比较字段值和一月中的指定日期
$user = Users::select('user_name','last_time')
->whereYear("last_time","2017")
->get()->toArray();
whereTime 方法用于比较字段值和指定时间
$user = Users::select('user_name','last_time')
->whereTime("last_time","=","10:24")
->get()->toArray();
whereColumn 方法用于验证两个字段是否相等
$user = Users::select('user_name','last_time')
->whereColumn("user_money","frozen_money")
->get()->toArray();
whereColumn还可以传递一个比较运算符到该方法:
$user = Users::select('user_name','last_time')
->whereColumn("reg_time",">=","last_login")
->get()->toArray();
还可以传递多条件数组到whereColumn 方法,这些条件通过 and 操作符进行链接:
$user = Users::select('user_name','last_time')
->whereColumn([["reg_time",">=","last_login"],
["user_money","=","frozen_money"]
])
->get()->toArray();
参数分组
例:括号中进行分组约束
$user = Users::select('user_name','last_time')
->where("is_status",">","0")
->orWhere(function($query){
$query->where("is_forten",">","0")
->whereColumn( [
["user_money","=","frozen_money"]
]);
})
->get()->toArray();
注:无论何时都需要对orWhere调用进行分组以避免应用全局作用域时出现与预期不符的行为。
排序、分组、限定
orderBy 方法允许你通过给定字段对结果集进行排序,orderBy的第一个参数应该是你希望排序的字段,第二个参数控制着排序的方向
$user = Users::where("is_status",1)
->orderBy('user_id',"desc")->get();

latest/oldest 方法允许你通过日期对结果进行排序,默认情况下,结果集根据 传入自动进行排序
$user = Users::select("reg_time")
->where("is_status",1)
->latest('reg_time')
->first()->toArray();
inRandomOrder 方法可用于对查询结果集进行随机排序,比如,你可以用该方法获取一个随机用户:
$user = Users::select("user_name","reg_time")
->where("is_status",1)
->inRandomOrder()
->get()->toArray();
groupBy/having 方法可用于对查询结果集进行分组, having方法和where方法的用法类似,having后面的二次筛选的参数必须是分组字段或聚合数据
$user = Users::select(user_id,"user_name","reg_time")
->groupBy("is_status")
->having("is_status",">",0)
->get()->toArray();

skip/take
想要限定查询返回的结果集数目,或者在查询中跳过指定数目的结果,可以使用skip和take方法
例 跳过10条 取5条
$user = Users::select("user_name","reg_time")
->where("is_status",">",0)
->skip(10)->take(5)
->get()->toArray();
作为替代方法,还可以使用limit和offset方法:
$user = Users::select("user_name","reg_time")
->where("is_status",">",0)
->offset(10)
->limit(5)
->get()->toArray();
条件子句
有时候你可能想要某些条件为true时才将条件子句应用到查询。

$sortBy = "reg_time";
$user = Users::select("user_name","reg_time")->when($sortBy,function($query) use ($sortBy){
return $query->orderBy($sortBy);
},function($query){
return $query->orderBy("user_name");
})->get()->toArray();
插入(Inert)
insert方法用于插入记录到数据表,insert方法接收数组形式的字段名和字段值进行插入操作:
Users::insert(['email' => 'john@example.com', 'votes' => 0]);
你也可以一次性传入多个数组来插入多条记录,每个数组代表要插入数据表的记录
Users::insert([
['email' => 'taylor@example.com', 'votes' => 0],
['email' => 'dayle@example.com', 'votes' => 0]
]);
自增ID
如果数据表有自增ID,使用insertGetID方法来插入记录并返回ID值:
更新
update方法和insert方法一样,接收字段名和字段值的键值对数组,对应字段名和字段值的键值对数组
Users::where("user_id",3623)->update(['email'=>'test@qq.com']);
更新JSON字段

更新json字段的时候,需要使用->语法访问json对象上相应的值,该操作只能用于支持json字段类型的数据库:
Test::where('id',1)->update(['option->option'=>'修改']);

增加/减少(存在减少到负值的坑。。。。)
increment/decrement 这两个方法都至少接收一个参数,需要修改的列。第二个参数是可选的,用于控制列值增加/减少的数目
Test::increment("vote");
Test::increment("vote",8);
 Test::decrement('vote');
Test::decrement("vote",5);
 在操作过程中你还可以制定额外的列进行更新
删除(delete)
DB::table('users')->delete();

DB::table('users')->where('votes', '>', 100)->delete();
如果你希望清除整张表,也就是删除所有列并将自增ID置为0,可以使用truncate 方法
DB::table('users')->truncate();
悲观锁&乐观锁
悲观锁:顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,
这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里面用到了很多这种机制,比如行锁、表锁、读锁、写锁等,都是在做操作之前先上锁

乐观锁,顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,
可以使用版本号等机制实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition 机制的其实都是提供的乐观锁

悲观锁使用
laravel查询构建起提供了一些方法帮助你在select语句中实现悲观锁。可以在查询中使用sharedLock方法从而在运行语句时带有一把‘共享锁’。
共享锁可以避免被选择的行被修改直到事务提交:
$test = Test::where("vote","<" , 0)->sharedLock()->get()->toArray();
上面的查询等价于下面这条SQL语句:
select * from test vote>0 lock in share mode

此外你可以使用lockForUpdate方法。 for update 锁避免选择行被其它共享锁修改或删除:
$test = Test::where("vote","<" , 0)->lockForUpdate()->get()->toArray();
上面这个查询等价于下面这条SQl语句
select * from test where vote <0 for update

for update 与 lock in share mode 都是用于确保被选中的记录值不能被其他事务更新(上锁),两者的区别在于
lock in share mode 不会阻塞其它事务读取被锁定行记录的值,而for update 会阻塞其它锁定性读对锁定行的读取
(非锁定性读仍然可以不读取这些记录,lock in share mode 和for update 都是锁定读)

举例说明:在一条语句中读取一个值,然后在另一条语句中更新这个值。使用lock in share mode 的话可以允许两个事务读取相同的初始化值,
所以执行两个事务之后最终计数器的值+1:而如果使用for update 的话,会锁定第二个事务对记录值的读取直到第一个事务执行完成,这样计数器的最终结果就是+2了

乐观锁使用
乐观锁,大多是基于数据版本记录机制实现。所谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个‘version’
字段来实现

总结

两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行重试,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。



注:数据转化  

       把数据转为数组  toArray()

       把数据转为json   toJson()

 https://xueyuanjun.com/post/9577.html

posted @ 2019-09-25 08:47  尚真  阅读(3030)  评论(0编辑  收藏  举报