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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM