连接数据库与模型初探

连接数据库

grade.sql

  1. ThinkPHP 采用内置抽象层将不同的数据库操作进行封装处理;
  2. 数据抽象层基于PDO模式,无须针对不同的数据库编写相应的代码;
  3. 使用数据库的第一步,就是连接你的数据库;
  4. 在根目录的config下的database.php可以设置数据库连接信息;
  5. 大部分系统已经给了默认值,你只需要修改和填写需要的值即可;
  6. 本地测试,会优先采用.env的配置信息,我们和database.php配置对应上即可;

QQ截图20200722111250.png

'type' => Env::get('database.type', 'mysql'),
'hostname' => Env::get('database.hostname', '127.0.0.1'),
'database' => Env::get('database.database', 'grade'),
'username' => Env::get('database.username', 'root'),
'password' => Env::get('database.password', '123456'),
'hostport' => Env::get('database.hostport', '3306'),
'charset' => Env::get('database.charset', 'utf8'),
'prefix' => Env::get('database.prefix', 'tp_'),
  1. 可以通过删除改变.env的配置,或删除.env来验证database的执行优先级;
  2. database.php配置中,default表示设置默认的数据库连接;
  3. connections配置数据库连接信息,可以是多个数据库,便于切换;
  4. 默认的数据库连接名称为:'mysql',再复制一组数据库链接信息:'demo'切换;
  5. 创建一个用于测试数据连接的控制器:DataTest.php;
<?php

namespace app\controller;
use think\facade\Db;

class Datatest
{
    public function index()
    {
        $user = Db::table('tp_user')->select();
        //$user = Db::connect('mysql')->table('tp_user')->select();
        return $user;
        return json($user);
    }
    public function demo()
    {
        $demo = Db::connect('demo')->table('tp_user')->select();
        return json($demo);
    }
}
  1. 暂时不必理解这里的代码,只要运行起来看到效果即可,后面章节会详解;

模型初探

  1. 在 app 目录下创建一个model目录,并创建User.php的模型类;
  2. User继承模型基类,即可实现数据调用,后面章节会详解讲解;
  3. 而受保护的字段$connection,则是切换到demo数据库;
  4. 需要引入Model类并继承该类;
  5. 控制器端的调用方式如下,具体原理,后面模型章节会详解;
<?php

namespace app\model;
use think\Model;

class User extends Model
{
    protected $connection = 'demo';
}
  • 数据库新增demo库和user表

QQ截图20200722112959.png

  • 对应需要修改数据库配置和表前缀

QQ截图20200722112857.png

  • 修改Datatest.php,引入User模型

调用getUser方法,访问的是demo库的user表

<?php

namespace app\controller;

use think\facade\Db;
use app\model\User;

class Datatest
{
    public function index()
    {
        $user = Db::table('tp_user')->select();
        //$user = Db::connect('mysql')->table('tp_user')->select();
        return $user;
        return json($user);
    }

    public function getUser()
    {
        $user = User::select();
        return json($user);
    }
}

QQ截图20200722113306.png

数据库的数据查询

数据库查询必须引入Db类

#引入Db类
use think\facade\Db;

单数据查询

  1. Db::table()中 table 必须指定完整数据表(包括前缀);
  2. 如果希望只查询一条数据,可以使用find()方法,需指定where条件,如果没有查询到默认返回null;
Db::table('tp_user')->where('id', 27)->find();
  1. Db::getLastSql()方法,可以得到最近一条 SQL 查询的原生语句;
Db::getLastSql();

QQ截图20200722134000.png

  1. 没有查询到任何值,则返回 null;
  2. 使用 findOrFail()方法同样可以查询一条数据,在没有数据时抛出一个异常;
Db::table('tp_user')->where('id', 1)->findOrFail();

QQ截图20200722134103.png

  1. 使用 findOrEmpty()方法也可以查询一条数据,但在没有数据时返回一个空数组;
Db::table('tp_user')->where('id', 1)->findOrEmpty();

QQ截图20200722134505.png

数据集查询

  1. 想要获取多列数据,可以使用select()方法;
Db::table('tp_user')->select();

// 执行的sql语句
// SELECT * FROM `tp_user`

QQ截图20200722135103.png

  1. 多列数据在查询不到任何数据时返回空数组,使用selectOrFail()抛出异常;
Db::table('tp_user')->where('id', 1)->selectOrFail();

QQ截图20200722135201.png

  1. 在 select()方法后再使用 toArray()方法,可以将数据集对象转化为数组;
Db::table('tp_user')->select()->toArray();

