thinkphp5學(xué)習(xí)筆記(五)數(shù)據(jù)庫與模型

連接與查詢構(gòu)造器

數(shù)據(jù)庫操作運(yùn)行流程圖.png
1.數(shù)據(jù)庫操作運(yùn)行流程圖
    * ThinkPHP5的數(shù)據(jù)庫操作對底層進(jìn)行優(yōu)化設(shè)計(jì),對各種操作進(jìn)行高級封裝,
      既可以直接使用連接器進(jìn)行高效的原生查詢,也可以使用封裝好的查詢構(gòu)造器進(jìn)行
      只管便捷的查詢。

數(shù)據(jù)庫連接配置

1.配置方法:
    * 靜態(tài)連接:應(yīng)用/模塊中的數(shù)據(jù)庫配置文件database.php
    * 動態(tài)連接:入口類Db.php中的connect(參數(shù)[數(shù)組或字符串])方法
    * 靜態(tài)配置重要參數(shù)
        -> debug True   數(shù)據(jù)庫調(diào)試模式
    * 動態(tài)配置連接字符串
        -> mysql://root:1234@localhost:3306/thinkphp#utf8
        -> 數(shù)據(jù)庫://用戶名:密碼@數(shù)據(jù)庫地址:數(shù)據(jù)庫端口/數(shù)據(jù)庫名#字符集
    * 動態(tài)配置數(shù)組方式
        eg: public function demo()
            {
                $config = [
                    'type'=>'mysql',
                    'hostname'=>'localhost',
                    'username'=>'root',
                    'password'=>'root',
                    'database'=>'tp5',
                ];
                //1.獲取數(shù)據(jù)庫的連接實(shí)例/對象
                $link = Db::connect($config);
                //2.用連接實(shí)例調(diào)用查詢類的查詢方法
                $res = $link->table('staff')->select();
                //3.輸出查詢結(jié)果
                dump($res);
                //Db::table('staff')->select();
            }
    2.數(shù)據(jù)庫的第一步就是數(shù)據(jù)庫的鏈接,TP5提供了強(qiáng)大靈活的連接方式,
      特別是惰性連接支持,極大的提高了連接效率(db()助手函數(shù)不支持),
      使用戶的關(guān)注重點(diǎn)放在業(yè)務(wù)邏輯上,不必?fù)?dān)心連接問題。

數(shù)據(jù)庫原生查詢

1.原生查詢的實(shí)現(xiàn)
    * Connection類
        ->query(sql語句字符串,[參數(shù)綁定]):讀操作    select
        ->execute(sql語句字符串,[參數(shù)綁定]):寫操作  insert、update、delete
2.thinkphp > library > think > db > Connection.php

    * 查詢操作:
        ->普通操作
        eg: $sql = "select * from staff salary > 4000";
            $result = Db::query($sql);
            dump($result);
        ->參數(shù)綁定查詢,可以防止sql注入
        eg: $sql = "select * from staff where salary > ?";
            $result = Db::query($sql,[4000]);
            dump($result);
        ->命名占位符綁定(推薦使用)
        eg: $sql = "select * from staff where salary > :salary";
            $result = Db::query($sql,['salary'=>4000]);
            dump($result);
    * 其他操作
        -> 更新操作
            eg: $sql = "update staff set salary = salary+1000 where id=:id";
                $res = Db::execute($sql,['id'=>1004]);
                dump($res);
        ->插入操作
            eg: $sql = "insert into staff (name,sex,age) values(:name,:sex,:age)";
                $res = Db::execute($sql,['name'=>'thinkphp5','name'=>'1','age'=>10]);
                dump($res);
        ->刪除操作
            eg: $sql = "delete from staff where id=:id";
                $res = Db::execute($sq,['id'=>10]);
                dump($res);
    * Connection類實(shí)例通過入口類Db靜態(tài)自動調(diào)用,不用顯示寫出
    * 利用查詢構(gòu)造器進(jìn)行增刪改查操作,最終仍是調(diào)用連接類Connection對應(yīng)方法完成。

