合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
# **Laravel9.2 数据填充** ##### <blockquote class="danger"><p>数据填充:编写seeder+工厂填充数据</p></blockquote> **需求背景:目前我有三张表:** 表1:fq_push_tasks1 任务表 ``` CREATE TABLE `fq_push_tasks1` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '推送名称', `push_number` varchar(125) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '推送编号', `push_task_type` tinyint NOT NULL DEFAULT '1' COMMENT '推送类型(1:定时消息 2:延迟消息)', `country_code` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '推送国家', `receive_type` tinyint NOT NULL DEFAULT '1' COMMENT '接收用户类型:1:全量用户 2:标签用户', `send_time` timestamp NULL DEFAULT NULL COMMENT '定时消息(必填):发送时间', `push_trigger_type` tinyint NOT NULL DEFAULT '0' COMMENT '延迟消息(必填):触发事件(默认0),1:用户新增 2:充值 3:关闭充值弹窗 4:支付失败', `delay_time` varchar(31) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '延迟消息(必填):延迟时间(单位s)', `cool_time` int NOT NULL DEFAULT '0' COMMENT '延迟消息(必填):冷却时间', `push_position` tinyint NOT NULL DEFAULT '0' COMMENT '推送位置 0全部 1仅push 2仅inbox', `push_scene` tinyint NOT NULL DEFAULT '0' COMMENT '推送场景 0 默认推送,1 新书推荐', `app_ids` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '标签用户(必填):APPID', `system` tinyint NOT NULL DEFAULT '0' COMMENT '标签用户(必填):系统 1:安卓 2:IOS', `last_uid_digits` varchar(125) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '标签用户(必填):最后一个Uid尾数', `ab_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '关联的ab实验id', `link_book_id` varchar(511) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '标签用户(必填):归因书籍', `read_book_id` varchar(511) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '标签用户(必填):阅读过的书', `create_to_send_time` varchar(125) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '标签用户(必填):新增距今天数(位数代表运算类型,首为数字代表非范围类型)', `active_to_send_time` varchar(125) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '标签用户(必填):活跃距今天数(位数代表运算类型,首为数字代表非范围类型)', `total_recharge_nums` varchar(125) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '标签用户(必填):累计充值次数(位数代表运算类型,首为数字代表非范围类型)', `total_recharge_money` varchar(125) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '标签用户(必填):累计充值金额(位数代表运算类型,首为数字代表非范围类型)', `total_active_days` varchar(125) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '标签用户(必填):累计活跃天数(位数代表运算类型,首为数字代表非范围类型)', `send_time_type` tinyint NOT NULL DEFAULT '1' COMMENT '推送时间类型 1:UTC,2:各国时区', `push_priority` int NOT NULL DEFAULT '0' COMMENT '推送优先级', `status` tinyint NOT NULL DEFAULT '1' COMMENT '发送状态 1. 待发送 2. 发送中 3. 发送成功 4. 发送取消 5. 发送失败(默认1:必填)', `admin_id` int unsigned NOT NULL DEFAULT '0' COMMENT '创建的管理员ID', `is_deleted` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 1 是 0 否', `deleted_at` timestamp NOT NULL COMMENT '删除时间', `last_stop_at` timestamp NOT NULL COMMENT '最后一次停止时间', `is_warm_up` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否开始预热 0 否 1 是', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), KEY `idx_system` (`system`), KEY `idx_name` (`name`) USING BTREE, KEY `idx_push_number` (`push_number`) USING BTREE, KEY `idx_push_task_type` (`push_task_type`) USING BTREE, KEY `idx_push_trigger_type` (`push_trigger_type`) USING BTREE, KEY `idx_push_position` (`push_position`) USING BTREE, KEY `idx_push_scene` (`push_scene`) USING BTREE, KEY `idx_status` (`status`) USING BTREE, KEY `idx_is_deleted` (`is_deleted`) USING BTREE, KEY `idx_created_at` (`created_at`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=812 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='推送消息任务主表'; ``` 表2:fq_push_task_apps1 任务关联的app表(1个任务对应多条记录) ``` CREATE TABLE `fq_push_task_apps1` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `task_id` int NOT NULL DEFAULT '0' COMMENT '推送任务ID', `app_id` int NOT NULL DEFAULT '0' COMMENT 'appId', `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_task_id` (`task_id`) USING BTREE, KEY `idx_app_id` (`app_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='推送消息-任务关联app表'; ``` 表三:fq_push_task_statistics1 推送消息-任务维度统计表(1个任务对应1条记录) ``` CREATE TABLE `fq_push_task_statistics1` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `task_id` int NOT NULL DEFAULT '0' COMMENT '推送任务ID', `push_type` int NOT NULL DEFAULT '0' COMMENT '发送类型', `is_auto` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '自动推送1是2否', `send_all` int NOT NULL DEFAULT '0' COMMENT '发送人数', `send_success` int NOT NULL DEFAULT '0' COMMENT '发送成功数', `click_num` int NOT NULL DEFAULT '0' COMMENT '点击数', `recharge_user_num` int NOT NULL DEFAULT '0' COMMENT '充值总人数', `order_num` int NOT NULL DEFAULT '0' COMMENT '订单总数', `order_price` int NOT NULL DEFAULT '0' COMMENT '充值总金额(普通充值,非订阅)', `total_recharge` int NOT NULL DEFAULT '0' COMMENT '总充值金额', `sub_coin_num` int NOT NULL DEFAULT '0' COMMENT '订阅金币包人数【普通订阅(普通月卡) + 复充订阅(复充月卡)】', `sub_coin_price` int NOT NULL DEFAULT '0' COMMENT '订阅金币包金额【普通订阅(普通月卡) + 复充订阅(复充月卡)】', `sub_time_num` int NOT NULL DEFAULT '0' COMMENT '订阅年月周日的人数(包周+买断)', `sub_time_money` int NOT NULL DEFAULT '0' COMMENT '订阅年月周日的金额(包周+买断)', `send_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '发送时间', `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_send_time` (`send_time`), KEY `idx_push_type` (`push_type`), KEY `idx_auto` (`is_auto`), KEY `idx_task_id` (`task_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='推送消息-任务维度统计表'; ``` **需求目标:由于要测试查询效率,因此要填充大量数据,且填充的数据要支持关联填充** ----------------------------------------- **开始实现** * [ ] 执行流程分为三步 * step1:分别讲上述三个表先创建模型,在模型中指定关联关系 * step2:分别创建fq_push_tasks1(PushTaskFactory)、fq_push_task_statistics1(PushTaskStatisticFactory)的工厂类 fq_push_tasks1工厂类创建命令:```php artisan make:factory PushTaskFactory --model=PushTask``` fq_push_task_statistics1工厂类创建命令:```php artisan make:factory PushTaskStatisticFactory --model=PushTaskStatistic``` 备注:PushTaskFactory:工厂名称,PushTask:模型名称,另外模型中必须引用工厂类: <span style="color:red">use HasFactory; </span>,且目录地址必须跟类的地址保持一致(比方说,PushTask.php模型在Model/Push/PushTask.php),那么PushTaskFactory的位置就必须在database/factories/Push/PushTaskStatisticFactory.php * step3:创建一个执行填充类:PushTaskSeeder,创建命令:```php artisan db:seed --class=PushTaskSeeder``` * [ ] 模型内容: ***PushTask.php*** ``` <?php namespace App\Models; use App\Models\Push\PushTaskApp; use App\Models\Push\PushTaskStatistic; use DateTime; use App\Models\Push\PushTaskContent; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasOne; /** * @method static self search($search) */ class PushTask extends BaseModel { // 设置表名 protected $table = "push_tasks1"; // 推送任务类型 1.定时推送 2.延迟推送 const PUSH_TASK_TIMED = 1; const PUSH_TASK_DELAY = 2; use HasFactory; /** * 关联消息统计【一对一】 * * @return HasOne */ public function statistic(): HasOne { return $this->hasOne(PushTaskStatistic::class, 'id', 'task_id'); } } ``` ***PushTaskApp.php*** ``` <?php namespace App\Models\Push; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class PushTaskApp extends Model { // 设置表名 protected $table = "push_task_apps1"; protected $guarded = ['id']; use HasFactory; } ``` ***PushTaskStatistic.php*** ``` <?php namespace App\Models\Push; use App\Models\PushTask; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; class PushTaskStatistic extends Model { protected $guarded = ['id']; protected $table = 'push_task_statistics1'; use HasFactory; /** * 关联任务 * * @return BelongsTo */ public function task(): BelongsTo { return $this->belongsTo(PushTask::class); } } ``` * [ ] 工厂类内容: ***PushTaskFactory.php*** ``` <?php namespace Database\Factories; use App\Models\PushTask; use Carbon\Carbon; use Illuminate\Database\Eloquent\Factories\Factory; class PushTaskFactory extends Factory { protected $model = PushTask::class; public function definition() { return [ 'name' => $this->faker->sentence, 'push_number' => $this->faker->unique()->randomNumber(8), 'push_task_type' => $this->faker->randomElement([1, 2]), 'country_code' => $this->faker->countryCode, 'receive_type' => $this->faker->randomElement([1, 2]), 'send_time' => Carbon::parse($this->faker->dateTimeBetween('-1 year', 'now'))->format('Y-m-d H:i:s'), 'push_trigger_type' => $this->faker->randomElement([0, 1, 2, 3, 4]), 'delay_time' => $this->faker->randomNumber(5), 'cool_time' => $this->faker->randomNumber(3), 'push_position' => $this->faker->randomElement([0, 1, 2]), 'push_scene' => $this->faker->randomElement([0, 1]), 'app_ids' => json_encode($this->faker->randomElements([1, 2, 3, 4], 2)), 'system' => $this->faker->randomElement([1, 2]), 'last_uid_digits' => $this->faker->randomNumber(5), 'ab_id' => $this->faker->randomNumber(8), 'link_book_id' => $this->faker->randomNumber(8), 'read_book_id' => $this->faker->randomNumber(8), 'create_to_send_time' => $this->faker->randomNumber(5), 'active_to_send_time' => $this->faker->randomNumber(5), 'total_recharge_nums' => $this->faker->randomNumber(5), 'total_recharge_money' => $this->faker->randomNumber(5), 'total_active_days' => $this->faker->randomNumber(5), 'send_time_type' => $this->faker->randomElement([1, 2]), 'push_priority' => $this->faker->randomNumber(3), 'status' => $this->faker->randomElement([1, 2, 3, 4, 5]), 'admin_id' => $this->faker->randomNumber(5), 'is_deleted' => $this->faker->randomElement([0, 1]), 'deleted_at' => Carbon::parse($this->faker->optional()->dateTimeBetween('-1 year', 'now'))->format('Y-m-d H:i:s'), 'last_stop_at' => Carbon::parse($this->faker->optional()->dateTimeBetween('-1 year', 'now'))->format('Y-m-d H:i:s'), 'is_warm_up' => $this->faker->randomElement([0, 1]), 'created_at' => Carbon::parse($this->faker->dateTimeBetween('-1 year', 'now'))->format('Y-m-d H:i:s'), 'updated_at' => Carbon::parse($this->faker->dateTimeBetween('-1 year', 'now'))->format('Y-m-d H:i:s'), ]; } } ***PushTaskStatisticFactory.php*** <?php namespace Database\Factories\Push; use App\Models\Push\PushTaskStatistic; use App\Models\PushTask; use Carbon\Carbon; use Illuminate\Database\Eloquent\Factories\Factory; class PushTaskStatisticFactory extends Factory { protected $model = PushTaskStatistic::class; public function definition() { return [ 'push_type' => $this->faker->randomNumber(2), 'is_auto' => $this->faker->randomElement([0, 1]), 'send_all' => $this->faker->randomNumber(5), 'send_success' => $this->faker->randomNumber(5), 'click_num' => $this->faker->randomNumber(5), 'recharge_user_num' => $this->faker->randomNumber(5), 'order_num' => $this->faker->randomNumber(5), 'order_price' => $this->faker->randomNumber(5), 'total_recharge' => $this->faker->randomNumber(5), 'sub_coin_num' => $this->faker->randomNumber(5), 'sub_coin_price' => $this->faker->randomNumber(5), 'sub_time_num' => $this->faker->randomNumber(5), 'sub_time_money' => $this->faker->randomNumber(5), 'send_time' => Carbon::parse($this->faker->dateTimeBetween('-1 year', 'now'))->format('Y-m-d H:i:s'), 'created_at' => Carbon::parse($this->faker->dateTimeBetween('-1 year', 'now'))->format('Y-m-d H:i:s'), 'updated_at' => Carbon::parse($this->faker->dateTimeBetween('-1 year', 'now'))->format('Y-m-d H:i:s') ]; } } 填充类内容: PushTaskSeeder.php ``` <?php namespace Database\Seeders; use Illuminate\Database\Seeder; use App\Models\PushTask; use App\Models\Push\PushTaskApp; use App\Models\Push\PushTaskStatistic; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; class PushTaskSeeder extends Seeder { public function run() { ini_set('memory_limit', '512M'); try { DB::beginTransaction(); // 生成1W条 PushTask 数据 $tasks = PushTask::factory()->count(1000)->create(); $tasks->each(function ($info) { // 创建关联的app数据 $pushTaskAppData = []; $appList = json_decode($info['app_ids'], 1); foreach ($appList as $appId) { $pushTaskAppData[] = ['task_id' => $info->id, 'app_id' => $appId]; } // 批量插入关联的app数据 if ($pushTaskAppData) { PushTaskApp::query()->insert($pushTaskAppData); } // 批量插入关联的PushTaskStatistic数据 PushTaskStatistic::factory()->count(1000)->create(['task_id' => $info->id]); }); DB::commit(); } catch (\Exception $e) { DB::rollBack(); $failMessage = sprintf('Failed to seed push tasks,Msg:%s,File:%s(%s)', $e->getMessage(), $e->getFile(), $e->getLine()); echo $failMessage . $e->getTraceAsString(); Log::error($failMessage); // 优先保存日志 } } } ```