自己做的網(wǎng)站怎么放視頻教程怎么建立自己的網(wǎng)站平臺
前言
先交代下背景,在一個(gè)項(xiàng)目中,有一個(gè)數(shù)據(jù)表有水平分表的需求。當(dāng)時(shí)想找到一種方法,把對數(shù)據(jù)庫的操作,寫到一個(gè)模型里,通過去換模型屬性中的table來達(dá)到代碼不變操作的數(shù)據(jù)表變化的效果。
我們都知道,模型要想關(guān)聯(lián)數(shù)據(jù)表的話,有兩中方式,第一種就是將模型名和數(shù)據(jù)表一致。這樣模型就會(huì)默認(rèn)關(guān)聯(lián)到名字對應(yīng)的數(shù)據(jù)表。第二種就是定義模型的 protected $table 來指定表明。
添加鏈接描述
模型初始化
ThinkPHP5內(nèi)置了partition方法,可用于實(shí)現(xiàn)簡單的分表。新增,修改,刪除,查詢單條數(shù)據(jù)時(shí),用parition方法都可以輕松搞定,因?yàn)檫@些操作有一個(gè)共同的特點(diǎn),就是能事先明確的知道,我要操作的是哪一條記錄。但有一個(gè)需求,ThinkPHP5似乎沒有解決,比如當(dāng)一個(gè)大表,被拆分成若干個(gè)子表時(shí),如何根據(jù)相關(guān)條件及排序獲取分頁數(shù)據(jù)。這種需求場景下,由于事先并不知道哪些數(shù)據(jù)會(huì)出現(xiàn)在第一頁,哪些數(shù)據(jù)會(huì)出現(xiàn)在第二頁,這些根據(jù)檢索條件動(dòng)態(tài)匹配的列表數(shù)據(jù),該如何查詢呢?
模型層
<?php
namespace app\common\model;
use think\Model;
class WalletLog extends Model
{protected $table = 'tb_walletlog';protected $pk = 'walletid';private function getRule(){return ['type' => 'mod', // 分表方式'num' => 3 // 分表數(shù)量];}public function saveData($data, $user_id){return $this->partition(['user_id' => $user_id], "user_id", $this->getRule())->insert($data);}public function getAll($where, $field = "*", $user_id){return $this->partition(['user_id' => $user_id], "user_id", $this->getRule())->where($where)->field($field)->select();}//查詢所有分割表public function getAll2(){return $this->partition('', '', $this->getRule())->select();}
}
分庫分表查詢分表與其他表關(guān)聯(lián)查詢 join 不好使用(各種sql 報(bào)錯(cuò))估計(jì)不支持
解決方案:
插入使用分表操作,進(jìn)行分割數(shù)據(jù),查詢使用普通聯(lián)合/聚合查詢
1、模型層調(diào)整 查詢
namespace application\workflow\model;
use think\Model;
class Init_Model extends Model
{protected $pk = 'id';//初始化表名public function __construct($name = ''){if (!empty($name)) {$this->name = $name;}}
}
使用時(shí):$model = new init_model(‘test’); //成功改變了數(shù)據(jù)表
$model->get(); //操作時(shí)二次走_(dá)_construct成空白,還原成沒有表名;
請問有內(nèi)置方法動(dòng)態(tài)改變表名嗎,對于動(dòng)態(tài)管理的東東很須要這個(gè)功能呀
前人栽樹,后人挖坑,哎
2、 執(zhí)行sql 查詢(拼接表名稱來實(shí)現(xiàn)查詢)
select count(1) as total from .$tables['countSql']
3、Db模型函數(shù)查詢
注意:不要使用任何 SQL 語句中會(huì)出現(xiàn)的關(guān)鍵字當(dāng)表名、字段名,例如 order 等。會(huì)導(dǎo)致數(shù)據(jù)模型拼裝 SQL 語句語法錯(cuò)誤。
thinkphp5 看云文檔 partition 方法用于是數(shù)據(jù)庫水平分表
partition 方法用法如下:
// 用于寫入
$data = ['user_id' => 110,'user_name' => 'think'
];$rule = ['type' => 'mod', // 分表方式'num' => 10 // 分表數(shù)量
];
Db::name('log')->partition(['user_id' => 110], "user_id", $rule)->insert($data);// 用于查詢
Db::name('log')->partition(['user_id' => 110], "user_id", $rule)->where(['user_id' => 110])->select();
4、閉包用法:
每個(gè)union方法相當(dāng)于一個(gè)獨(dú)立的SELECT語句。MySQL通過創(chuàng)建并填充臨時(shí)表的方式來執(zhí)行union查詢。除非確實(shí)要消除重復(fù)的行,否則建議使用union all。原因在于如果沒有all這個(gè)關(guān)鍵詞,MySQL會(huì)給臨時(shí)表加上distinct選項(xiàng),這會(huì)導(dǎo)致對整個(gè)臨時(shí)表的數(shù)據(jù)做唯一性校驗(yàn),這樣做的消耗相當(dāng)高。
Db::field('name')->table('think_user_0')->union('SELECT name FROM think_user_1')->union('SELECT name FROM think_user_2')->select();
//或者下面這種用法
Db::field('name')->table('think_user_0')->union(['SELECT name FROM think_user_1','SELECT name FROM think_user_2'])->select();
//支持UNION ALL 操作,例如:
Db::field('name')->table('think_user_0')->union(['SELECT name FROM think_user_1','SELECT name FROM think_user_2'],true)->select();
其他案例
應(yīng)用ThinkPHP內(nèi)置的分表算法處理百萬級用戶數(shù)據(jù).(適合流水類記錄表)
數(shù)據(jù)表:house_member_0house_member_1house_member_2house_member_3模型中//class MemberModel extends AdvModel {protected $partition = array('field'=>'username','type'=>'id','num'=>'4');public function getDao($data=array()) {$data = empty($data) ? $_POST : $data;$table = $this->getPartitionTableName($data);return $this->table($table);}}方法中class MemberAction extends BaseAction {public function login() {if($this->isPost()) {$this->validToken();$dao = D('Member')->getDao();$res = $dao->where('username = '.$_POST['username'])->find();// output 為自定義方法// $isAjax - bool$this->output(false);}$this->display();}}/**+----------------------------------------------------------* 得到分表的的數(shù)據(jù)表名+----------------------------------------------------------* @access public+----------------------------------------------------------* @param array $data 操作的數(shù)據(jù)+----------------------------------------------------------* @return string+----------------------------------------------------------*/public function getPartitionTableName($data=array()) {// 對數(shù)據(jù)表進(jìn)行分區(qū)if(isset($data[$this->partition['field']])) {$field = $data[$this->partition['field']];switch($this->partition['type']) {case 'id':// 按照id范圍分表$step = $this->partition['expr'];$seq = floor($field / $step)+1;break;case 'year':// 按照年份分表if(!is_numeric($field)) {$field = strtotime($field);}$seq = date('Y',$field)-$this->partition['expr']+1;break;case 'mod':// 按照id的模數(shù)分表$seq = ($field % $this->partition['num'])+1;break;case 'md5':// 按照md5的序列分表$seq = (ord(substr(md5($field),0,1)) % $this->partition['num'])+1;break;default :if(function_exists($this->partition['type'])) {// 支持指定函數(shù)哈希$fun = $this->partition['type'];$seq = (ord(substr($fun($field),0,1)) % $this->partition['num'])+1;}else{// 按照字段的首字母的值分表$seq = (ord($field{0}) % $this->partition['num'])+1;}}return $this->getTableName().'_'.$seq;}else{// 當(dāng)設(shè)置的分表字段不在查詢條件或者數(shù)據(jù)中//進(jìn)行聯(lián)合查詢,必須設(shè)定 partition['num']$tableName = array();for($i=0;$i<$this->partition['num'];$i++)$tableName[] = 'SELECT * FROM '.$this->getTableName().'_'.$i;$tableName = '( '.implode(" UNION ",$tableName).') AS '.$this->name;return $tableName;}}
溫馨提示:
其中 partition 方法指定要查詢的分表,where 方法則是查詢條件。
需要注意的是,分表可能會(huì)給應(yīng)用帶來更高的維護(hù)成本和查詢復(fù)雜度,需要在實(shí)際開發(fā)中根據(jù)業(yè)務(wù)需要進(jìn)行選擇
復(fù)雜模型實(shí)現(xiàn)不了的業(yè)務(wù)邏輯只能用原生sql 來實(shí)現(xiàn)。(團(tuán)隊(duì)封裝的模型基本夠用,大數(shù)據(jù)項(xiàng)目也不會(huì)用輕量級框架)有更好的分表查詢方法可以歡迎留言。用到那、學(xué)到哪!!!
其他文檔
ThinkPHP中的分表使用