美文网首页
thinkphp5学习笔记(五)数据库与模型

thinkphp5学习笔记(五)数据库与模型

作者: 阿泽453 | 来源:发表于2017-12-20 15:52 被阅读0次

    连接与查询构造器

    数据库操作运行流程图.png
    1.数据库操作运行流程图
        * ThinkPHP5的数据库操作对底层进行优化设计,对各种操作进行高级封装,
          既可以直接使用连接器进行高效的原生查询,也可以使用封装好的查询构造器进行
          只管便捷的查询。
    

    数据库连接配置

    1.配置方法:
        * 静态连接:应用/模块中的数据库配置文件database.php
        * 动态连接:入口类Db.php中的connect(参数[数组或字符串])方法
        * 静态配置重要参数
            -> debug True   数据库调试模式
        * 动态配置连接字符串
            -> mysql://root:1234@localhost:3306/thinkphp#utf8
            -> 数据库://用户名:密码@数据库地址:数据库端口/数据库名#字符集
        * 动态配置数组方式
            eg: public function demo()
                {
                    $config = [
                        'type'=>'mysql',
                        'hostname'=>'localhost',
                        'username'=>'root',
                        'password'=>'root',
                        'database'=>'tp5',
                    ];
                    //1.获取数据库的连接实例/对象
                    $link = Db::connect($config);
                    //2.用连接实例调用查询类的查询方法
                    $res = $link->table('staff')->select();
                    //3.输出查询结果
                    dump($res);
                    //Db::table('staff')->select();
                }
        2.数据库的第一步就是数据库的链接,TP5提供了强大灵活的连接方式,
          特别是惰性连接支持,极大的提高了连接效率(db()助手函数不支持),
          使用户的关注重点放在业务逻辑上,不必担心连接问题。
    

    数据库原生查询

    1.原生查询的实现
        * Connection类
            ->query(sql语句字符串,[参数绑定]):读操作    select
            ->execute(sql语句字符串,[参数绑定]):写操作  insert、update、delete
    2.thinkphp > library > think > db > Connection.php
    
        * 查询操作:
            ->普通操作
            eg: $sql = "select * from staff salary > 4000";
                $result = Db::query($sql);
                dump($result);
            ->参数绑定查询,可以防止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类实例通过入口类Db静态自动调用,不用显示写出
        * 利用查询构造器进行增删改查操作,最终仍是调用连接类Connection对应方法完成。
    

    查询构造器

    1.查询构造器的原理:

    查询构造器工作原理图 .png
     thinkphp > library > think > db > Query.php Builder.php 查询类和生成类
    

    2.什么是链式操作?为什么要用链式操作?

    链式操作的工作原理图.png

    3.数据表的查询条件是如何生成的?

    查询条件生成原理图.png
        * 两种方法
            where():AND条件
            whereOr():OR条件
        * 三种格式
            where('字段名','表达式','查询条件')   //默认省略表达式就是相等
            where(['字段名'=>['表达式','查询条件'], ....])
            where(function($query){ //链式查询语句;闭包查询  })
        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.如何用查询构造器实现数据表的增删改查(CURD)操作?
        * 新增
            ->  insert(['字段'=>'值'])
            ->  insertAll(['二维数组'])
        * 更新
            ->  update(['字段'=>'值'])
            ->  setInc/setDec('字段',步长,[秒数])
        * 读取
            ->  find(主键)
            ->  select(主键)
        * 删除
            ->  delete(主键)
            ->  delete(true)
    5.查询
        eg:
            //value('字段','默认值')  column('字段','字段')
            dump(Db::table('staff')->where('id','1020)->value('name'));
            dump(Db::table('staff')->where('id','>','1020)->column('name'));
    6.推荐使用闭包,来生成查询条件,不仅功能强大,而且便于扩展
    

    模型

    1.模型是对实体的抽象模式,快速直观的展示出实体的特征
    2.tp5中的模型是指什么
        <?php
            namespace app\index\model;
            use Think\Model;
            class Staff extends Model
            {
                //
            }
    3.模型类中的属性和方法
        * 模型类的属性和方法需要在基类Model中查看
        * Model.php类位于thinkphp/library/think/Model.php
        * 该类是一个抽象类,不能实例化,必须有子类继承并实现内部的全部抽象方法
    

    模型与数据表的对应关系

    模型与数据表的对应关系.png
    2.模型与数据表的区别与联系
        * 区别:
            ->  分工不同     Db类负责数据表的访问,模型专注于业务逻辑处理
            ->  返回值不同   Db访问返回数组,模型操作返回对象
        * 联系
            ->  模型最终仍须调用Db类完成数据表的查询操作
    3.如何创建模型
        * 手工创建:在应用或模块下创建目录model,并在该目录下创建与数据表同名的类文件
            如:User.php对应user.dbf表
        * 命令创建:在当前项目目录下,用命令:php think make:model 模块名/模型名,会
            自动创建指定位置和命名空间的空模型,并自动与数据表绑定
            eg: php think make:model test/Blog
        * 模型创建完成后,会自动获取当前数据表名称$table,表中所有字段信息$field,主键$pk
            和数据库配置信息$connection . 同时会自动继承基类Model中所有属性和方法,protected
            类型在本模型中使用,public类型还可以在控制器使用,静态方法大多直接在控制器,进行
            CURD操作
    4.在控制器中调用模型
        * 实例化调用
            -> 用new生成模型对象
            -> 用模型对象处理相关业务
        * 静态调用
           -> 通过静态查询直接将一个空模型转为数据模型
           -> 在调用相关方法完成增删改查操作
        * 不推荐使用助手函数model()和添加模型类后缀
    eg:
        <?php
            namespace app\index\controller;
            use app\index\model\Staff;
            class Index
            {
                public function index()
                {
                    //实例化创建模型对象
                    $staff = new Staff();
                    $res = $staff->where('id',1004)->find();
                    dump($res);
                    dump($res->getData());
                    //静态创建模型对象
                    dump(Staff::get(1004)->getData('name'));
                }
            }
    6.模型数据访问方式
        * 控制器访问(外部)     用模型对象:$model
        * 模型访问(内部)       用伪对象变量:$this
    

    模型CURD操作

    1.通过模型,create创建数据
        * save($data[])         单条添加        调用方式:实例化    返回值:影响记录数
        * saveAll($data[])      批量添加        调用方式:实例化    返回值:模型对象数组
        * create($data[])       单条添加        调用方式:静态      返回值:模型对象
    
        * 数据创建过程可以出发很多操作,非Db类操作可比
        * 静态调用的实质其实仍是实例化调用,只是将CURD方法进行静态封装
        * saveAll()方法实际上是通过多次执行insert语句完成,很少用到
        * 理论上讲,通过模型向表中添加数据,尽可能都采用静态方式
        eg:
            引入 use app\index\model\Staff;
            //方法中,实例化模型
            $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);  //返回的是对象数组
    
            //静态添加
            $res = Staff::create([['name'=>'test4','sex'=>1],]);
            dump($res->getData());
    2.通过模型update更新数据
        * save($data=[],$where=[])              单条更新    实例化调用   返回值:影响记录数
        * saveAll($data=[],true)                批量更新    实例化调用   返回值:模型对象数组
        * update($data=[],$where=[],$field=[])  单条更新    静态调用     返回值:模型对象
    
        * 不允许无条件更新,必须设置更新条件
        * 可以将更新条件,如主键写在更新数据中,方法可以自动识别
        * 更新条件可以使用闭包,完成更复杂的业务逻辑
        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(更新数据,更新条件,允许更新的字段)
            $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.通过模型查询表中数据
        * ORM模型(对象关系映射)
            -> ThinkPHP5实现了基于ActiveRecords模式的ORM模型
    
    模型与数据表的对应关系.png
        * Read读取操作
            ->  find($where)和get($where)    调用方式:实例化/静态    返回值:模型对象
            ->  select($where)和all($where)  调用方式:实例化/静态    返回值:模型对象数组
    
            -> 原则来说,查询都应该采用静态查询方法
            -> 尽可能采用get()和all()方法代替find()和select()
            -> 牢记一条原则:一个模型对象实例应该唯一对应数据表的一条记录
            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()              调用方式:实例化    返回值:受影响记录数量
        * destory(条件/闭包)    调用方式:静态 返回值:受影响记录数量
    
        * delete()方法不要传任何参数,它只删除当前模型对象对应的记录
        * destory()中的删除条件,推荐采用闭包方式
        * 推荐用软删除替代该方法,即用更新方式来实现删除操作
        eg:
            $res = Staff::get(['id'=>['>',1000]]);
            $affected = $res->delete();             //不能有参数,只删除一条
    
            $where = function($query){
                $query->where('id','>',1030)
                ->where('age','>',40)
                ->whereOr('salary','>',40000);
            };
            $value = Staff::all($where);
            $res = Staff::destroy($where);
    

    模型高级操作

    1.模型读取器
        * 触发条件:当用模型对象读取表中字段值的字段
        * 应用场景:日期时间字段,集合或枚举数据数字状态与文本转换字段拼装
        * 设置位置:在模型中设置,访问属性通常为protected,不允许外部直接访问
        * 方法名称:get属性名称Attr($name,$data=[])
    
        //FieldName  命名规则,驼峰命名法,对应表中字段 field_name
        get FieldNameAttr($name,$data[])  //data 是表中所有的数据
    
        eg:
            //控制器中调用
            $staff = Staff::get(1033);
            return '入职时间:'.$staff->hiredate;
            //模型中
            protected function getHireDateAttr($hiredate)
            {
                return date('Y-m-d',$hiredate);
            }
    2.模型的读取器工作原理图
        * 模型记录元素数据保存在$data属性中,可用getData()方法获取!$staff->getData('字段');
    
    模型的读取器工作原理图.png
    3.模型的修改器
        * 触发条件:当用模型对象想数据表中新增记录或更新字段值的时候
        * 应用场景:日期时间字段,集合或枚举数据,数字状态与文本转换,字段拼装
        * 设置位置:在模型中设置,访问属性通常为protected,不允许外部直接访问
        * 方法名称:set 属性名称Attr($name,$data=[])
    
        set FieldNameAttr($name)  //FieldName 对应表中字段:field_name
        eg:
            控制器中:
            $staff->hiredate = '2017-12-20';
            $staff->save();
            模型中:
            protected function setHireDateAttr($hiredate)
            {
                return strtotime($hiredate);
            }
    4.模型的修改器工作原理图
    
    模型的修改器工作原理图.png
    5.模型的获取器与修改器,是模型中最常用的自定义方法,配合验证器,可以
        让用户更安全的读写数据表中的数据
    

    模型类型转换

    1.类型转换
        protected $type = [
            'name'=>'array',        //以json格式写入,取出自动解码为array
            'age'=>'integer',       //该字段写入和输出的时候都会自动转换为整型
            'salary'=>'float',      //该字段写入和输出的时候都会自动转换为浮点型
            'dept'=>'serialize',    //自动序列写入,读取的时候自动反序列化
            'home'=>'json',         //json_enocde写入,读取时json_decode处理
            'hiredate'=>'timestamp',//用strtotime转为时间戳写入,读出按$dateFormat格式输出
            //'hiredate'=>'timestamp:Y/m/d',
            'birthday'=>'datetime'  //读写时都按$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();
                    //转换数据
                    $staff = Staff::get(1033);
                    dump($staff->name);
                    dump($staff->age);
                    dump($staff->salary);
                    dump($staff->hiredate);
                    //查看原始数据
                    $staff->getData();
                }
        * 通过配置属性值的方式,来完成写入数据的类型自动转换,比用修改器和读取器更加方便。
            如果数据处理逻辑不复杂,推荐使用这种方式来替代传统的读取器和修改器方法。

    相关文章

      网友评论

          本文标题:thinkphp5学习笔记(五)数据库与模型

          本文链接:https://www.haomeiwen.com/subject/umjgwxtx.html