数据模型

浏览数 111224 最后修改时间
数据模型是操作数据库的类,简称为“模型”,符合类的通用规则模型的类名需要以 model_ 作为前缀,或者驼峰式以model为前缀,可以放在 /model 目录里,也可以放在 /helper目录里,你可以这两个目录之间随意的移动,不会影响程序的正常运行。如果你的系统文件不多,建议放在 /helper 目录里,这样可以得到更快的执行速度。
大多模型是与数据库直接打交道的,因此继承基类model(文件是/system/helper/model.php),继承后即刻拥有常用的数据表操作方法。当然你也可以不继承基类model,识情况而定。

数据库连接方式

YiluPHP提倡只用一种最常用的、最优的方案,这在数据库的使用就有体现,YiluPHP官方只提供MySQL数据库的合作方案,PHP与MySQL有多种连接方式,YiluPHP官方只提供PDO的连接方式,使用PDO的预编译功能,可以有效得避免SQL注入的漏洞。如果你的PHP没有开启PDO模块,记得开启哦,可以网上搜索 “PHP安装PDO模块的方法”。

配置数据库

需要使用MySQL数据库,你只要在配置文件(/config/app.php)中配置你的数据库连接信息即可。因各个(开发、测试、线上)环境中的数据库连接信息会不一样,建议你把数据库信息单独在项目目录外的文件中,然后使用 include 或 require 引入,并合并到全局变量 $config 中。这样做的好处有:
一、数据库信息不会进入SVN或git库中,线上的数据库信息不会被泄露;
二、数据库信息不会在项目的文件中,避免误删。
在 $config['mysql'] 中有默认的数据库连接名称为 default,你可以把它修改成你的可用的数据库连接信息。另外YiluPHP支持同时配置多个数据库,和 default 一样,你可以定义多个你自己的数据库连接名称,并配置上相应的信息。然后在具体模型类中设置此类所需的数据库连接名称。
$config = [
    ...
    'mysql' => [
        //default为默认的数据库连接名
        'default' => [
            'dsn'   =>  'mysql:host=127.0.0.1;port=3306;dbname=yiluuc',
            'username'  =>  'root', //你的数据库登录名
            'password'  =>  'yiluPHP@2017', //你的数据库登录密码
            'charset'   =>  'utf8mb4',
            'option'    =>  [],
        ],
        //你可以自定义一个你想要的连接名称
        'your_db_name' => [
            'dsn'   =>  'mysql:host=127.0.0.1;port=3306;dbname=my_db_name',
            'username'  =>  'root', //你的数据库登录名
            'password'  =>  'yiluPHP@2017', //你的数据库登录密码
            'charset'   =>  'utf8mb4',
            'option'    =>  [],
        ],
    ],
    ...
];

class model_users extends model
{
    //表名
    protected $_table = 'users';
    //数据库连接名
    protected $_connection = 'default';
    //存储单例
    private static $_instance = null;

    /**
     * 获取单例
     * @return model|null 返回单例
     */
    public static function I(){
        if (!static::$_instance){
            return static::$_instance = new self();
        }
        return static::$_instance;
    }
    ...
}

class model_blog extends model
{
    //表名
    protected $_table = 'blog';
    //使用你自定义的数据库连接名
    protected $_connection = 'your_db_name';

    //存储单例
    private static $_instance = null;

    /**
     * 获取单例
     * @return model|null 返回单例
     */
    public static function I(){
        if (!static::$_instance){
            return static::$_instance = new self();
        }
        return static::$_instance;
    }
    ...
}

使用PHP操作数据库

配置完数据库连接信息之后,按照上一步创建数据模型类,只要模型类继承了model基类,那它就自带一些常用的增删改查功能了。无需要额外写引入类文件的代码,你可以在任务地方调用模型。
//根据id查询一条数据
$blog_info = model_blog::I()->find_table(['id'=>888], '*');

//选择所有type为1的数据,按创建时间倒序排
$data = model_blog::I()->select_all(['type'=>1],'create_time DESC','*');

//分页获取数据,这里获取第1页,每页20条,按创建时间倒序排
$data_list = model_blog::I()->paging_select([],1,20,'create_time DESC');

//往博客表中插入一条数据
$data = [
    'title' => '博客标题',
    'content' => '博客内容',
    'create_time' => time(),
];
model_blog::I()->insert_table($data);
查询条件中需要使用大于、小于、LIKE和IN操作的使用方法
//获取两天内的博客数据,按创建时间倒序排序
$where = [
    'create_time' => [
        'symbol' => '>=',
        'value' => strtotime('-2 days'),
    ],
];
$data_list = model_blog::I()->select_all($where, 'create_time DESC', '*');