QQ截图20200722135344.png

  1. 当在database.php配置文件中设置了前缀,那么我们可以使用name()方法忽略前缀;
// database.php
// 'prefix'            => env('database.prefix', 'tp_'),

Db::name('user')->select();

QQ截图20200722135526.png

其它查询

  1. 通过value()方法,可以查询指定字段的值(单个),没有数据返回null;
Db::name('user')->where('id', 27)->value('username');

QQ截图20200722140249.png

  1. 通过colunm()方法,可以查询指定列的值(多个),没有数据返回空数组;
Db::name('user')->column('username');
  1. 可以指定id作为列值的索引;
Db::name('user')->column('username', 'id');

QQ截图20200722140353.png

  1. 如果处理的数据量巨大,成百上千那种,一次性读取有可能会导致内存开销过大;
  2. 为了避免内存处理太多数据出错,可以使用 chunk()方法分批处理数据;
  3. 比如,每次只处理100条,处理完毕后,再读取100条继续处理,示例以2条为例;
Db::table('tp_user')->chunk(2, function($users) {
    foreach ($users as $key => $user) {
        dump($user);
    }
    echo 1;
});

QQ截图20200722140610.png

  1. 可以利用游标查询功能,可以大幅度减少海量数据的内存开销,它利用了PHP生成器特性。每次查询只读一行,然后再读取时,自动定位到下一行继续读取;
  • 关键字yield,php官网关于生成器相关解释官网地址
$cursor = Db::table('tp_user')->cursor();
foreach($cursor as $user){
    dump($user);
}

QQ截图20200722140648.png

数据库的链式查询

查询规则

  1. 前面课程中我们通过指向符号->多次连续调用方法称为:链式查询;
  2. Db::name('user')时,返回查询对象(Query),即可连缀数据库对应的方法;
  3. 而每次执行一个数据库查询方法时,比如where(),还将返回查询对象(Query);
  4. 只要还是数据库对象,那么就可以一直使用指向符号进行链式查询;
  5. 再利用find(),select()等方法返回数组(Array)或数据集对象(Colletion);
  6. find()select()是结果查询方法(放在最后),并不是链式查询方法;
Db::name('user')->where('id', 27)->order('id', 'desc')->find();
  1. 除了查询方法可以使用链式连贯操作,CURD操作也可以使用(后续课程研究);
  2. 那么,有多少种类似where()的链式操作方法呢?打开手册瞄一下

更多查询

  1. 如果多次使用数据库查询,那么每次静态创建都会生成一个实例,造成浪费;
  2. 我们可以把对象实例保存下来,再进行反复调用即可;
$userQuery = Db::name('user');
$dataFind = $userQuery->where('id', 27)->find();
$dataSelect = $userQuery->select();

QQ截图20200722141546.png

  1. 当同一个对象实例第二次查询后,会保留第一次查询的值;
$data1 = $userQuery->order('id', 'desc')->select();
$data2 = $userQuery->select();

QQ截图20200722141702.png

  1. 使用 removeOption()方法,可以清理掉上一次查询保留的值;
$userQuery->removeOption('where')->select();

QQ截图20200722141813.png

数据库的数据新增

单数据新增

  1. 使用insert()方法可以向数据表添加一条数据,更多的字段采用默认;
$data = [
    'username' => '辉夜',
    'password' => '123',
    'gender' => '女',
    'email' => 'huiye@163.com',
    'price' => 90,
    'details' => '123',
];
Db::name('user')->insert($data);
  1. 如果新增成功,insert()方法会返回操作的行数;
echo Db::name('user')->insert($data);

QQ截图20200722143914.png

  1. 如果你添加一个不存在的字段数据,会抛出一个异常Exception;
  2. 如果想强行新增抛弃不存在的字段数据,则使用strick(false)方法,忽略异常;
Db::name('user')->strict(false)->insert($data);

QQ截图20200722144143.png

  1. 如果我们采用的数据库是 mysql,可以支持replace写入;
  2. insertreplace写入的区别,前者表示表中存在主键相同则报错,后者则修改;
Db::name('user')->replace()->insert($data);
echo Db::getLastSql();

QQ截图20200722144238.png

  1. 使用insertGetId()方法,可以在新增成功后返回当前数据ID;
echo Db::name('user')->insertGetId($data);

QQ截图20200722144309.png

批量数据新增

  1. 使用insertAll()方法,可以批量新增数据,但要保持数组结构一致;