查詢構(gòu)造器

1.查詢構(gòu)造器的原理:

查詢構(gòu)造器工作原理圖 .png

 thinkphp > library > think > db > Query.php Builder.php 查詢類和生成類

2.什么是鏈?zhǔn)讲僮鳎繛槭裁匆面準(zhǔn)讲僮鳎?/strong>

鏈?zhǔn)讲僮鞯墓ぷ髟韴D.png

3.數(shù)據(jù)表的查詢條件是如何生成的?

查詢條件生成原理圖.png

    * 兩種方法
        where():AND條件
        whereOr():OR條件
    * 三種格式
        where('字段名','表達(dá)式','查詢條件')   //默認(rèn)省略表達(dá)式就是相等
        where(['字段名'=>['表達(dá)式','查詢條件'], ....])
        where(function($query){ //鏈?zhǔn)讲樵冋Z句;閉包查詢  })
    eg:三種格式的例子
        Db::table("staff")
        ->field('name')
        ->where('salary','>',3000)
        ->select();

        Db::table("staff")
        ->field('name')
        ->where(['id'=>['>',1003],'salary'=>['>',3000],])
        ->select();

        $salary = 3000;
        Db::table("staff")
        ->field('name')
        ->where(function($query) use ($salary){
            $query->where('id','>',1003)
            ->where('salary','>',$salary)
        })
        ->select();
        Db::select(
            function($query){
                $query->table('staff')
                ->field(['name'=>'姓名','salary'=>'工資'])
                ->where(['id'=>['>',1003],'salary'=>['>',4000],]);
            })
        );
4.如何用查詢構(gòu)造器實(shí)現(xiàn)數(shù)據(jù)表的增刪改查(CURD)操作?
    * 新增
        ->  insert(['字段'=>'值'])
        ->  insertAll(['二維數(shù)組'])
    * 更新
        ->  update(['字段'=>'值'])
        ->  setInc/setDec('字段',步長,[秒數(shù)])
    * 讀取
        ->  find(主鍵)
        ->  select(主鍵)
    * 刪除
        ->  delete(主鍵)
        ->  delete(true)
5.查詢
    eg:
        //value('字段','默認(rèn)值')  column('字段','字段')
        dump(Db::table('staff')->where('id','1020)->value('name'));
        dump(Db::table('staff')->where('id','>','1020)->column('name'));
6.推薦使用閉包,來生成查詢條件,不僅功能強(qiáng)大,而且便于擴(kuò)展

模型

1.模型是對實(shí)體的抽象模式,快速直觀的展示出實(shí)體的特征
2.tp5中的模型是指什么
    <?php
        namespace app\index\model;
        use Think\Model;
        class Staff extends Model
        {
            //
        }
3.模型類中的屬性和方法
    * 模型類的屬性和方法需要在基類Model中查看
    * Model.php類位于thinkphp/library/think/Model.php
    * 該類是一個(gè)抽象類,不能實(shí)例化,必須有子類繼承并實(shí)現(xiàn)內(nèi)部的全部抽象方法

模型與數(shù)據(jù)表的對應(yīng)關(guān)系

模型與數(shù)據(jù)表的對應(yīng)關(guān)系.png
2.模型與數(shù)據(jù)表的區(qū)別與聯(lián)系
    * 區(qū)別:
        ->  分工不同     Db類負(fù)責(zé)數(shù)據(jù)表的訪問,模型專注于業(yè)務(wù)邏輯處理
        ->  返回值不同   Db訪問返回?cái)?shù)組,模型操作返回對象
    * 聯(lián)系
        ->  模型最終仍須調(diào)用Db類完成數(shù)據(jù)表的查詢操作
3.如何創(chuàng)建模型
    * 手工創(chuàng)建:在應(yīng)用或模塊下創(chuàng)建目錄model,并在該目錄下創(chuàng)建與數(shù)據(jù)表同名的類文件
        如:User.php對應(yīng)user.dbf表
    * 命令創(chuàng)建:在當(dāng)前項(xiàng)目目錄下,用命令:php think make:model 模塊名/模型名,會
        自動創(chuàng)建指定位置和命名空間的空模型,并自動與數(shù)據(jù)表綁定
        eg: php think make:model test/Blog
    * 模型創(chuàng)建完成后,會自動獲取當(dāng)前數(shù)據(jù)表名稱$table,表中所有字段信息$field,主鍵$pk
        和數(shù)據(jù)庫配置信息$connection . 同時(shí)會自動繼承基類Model中所有屬性和方法,protected
        類型在本模型中使用,public類型還可以在控制器使用,靜態(tài)方法大多直接在控制器,進(jìn)行
        CURD操作
4.在控制器中調(diào)用模型
    * 實(shí)例化調(diào)用
        -> 用new生成模型對象
        -> 用模型對象處理相關(guān)業(yè)務(wù)
    * 靜態(tài)調(diào)用
       -> 通過靜態(tài)查詢直接將一個(gè)空模型轉(zhuǎn)為數(shù)據(jù)模型
       -> 在調(diào)用相關(guān)方法完成增刪改查操作
    * 不推薦使用助手函數(shù)model()和添加模型類后綴
eg:
    <?php
        namespace app\index\controller;
        use app\index\model\Staff;
        class Index
        {
            public function index()
            {
                //實(shí)例化創(chuàng)建模型對象
                $staff = new Staff();
                $res = $staff->where('id',1004)->find();
                dump($res);
                dump($res->getData());
                //靜態(tài)創(chuàng)建模型對象
                dump(Staff::get(1004)->getData('name'));
            }
        }
6.模型數(shù)據(jù)訪問方式
    * 控制器訪問(外部)     用模型對象:$model
    * 模型訪問(內(nèi)部)       用偽對象變量:$this

模型CURD操作

1.通過模型,create創(chuàng)建數(shù)據(jù)
    * save($data[])         單條添加        調(diào)用方式:實(shí)例化    返回值:影響記錄數(shù)
    * saveAll($data[])      批量添加        調(diào)用方式:實(shí)例化    返回值:模型對象數(shù)組
    * create($data[])       單條添加        調(diào)用方式:靜態(tài)      返回值:模型對象

    * 數(shù)據(jù)創(chuàng)建過程可以出發(fā)很多操作,非Db類操作可比
    * 靜態(tài)調(diào)用的實(shí)質(zhì)其實(shí)仍是實(shí)例化調(diào)用,只是將CURD方法進(jìn)行靜態(tài)封裝
    * saveAll()方法實(shí)際上是通過多次執(zhí)行insert語句完成,很少用到
    * 理論上講,通過模型向表中添加數(shù)據(jù),盡可能都采用靜態(tài)方式
    eg:
        引入 use app\index\model\Staff;
        //方法中,實(shí)例化模型
        $staff = new Staff();
        $staff->name = 'test';
        $staff->sex = 1;
        $staff->save();

        //批量添加
        $data = [
            ['name'=>'test','sex'=>1],
            ['name'=>'test1','sex'=>0],
            ['name'=>'test2','sex'=>1],
        ];
        $res = $staff->saveAll($data);  //返回的是對象數(shù)組

        //靜態(tài)添加
        $res = Staff::create([['name'=>'test4','sex'=>1],]);
        dump($res->getData());
2.通過模型update更新數(shù)據(jù)
    * save($data=[],$where=[])              單條更新    實(shí)例化調(diào)用   返回值:影響記錄數(shù)
    * saveAll($data=[],true)                批量更新    實(shí)例化調(diào)用   返回值:模型對象數(shù)組
    * update($data=[],$where=[],$field=[])  單條更新    靜態(tài)調(diào)用     返回值:模型對象

    * 不允許無條件更新,必須設(shè)置更新條件
    * 可以將更新條件,如主鍵寫在更新數(shù)據(jù)中,方法可以自動識別
    * 更新條件可以使用閉包,完成更復(fù)雜的業(yè)務(wù)邏輯
    eg:
        $staff = new Staff();
        $data = [
            //'id'=>1032,
            'name'=>'張三豐',
            'age'=>100
        ];
        $where = ['id'=>1032];
        //$staff->isUpdate(true)->save($data);
        $staff->save($data,$where);
        dump($staff->getData());

        $staff = new Staff();
        $data = [
            ['id'=>1032,'name'=>'張三豐', 'age'=>100],
            ['id'=>1033,'name'=>'張三豐1', 'age'=>101],
            ['id'=>1034,'name'=>'張三豐2', 'age'=>102],
        ];
        $staff->isUpdate(true)->saveAll($data);
        dump($staff->getData());

        //update(更新數(shù)據(jù),更新條件,允許更新的字段)
        $data = ['name'=>'張三豐2', 'age'=>102,'salary'=>5000];
        //$where = ['id'=>1034];
        $where = function($query){  //閉包 好處是支持外部傳入變量
            $query->where('id',1034);
        };
        $field = ['name','age'];
        $res = Staff::update($data,$where,$field);
        dump($res);
3.通過模型查詢表中數(shù)據(jù)
    * ORM模型(對象關(guān)系映射)
        -> ThinkPHP5實(shí)現(xiàn)了基于ActiveRecords模式的ORM模型
模型與數(shù)據(jù)表的對應(yīng)關(guān)系.png
    * Read讀取操作
        ->  find($where)和get($where)    調(diào)用方式:實(shí)例化/靜態(tài)    返回值:模型對象
        ->  select($where)和all($where)  調(diào)用方式:實(shí)例化/靜態(tài)    返回值:模型對象數(shù)組

        -> 原則來說,查詢都應(yīng)該采用靜態(tài)查詢方法
        -> 盡可能采用get()和all()方法代替find()和select()
        -> 牢記一條原則:一個(gè)模型對象實(shí)例應(yīng)該唯一對應(yīng)數(shù)據(jù)表的一條記錄
        eg:
            $staff = new Staff();
            $where = function($query){
                $query->field(['name','age'])
                ->where('salary','>',8000);
            };
            $res = $staff->select($where);
            dump($res);

            $res = Staff::find($where);
            $res = Staff::get($where);
            $res = Staff::all($where);
4.通過模型delete刪除表中記錄
    * delete()              調(diào)用方式:實(shí)例化    返回值:受影響記錄數(shù)量
    * destory(條件/閉包)    調(diào)用方式:靜態(tài) 返回值:受影響記錄數(shù)量

    * delete()方法不要傳任何參數(shù),它只刪除當(dāng)前模型對象對應(yīng)的記錄
    * destory()中的刪除條件,推薦采用閉包方式
    * 推薦用軟刪除替代該方法,即用更新方式來實(shí)現(xiàn)刪除操作
    eg:
        $res = Staff::get(['id'=>['>',1000]]);
        $affected = $res->delete();             //不能有參數(shù),只刪除一條

        $where = function($query){
            $query->where('id','>',1030)
            ->where('age','>',40)
            ->whereOr('salary','>',40000);
        };
        $value = Staff::all($where);
        $res = Staff::destroy($where);

模型高級操作

1.模型讀取器
    * 觸發(fā)條件:當(dāng)用模型對象讀取表中字段值的字段
    * 應(yīng)用場景:日期時(shí)間字段,集合或枚舉數(shù)據(jù)數(shù)字狀態(tài)與文本轉(zhuǎn)換字段拼裝
    * 設(shè)置位置:在模型中設(shè)置,訪問屬性通常為protected,不允許外部直接訪問
    * 方法名稱:get屬性名稱Attr($name,$data=[])

    //FieldName  命名規(guī)則,駝峰命名法,對應(yīng)表中字段 field_name
    get FieldNameAttr($name,$data[])  //data 是表中所有的數(shù)據(jù)

    eg:
        //控制器中調(diào)用
        $staff = Staff::get(1033);
        return '入職時(shí)間:'.$staff->hiredate;
        //模型中
        protected function getHireDateAttr($hiredate)
        {
            return date('Y-m-d',$hiredate);
        }
2.模型的讀取器工作原理圖
    * 模型記錄元素?cái)?shù)據(jù)保存在$data屬性中,可用getData()方法獲?。?staff->getData('字段');
模型的讀取器工作原理圖.png
3.模型的修改器
    * 觸發(fā)條件:當(dāng)用模型對象想數(shù)據(jù)表中新增記錄或更新字段值的時(shí)候
    * 應(yīng)用場景:日期時(shí)間字段,集合或枚舉數(shù)據(jù),數(shù)字狀態(tài)與文本轉(zhuǎn)換,字段拼裝
    * 設(shè)置位置:在模型中設(shè)置,訪問屬性通常為protected,不允許外部直接訪問
    * 方法名稱:set 屬性名稱Attr($name,$data=[])

    set FieldNameAttr($name)  //FieldName 對應(yīng)表中字段:field_name
    eg:
        控制器中:
        $staff->hiredate = '2017-12-20';
        $staff->save();
        模型中:
        protected function setHireDateAttr($hiredate)
        {
            return strtotime($hiredate);
        }
4.模型的修改器工作原理圖
模型的修改器工作原理圖.png
5.模型的獲取器與修改器,是模型中最常用的自定義方法,配合驗(yàn)證器,可以
    讓用戶更安全的讀寫數(shù)據(jù)表中的數(shù)據(jù)

模型類型轉(zhuǎn)換

1.類型轉(zhuǎn)換
    protected $type = [
        'name'=>'array',        //以json格式寫入,取出自動解碼為array
        'age'=>'integer',       //該字段寫入和輸出的時(shí)候都會自動轉(zhuǎn)換為整型
        'salary'=>'float',      //該字段寫入和輸出的時(shí)候都會自動轉(zhuǎn)換為浮點(diǎn)型
        'dept'=>'serialize',    //自動序列寫入,讀取的時(shí)候自動反序列化
        'home'=>'json',         //json_enocde寫入,讀取時(shí)json_decode處理
        'hiredate'=>'timestamp',//用strtotime轉(zhuǎn)為時(shí)間戳寫入,讀出按$dateFormat格式輸出
        //'hiredate'=>'timestamp:Y/m/d',
        'birthday'=>'datetime'  //讀寫時(shí)都按$dateFormat格式處理
    ];
    eg:模型中
        class Staff extends Model
        {
             protected $type = [
                'name'=>'array',
                'age'=>'integer',
                'salary'=>'float',
                'hiredate'=>'timestamp'
            ];
        }
        //控制器中
            public function index()
            {
                $staff = Staff::get(1023);
                $staff->name = '張無忌';
                $staff->age = '100';
                $staff->salary = '6000.23';
                $staff->hiredate = '2017-12-20';
                $staff->isUpdate(true)->save();
                //轉(zhuǎn)換數(shù)據(jù)
                $staff = Staff::get(1033);
                dump($staff->name);
                dump($staff->age);
                dump($staff->salary);
                dump($staff->hiredate);
                //查看原始數(shù)據(jù)
                $staff->getData();
            }
    * 通過配置屬性值的方式,來完成寫入數(shù)據(jù)的類型自動轉(zhuǎn)換,比用修改器和讀取器更加方便。
        如果數(shù)據(jù)處理邏輯不復(fù)雜,推薦使用這種方式來替代傳統(tǒng)的讀取器和修改器方法。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容