TP6中數據庫操作
要使用Db類必須使用門面方式(think\facade\Db)調用
use think\facade\Db;
一、數據庫連接配置
配置文件位於,config/database.php
或者開發環境 位於根目錄下的 .env 文件
APP_DEBUG = true [APP] DEFAULT_TIMEZONE = Asia/Shanghai [DATABASE] TYPE = mysql //數據庫類型 HOSTNAME = 127.0.0.1 //連接地址 DATABASE = test //數據庫名稱 USERNAME = username //數據庫用戶名 PASSWORD = password //數據庫密碼 HOSTPORT = 3306 //端口 CHARSET = utf8 //字符集 DEBUG = true //是否開啟debug [LANG] default_lang = zh-cn
動態配置數據庫連接查詢
\think\facade\Db::connect('demo')->table('user')->find();
數據模型中定義connection屬性
protected $connection = 'demo';
ThinkPHP的數據庫連接是惰性的,只有實際的數據操作的時候才會去連接數據庫。
二、數據庫分布式支持
如果需要支持分布式數據庫,包括讀寫分離,需要設置配置參數 deploy 的值為 1
// 啟用分布式數據庫 'deploy' => 1, 'hostname' => '192.168.1.1,192.168.1.2', //默認情況下第一個地址就是主服務器 // 數據庫用戶名 'username' => 'root,slave,slave', // 數據庫密碼 'password' => '123456',
關於 hostname,username,password,hostport,database,dsn,charset 要么值相同就配置一個,不然就分別設置
建議使用數組定義參數,例如:
'hostname' =>[ '192.168.1.1','192.168.1.2','192.168.1.3'], 'password' => ['123456','abc,def','hello']
三、數據庫支持讀寫分離
開啟讀寫分類配置:
'rw_separate' => true,
默認第一個是主數據庫,負責寫入數據。如果設置 master_num ,則可以支持多個主服務器寫入。
如果用原生SQL,寫操作必須用 execute 方法,讀操作必須用 query方法
剛寫入數據之后,從庫數據還沒來得及同步完成,你可以使用 master() 進行主庫查詢
Db::name('user')->master(true)->find(1);
也可以開啟:當我們對某個數據表進行了寫操作,那么當前請求的后續所有對該表的查詢都會使用主庫讀取
'read_master' => true,
四、鏈式操作
查詢單個數據
Db::table('think_user')->where('id', 1)->find();
查詢為空返回空數組
Db::table('think_user')->where('id', 1)->findOrEmpty();
說明:
如果沒有任何的查詢條件,也沒有調用order方法的話 ,find查詢不會返回任何結果。
查詢結果集:
Db::table('think_user')->where('status', 1)->select();
select 方法查詢結果是一個數據集對象,如果需要轉換為數組可以使用
Db::table('think_user')->where('status', 1)->select()->toArray();
查詢一個字段
Db::table('think_user')->where('id', 1)->value('name');
查詢一列
// 返回數組 Db::table('think_user')->where('status',1)->column('name'); // 指定id字段的值作為索引 Db::table('think_user')->where('status',1)->column('name', 'id');
添加數據:
$data = ['foo' => 'bar', 'bar' => 'foo']; Db::name('user')->save($data); 或 Db::name('user')->insert($data);
使用save方法時,數據中有ID則為更新,沒有ID則為新增
insert 方法添加數據成功返回添加成功的條數,通常情況返回 1
如果不希望因為存在數據表中沒有的字段而拋出異常,可以使用以下方法
Db::name('user')->strict(false)->insert($data);
添加后返回主鍵
$userId = Db::name('user')->strict(false)->insertGetId($data);
更新數據:
Db::name('user')->save(['id' => 1, 'name' => 'thinkphp']);
或
Db::name('user')->where('id', 1)->update(['name' => 'thinkphp']);
支持表達式更新
Db::name('user')->where('id',1)->exp('name','UPPER(name)')->update(); 或使用raw Db::name('user')->where('id', 1)->update([ 'name' => Db::raw('UPPER(name)'), 'score' => Db::raw('score-3'), 'read_time' => Db::raw('read_time+1') ]);
自增自減
// score 字段加 1 Db::table('think_user')->where('id', 1)->inc('score')->update(); // score 字段加 5 Db::table('think_user')->where('id', 1)->inc('score', 5)->update(); // score 字段減 1 Db::table('think_user')->where('id', 1)->dec('score')->update(); // score 字段減 5 Db::table('think_user')->where('id', 1)->dec('score', 5)->update();
刪除數據:
// 根據主鍵刪除 Db::table('think_user')->delete(1); Db::table('think_user')->delete([1,2,3]); // 條件刪除 Db::table('think_user')->where('id',1)->delete(); Db::table('think_user')->where('id','<',10)->delete();
沒有任何條件調用delete會返回錯誤。如果確實需要刪除所有數據,可以使用
// 無條件刪除所有數據 Db::name('user')->delete(true);
查詢表達式:
格式如下:
where('字段名','查詢表達式','查詢條件');
// = 等於 Db::name('user')->where('id','=',100)->select(); //<> 不等於 Db::name('user')->where('id','<>',100)->select(); //> 大於 Db::name('user')->where('id','>',100)->select(); //>= 大於等於 Db::name('user')->where('id','>=',100)->select(); //< 小於 Db::name('user')->where('id', '<', 100)->select(); <= 小於等於 Db::name('user')->where('id', '<=', 100)->select(); //[NOT] LIKE 模糊查詢 Db::name('user')->where('name', 'like', 'thinkphp%')->select(); //[NOT] BETWEEN (不在)區間查詢 Db::name('user')->where('id','between','1,8')->select(); //[NOT] IN (不在)IN 查詢 Db::name('user')->where('id','in','1,5,8')->select(); 或 Db::name('user')->where('id','in',[1,5,8])->select(); //[NOT] NULL : Db::name('user')->where('name', null)->where('email','null') ->where('name','not null')->select();
鏈式操作示例:
Db::table('think_user') ->where('status',1) ->order('create_time') ->limit(10) ->select();
鏈式where條件:
//1、表達式條件 Db::table('think_user')->where('id','>',1)->where('name','thinkphp')->select(); //2、數組條件 Db::table('think_user')->where(['name'=>'thinkphp','status'=>1])->select(); //3、字符串條件 Db::table('think_user')->whereRaw('type=1 AND status=1')->select(); 或需要傳入變量,配合預處理機制,確保更加安全 Db::table('think_user') ->whereRaw("id=:id and username=:name", ['id' => 1 , 'name' => 'thinkphp']) ->select();
鏈式table操作
Db::field('user.name,role.title') ->table([ 'think_user'=>'user', 'think_role'=>'role' ]) ->limit(10)->select();
鏈式alias操作,設置表的別名
Db::table('think_user') ->alias('a') ->join('think_dept b ','b.user_id= a.id') ->select();
field操作
Db::table('user')->field('id,title,content')->select(); 或使用別名 Db::table('user')->field('id,nickname as name')->select(); 或使用SQL函數 Db::table('user')->fieldRaw('id,SUM(score)')->select();
strict操作
提交了非法字段會拋出異常,可以在配置中關閉嚴格字段檢查
'fields_strict' => false,
也可以臨時關閉
// 關閉字段嚴格檢查 Db::name('user')->strict(false)->insert($data);
limit操作
//獲取滿足要求的10個用戶 Db::table('user')->where('status',1)->field('id,name')->limit(10)->select(); //limit方法也可以用於寫操作,例如更新滿足要求的3條數據: Db::table('user')->where('score',100)->limit(3)->update(['level'=>'A']); //分頁查詢,查詢從第20行開始的10條數據 Db::table('article')->limit(20,10)->select();
page操作
// 查詢第一頁數據 Db::table('article')->page(1,10)->select(); // 查詢第二頁數據 Db::table('article')->page(2,10)->select();
order操作
//沒有指定排序規則,默認 asc Db::table('user')->where('status', 1)->order('id')->select(); //指定排序規則 Db::table('user')->where('status', 1)->order('id', 'desc')->select();
group操作
通常用於結合合計函數,根據一個或多個列對結果集進行分組。
Db::table('user')->field('user_id,username,max(score)') ->group('user_id')->select(); 對多個字段進行分組 Db::table('user')->field('user_id,test_time,username,max(score)') ->group('user_id,test_time')->select();
having操作
Db::table('score') ->field('username,max(score)')->group('user_id') ->having('count(test_time)>3')->select();
join操作
INNER JOIN: 等同於 JOIN(默認的JOIN類型),如果表中有至少一個匹配,則返回行 LEFT JOIN: 即使右表中沒有匹配,也從左表返回所有的行 RIGHT JOIN: 即使左表中沒有匹配,也從右表返回所有的行 FULL JOIN: 只要其中一個表中存在匹配,就返回行
//join 方式 Db::table('think_artist') ->alias('a') ->join('work w','a.id = w.artist_id') ->join('card c','a.card_id = c.id') ->select(); //left join 方式 Db::table('think_user') ->alias('a') ->leftJoin('word w','a.id = w.artist_id') ->select();
五、聚合查詢
count:Db::table('think_user')->count(); max:Db::table('think_user')->max('score'); min:Db::table('think_user')->min('score'); avg: Db::table('think_user')->avg('score'); sum: Db::table('think_user')->sum('score');
六、分頁查詢
控制器代碼:
// 查詢狀態為1的用戶數據 並且每頁顯示10條數據 $list = Db::name('user')->where('status',1)->order('id', 'desc')->paginate(10); // 獲取分頁顯示 $page = $list->render(); return view('index', ['list' => $list, 'page' => $page]);
HTML代碼:
<div> <ul> {volist name='list' id='user'} <li> {$user.nickname}</li> {/volist} </ul> </div> {$page|raw}
獲取總數據
// 獲取總記錄數 $count = $list->total();
分頁后數據處理
$list = Db::name('user')->where('status',1)->order('id', 'desc') ->paginate()->each(function($item, $key){ $item['nickname'] = 'think'; return $item; });
模型中分頁數據處理,無需return
$list = User::where('status',1)->order('id', 'desc')->paginate()->each(function($item, $key){ $item->nickname = 'think'; });
分頁參數:
$list = Db::name('user')->where('status',1)->paginate([ 'list_rows'=> 20, 'query' => $data ]);
七、時間查詢 whereTime
// 大於某個時間 Db::name('user')->whereTime('birthday', '>=', '1970-10-1')->select(); // 小於某個時間 Db::name('user')->whereTime('birthday', '<', '2000-10-1')->select(); // 時間區間查詢 Db::name('user')->whereTime('birthday', 'between', ['1970-10-1', '2000-10-1']) ->select(); // 不在某個時間區間 Db::name('user')->whereTime('birthday', 'not between', ['1970-10-1', '2000-10-1']) ->select();
八、原生查詢
V6.0.3+版本開始,原生查詢僅支持Db類操作
query方法
Db::query("select * from think_user where status=:id", ['id' => 1]); //從主庫讀取 Db::query("select * from think_user where status=:id", ['id' => 1], true);
execute方法
Db::execute("update think_user set name='thinkphp' where status=1");
參數綁定
//問號占位符綁定 Db::query("select * from think_user where id=? AND status=?", [8, 1]); // 命名綁定 Db::execute("update think_user set name=:name where status=:status", ['name' => 'thinkphp', 'status' => 1]); //注意不支持對表名使用參數綁定
九:事務操作
使用事務處理的話,需要數據庫引擎支持事務處理。比如 MySQL 的 MyISAM 不支持事務處理,需要使用 InnoDB 引擎。
最簡單的事務閉包操作:
Db::transaction(function () { Db::table('think_user')->find(1); Db::table('think_user')->delete(1); });
手動運行事務:
// 啟動事務 Db::startTrans(); try { Db::table('think_user')->find(1); Db::table('think_user')->delete(1); // 提交事務 Db::commit(); } catch (\Exception $e) { // 回滾事務 Db::rollback(); }
十:存儲過程
//數據訪問層調用存儲過程 $resultSet = Db::query('call procedure_name'); foreach ($resultSet as $result) { } //存儲過程可以支持輸入和輸出參數,以及進行參數綁定操作。 $resultSet = Db::query('call procedure_name(:in_param1,:in_param2,:out_param)', [ 'in_param1' => $param1, 'in_param2' => [$param2, PDO::PARAM_INT], 'out_param' => [$outParam, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 4000], ]);
數據集:
// 獲取數據集 $users = Db::name('user')->select(); // 直接操作第一個元素 $item = $users[0]; // 獲取數據集記錄數 $count = count($users); // 遍歷數據集 foreach($users as $user){ echo $user['name']; echo $user['id']; }
判斷數據集是否為空,不能直接使用empty判斷,而必須使用數據集對象的isEmpty方法判斷,
$users = Db::name('user')->select(); if($users->isEmpty()){ echo '數據集為空'; }