$data = [
    [
        'username' => '辉夜',
        'password' => '123',
        'gender' => '女',
        'email' => 'huiye@163.com',
        'price' => 90,
        'details' => '123'
    ],
    [
        'username' => '辉夜',
        'password' => '123',
        'gender' => '女',
        'email' => 'huiye@163.com',
        'price' => 90,
        'details' => '123'
    ]
];
Db::name('user')->insertAll($data);
  1. 批量新增也支持replace()方法,添加后改变成replace into;
Db::name('user')->replace()->insertAll($data);

QQ截图20200722144543.png

save()新增

  1. save()方法是一个通用方法,可以自行判断是新增还是修改(更新)数据;
  2. save()方法判断是否为新增或修改的依据为,是否存在主键,不存在即新增;
Db::name('user')->save($data);

数据库的修改删除

数据修改

  1. 使用update()方法来修改数据,修改成功返回影响行数,没有修改返回 0;
$data = [
'username' => '李白'
];
echo Db::name('user')->where('id', 38)->update($data);
  1. 如果修改数据包含了主键信息,比如 id,那么可以省略掉 where 条件;
$data = [
'id' => 231,
'username' => '李白'
];
echo Db::name('user')->update($data);
  1. 如果想让一些字段修改时执行SQL函数操作,可以使用exp()方法实现;
Db::name('user')->where('id', 232)
->exp('email', 'UPPER(email)')
->update();
  1. 如果要自增/自减某个字段,可以使用inc/dec方法,并支持自定义步长;
Db::name('user')->where('id', 232)
->inc('price')
->dec('status', 2)
->update();
  1. 一个更加简单粗暴灵活的方式,使用::raw()方法实现 3,4 点的内容;
Db::name('user')->where('id', 232)
->update(['email' => Db::raw('UPPER(email)'),
'price' => Db::raw('price + 1'),
'status' => Db::raw('status - 2')]);
  1. 使用 save()方法进行修改数据,这里必须指定主键才能实现修改功能;
Db::name('user')->where('id', 232)->save(['username'=>'李黑']);

数据删除

  1. 极简删除可以根据主键直接删除,删除成功返回影响行数,否则0;
Db::name('user')->delete(51);
  1. 根据主键,还可以删除多条记录;
Db::name('user')->delete([48,49,50]);
  1. 正常情况下,通过where()方法来删除;
Db::name('user')->where('id', 47)->delete();
  1. 通过 true 参数删除数据表所有数据,我还没测试,大家自行测试下;
Db::name('user')->delete(true);

数据库的查询表达式

比较查询

  1. 查询表达式支持大部分常用的SQL语句,语法格式如下:
where('字段名','查询表达式','查询条件');
  1. 在查询数据进行筛选时,我们采用where()方法,比如id=80;
Db::name('user')->where('id', 80)->find();
Db::name('user')->where('id','=',80)->find();
  1. 使用<>,>,<,>=,<=可以筛选出各种符合比较值的数据列表;
Db::name('user')->where('id','<>',80)->select();

区间查询

  1. 使用like表达式进行模糊查询;
Db::name('user')->where('email','like','xiao%')->select();
  1. like表达式还可以支持数组传递进行模糊查询;
Db::name('user')->where('email','like',['xiao%','wu%'], 'or')->select();
// SELECT * FROM `tp_user` WHERE (`email` LIKE 'xiao%' OR `email` LIKE 'wu%')
  1. like表达式具有两个快捷方式whereLike()whereNoLike();
Db::name('user')->whereLike('email','xiao%')->select();
Db::name('user')->whereNotLike('email','xiao%')->select();
  1. between表达式具有两个快捷方式whereBetween()whereNotBetween();
Db::name('user')->where('id','between','19,25')->select();
Db::name('user')->where('id','between',[19, 25])->select();
Db::name('user')->whereBetween('id','19,25')->select();
Db::name('user')->whereNotBetween('id','19,25')->select();
  1. in表达式具有两个快捷方式whereIn()whereNotIn();
Db::name('user')->where('id','in', '19,21,29')->select();
Db::name('user')->where('id','in', [19, 21, 29])->select();
Db::name('user')->whereIn('id','19,21,29')->select();
Db::name('user')->whereNotIn('id','19,21,29')->select();
  1. null表达式具有两个快捷方式whereNull()whereNotNull();
Db::name('user')->where('uid','null')->select();
Db::name('user')->where('uid','not null')->select();
Db::name('user')->whereNull('uid')->select();
Db::name('user')->whereNotNull('uid')->select();

EXP查询

  1. 使用exp可以自定义字段后的SQL语句;
Db::name('user')->where('id','exp','IN (19,21,25)')->select();
Db::name('user')->whereExp('id','IN (19,21,25)')->select();