Blogger Information
Blog 91
fans 2
comment 4
visits 127760
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
thinkphp5数据库与模型
夏日的烈风的博客
Original
1484 people have browsed it

连接与查询构造器

数据库操作运行流程图.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、delete2.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();
           }
   * 通过配置属性值的方式,来完成写入数据的类型自动转换,比用修改器和读取器更加方便。
       如果数据处理逻辑不复杂,推荐使用这种方式来替代传统的读取器和修改器方法。



作者:阿泽453
链接:https://www.jianshu.com/p/2ea160353d3c
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。


Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post