如何优雅的处理表结构变更导致的数据拆分需求

业务需求

  • 1.0版系统的微信模块只有一个用户表 wechat_users ,里面包含了微信用户信息,主要字段是 mini_open_id, mp_open_id, user_name 。
  • 随着业务需求的更新与升级,微信公众号与小程序的一对一关系已经满足不了。需要升级为一对多的关系了,也就是一个公众号信息对应多个小程序。
  • 所以现在需要新增一个小程序用户表 mini_program_users ,包含小程序用户的信息,主要字段是 mini_open_id。原来微信用户表 wechat_users 的 mini_open_id 字段删除。
  • 因为已经是线上的系统,所以 wechat_users 表中已经有很多用户数据了。

目前的方案

前提:使用 Migration 进行所有表结构的管理。

  • 创建 CreateMiniProgramsTable 类新建 mini_program_users 表。
  • 创建 MoveWechatUserData 类将 wechat_users 表的 mini_open_id 等字段迁移至 mini_program_users 表。
  • 创建 EditWechatUsersTable 类删除 wechat_users 表的 mini_open_id 等字段。

目前的问题

  • 看了 migrate 和 seeder 文档,最后决定用 migrate 进行处理,不知 Laravel 是否还有其他更好的方案?
  • 因为 wechat_users 和 mini_program_users 表有关联关系,所以在 MoveWechatUserData 类中有一些必要的业务逻辑处理,然后在做新增操作,这样是否符合规范呢?

希望听到大家更好的解决方案,你们是如何处理这样的问题呢?

《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 10
aen233

我这两天刚写过 一对多 变 多对多 的数据处理,跟你的需求大概类似
我的做法是,
第一步:migration写新建表,和表新增的字段,
第二步:app/Console/Commands/目录下新建一个命令脚本,在这个脚本中跑数据处理(数据批量插入、原有字段删除、多余表删除、表字段名称修改等等)
第三步:命令行执行php artisan laravel-project:update-wechat-user (就是第二步命令的名称)

抛砖引玉啦,同求更优实现方法~

namespace App\Console\Commands;

use App\Models\A;
use App\Models\B;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class UpdateWechatUser extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'laravel-project:update-wechat-user';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '批量更新微信用户相关数据';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {

        if (Schema::hasTable('a_table')) {
            $this->info('处理a_table表');
            DB::statement('alter table `a_table` drop column a_column');
            DB::statement('drop table c_table');
            DB::statement(' alter table a_table rename c_table');
        }

        if (Schema::hasColumn('b_table', 'b_column')) {
            $this->info('处理b_table表');
            DB::statement('truncate table d_table');
            $data = A::selectRaw('id as e_table_id,else_id,created_at,updated_at,deleted_at')
                ->withTrashed()->get();
            B::insert($data->toArray());
            DB::statement('alter table `d_table` drop column d_column');
        }
        $this->info('ok!');

        return true;
    }
}
2周前

使用 command 确实也是一种方式,可以研究一下。

有个疑问,用这种方式,支持 rollback 这种降级操作吗?也是通过在写一个 command 来实现吧。
@aen233

2周前
aen233

:see_no_evil:写的时候就没考虑回滚,本地用备份的数据库测试,随时跑命令,随时恢复数据库

2周前

:ghost: 嗯 简单研究了一下 如果不考虑降级操作 command 会更灵活 :+1:

1周前

这种操作一般不考虑降级,因为会导致信息丢失,旧表字段可以延后删除,比如1.1版本上线,等1.2 1.3以后再考虑把废弃的字段删除

1周前

@Kamicloud 嗯 在降级的时候 确实会存在数据丢失的问题

因为我用 Migration 方案做,所以也定义了 down 方法,如果降级会丢失新增字段的数据。降级也是仅限于上线后短时间发现问题,能够及时回滚操作。

如果是您遇到这种需求,要如何优雅的处理呢?

1周前

@24K大白羊 production禁用rollback,只允许测试和开发使用。回滚只做代码上的回滚,因为蓝绿部署的时候也需要保证旧代码可以跑,所以不太容易出现逻辑回滚后和数据库不兼容的情况

1周前
aen233

@Kamicloud 你头像的猫猫好萌哦

1周前

@Kamicloud 有道理 感谢分享 学习到了很多 :grin:

1周前

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

社区文档:

将托管在 packagist.org 和 github.com 的扩展包使用国内 CDN 加速
GitHub Laravel 扩展包 TOP 250
速查表方便快速查询框架功能,支持手机访问,支持中英文版本
Laravel 中文文档,由社区用户翻译和维护,将会保持一直更新
此文档的目的,就是为了提高技术团队的凝聚力、一致性和生产效率。
开发环境的部署,开发者工具的选择,适用于 Mac 和 Windows。
浓缩过后的精华
Laravel Nova 后台管理面板文档的中文翻译
Lumen 中文文档,由社区用户翻译和维护,将会保持一直更新
Laravel 下知名扩展包 Dingo API 的中文文档,Laravel API 开发必知必会