//获取所有type等于1和2的数据,按创建时间倒序排序
$where = [
    'type' => [
        'symbol' => 'IN',
        'value' => [1,2],
    ],
];
$data_list = model_blog::I()->select_all($where,'create_time DESC','*');

//获取所有title中包含“关键词”的数据,按创建时间倒序排序
$where = [
    'title' => [
        'symbol' => 'LIKE',
        'value' => '%关键词%',
    ],
];
$data_list = model_blog::I()->select_all($where,'create_time DESC','*');

在model基类中还有其它一些操作方法,可以查看 /system/helper/model.php 的源码了解,这里再提两个使用原生SQL的方法,一个查询方法和一个修改方法
//查询类SQL的操作方法
$table = model_blog::I()->get_table();
$sql = <<<sql
SELECT * FROM `$table` WHERE `title` LIKE :title LIMIT 10
sql;
$args = ['title'=>'关键词%'];
$data_list = model_blog::I()->select_sql($sql, $args);

//修改类SQL的操作方法
$table = model_demo::I()->get_table();
$sql = <<<sql
UPDATE `$table` SET `status`=1 WHERE id=:id
sql;
model_blog::I()->execute_sql($sql, ['id'=>888]);

模型方法的命名约定

另外,model 的方法名有一个约定的规范,遵照这个规范可以让你轻易得找到你想要的方法,如下:
/* 
 * 新增一条记录的方法名使用insert_开头
 * 新增多条记录的方法名使用add_开头
 * 新增(已存在则更新)一条记录的方法名使用save_开头
 * 新增(已存在则更新)多条记录的方法名使用store_开头
 * 删除一条记录的方法名使用delete_开头
 * 删除多条记录的方法名使用destroy_开头
 * 更新一条记录的方法名使用update_开头
 * 更新多条记录的方法名使用change_开头
 * 查询一条记录的方法名使用find_开头
 * 查询一条统计数据的方法名使用count_开头
 * 查询多条记录的方法名使用select_开头
 * 分页查询的方法名使用paging_开头
 */

分库分表

YiluPHP 的 model 实现了两种分表方式,第一种是按id的后两位分为100个表,分表名的后缀为下划线加id的后两位整数。第二种是按时间和表数据的数量自动分表。

第一种:按主键id的后两位分为100个表


第二种:按时间和表数据的数量自动分表
需要创建一个管理分表的数据表,SQL在这里:
/document/default_table.sql
CREATE TABLE `sub_table_manage` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `main_table` varchar(32) COLLATE utf8mb4_general_ci NOT NULL COMMENT '主表名称',
  `sub_table` varchar(64) COLLATE utf8mb4_general_ci NOT NULL COMMENT '分表名称',
  `connection` varchar(64) COLLATE utf8mb4_general_ci NOT NULL COMMENT '数据库连接的名称',
  `model_name` varchar(64) COLLATE utf8mb4_general_ci NOT NULL COMMENT '模型类的名称',
  `count` int unsigned NOT NULL DEFAULT '0' COMMENT '表中的数据量每天更新一次',
  `start_time` int unsigned NOT NULL COMMENT '启用时间',
  `end_time` int NOT NULL DEFAULT '0' COMMENT '结束时间',
  `create_time` int unsigned NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_unique` (`main_table`,`sub_table`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='主表和分表的管理';
然后在模型中设置分表方式为 time_and_quantity,和单表的是大数据量
class user extends model
{
    //表名,不包含分表名
    protected $_table = 'user';
    //数据库连接名
    protected $_connection = 'default';
    /**
     * 拆分表的方式
     * null表示不拆分
     * last_two_digits表示根据(如ID)末尾2位数拆分成100个表
     * time_and_quantity表示按时间和数量分表,在一定时间内数量未达到 $_max_quantity_per_table 设置的数量时不分表,否则分表,每天凌晨4点检测是否需要分表,
     *      如果需要分表会设置好第二天开始需要使用的表,所以表中的最终数据量会比预设的数值多一天的数据量
     */
    protected $_split_method = 'time_and_quantity';
    //单表超过5百万条数据就分表
    public $_max_quantity_per_table = 5000000;
    ....
}

创建系统的定时任务:创建新的分表,按照目前实现规则,只需要在每天的凌晨3点半和4点各执行一次就行
运行方式如:/usr/local/php8.0.2/bin/php /data/web/www.yiluphp.com/yilu create_sub_table




我来说说