多客户数据库数据更新如何实现

场景描述

对于一个系统往往不止一个客户使用(注意:不是用户,是客户,例如A大学是一个客户、B大学是另一个客户),那么这时,对于系统中的数据结构(例如表设计、字段设计等等)往往是需要更改、完善的,那为了不一一去各个数据库执行相关sql,只想配置一次,从而做到各个数据库都可以更新到相关的数据结构,如何进行除了?

解决思路

首先,客户需要用到数据,一定是进入到系统的,而进入到系统,就一定会经过登入这一操作。

因此,可以通过设置代码全局静态版本号,与数据库存入的版本号进行比对,如果不一致,则进行数据更新,如果一致,则直接进行登入。(这样处理的一个好处就是,每一次的系统数据结构的更迭,只需要一个用户登入一次系统,触发一次数据更新即可)

解决方法

一般来说,对于检查数据结构的更改有:检查表是否存在、检查表字段是否存在、检查表字段是否升级(字段类型变化、长度变化、默认值变化、检查数据是否需要初始化)

此时需要注意:

    1. 对于检查是否需要更新的数据结构需要配置在代码中;
    1. 对于检测是否更新可以做一个标识,标识当前是否满足了数据结构,不满足则进行更新(例如:对于检测表结构,这个标识可以取最近最新添加的表进行配置,检测数据库中是否存在该表,如果不存在,则进入表升级配置里面进行表升级);
    1. 在配置相关的sql时,可以统一进行一个底层方法的执行,这样就可以避免一个数据结构的更改创建一次连接执行一次sql了。

实现方式如下:

图3-1

代码实现举例:

//代码3.1检测版本->检测结构->得到返回的对象->进行sql执行而升级
//检测版本号从而判断是否需要升级
String updateVersion = iSelectSQLService.acquireUpdateVersion(dbName);//获取数据库存储的版本号
iUpdateLog.saveStep(maxLastUpdateIndex, dbName, "检查账套升级版本号和上次升级成功版本号是否一致?");//保存进度、日志
if (StringUtils.isNotEmpty(updateVersion) && updateVersion.equals(UpdateVersion.JavaUpdateVersion)) {
    sMsg = "账套数据库[" + request.getAccDBName() + "]升级版本号与上次一致, 无需升级";
    iUpdateLog.saveStep(maxLastUpdateIndex, dbName, sMsg);//保存进度、日志
    result.put("result", true);
    return success(sMsg, result);
}
sMsg = "升级版本号不一致,需要升级";
iUpdateLog.saveStep(maxLastUpdateIndex, dbName, sMsg);//保存进度、日志
​
//检测数据库是否需要升级
iUpdateLog.saveStep(maxLastUpdateIndex, dbName, "检测数据库是否需要升级?");//保存进度、日志
Boolean aBoolean = iAutoUpdateDB_acc.checkIsNeedUpdate_Acc(iUpdateLog, maxLastUpdateIndex, dbName);//检测表结构是否需要升级 统一进行相关检测 如下    3.2
if (aBoolean) {//进行表升级
    sMsg = "账套数据库[" + request.getAccDBName() + "]需要升级";
    iUpdateLog.saveStep(maxLastUpdateIndex, dbName, sMsg);//保存进度、日志
    msgList.append(sMsg + "\n");
    if (iAutoUpdateDB_acc.update_AccDB()) {//进入表升级sql配置中,获取sql进行处理 3.4
        sMsg = "账套数据库[" + request.getAccDBName() + "]升级成功";
        iUpdateLog.saveStep(maxLastUpdateIndex, dbName, sMsg);
    } else {
        sMsg = "账套数据库[" + request.getAccDBName() + "]升级失败!";
        iUpdateLog.saveStep(maxLastUpdateIndex, dbName, sMsg);//保存进度、日志
        aBoolean = false;
    }
​
} else {
    sMsg = "账套数据库[" + request.getAccDBName() + "]无需升级!";
    iUpdateLog.saveStep(maxLastUpdateIndex, dbName, sMsg);//保存进度、日志
}
​
//代码3.2 统一进行相关检测
public static boolean checkIsNeedUpdate_Acc(IUpdateLog iUpdateLog,int maxLastUpdateIndex,String dbName) throws UnsupportedEncodingException {
        //1
        iUpdateLog.saveStep(maxLastUpdateIndex,dbName,"检测数据表是否需要升级?");//保存进度、日志
        if (checkIsNeedUpdateTable_Acc()){//进入配置(最新的需要升级的表)检测是否要更新 3.3
            iUpdateLog.saveStep(maxLastUpdateIndex,dbName,"数据表需要升级");//保存进度、日志
            return true;
        }else{
            iUpdateLog.saveStep(maxLastUpdateIndex,dbName,"数据表不需要升级");//保存进度、日志
        }
        //2
        iUpdateLog.saveStep(maxLastUpdateIndex,dbName,"检测表字段是否需要升级?");
        if (checkIsNeedUpdateField_Acc()){
            iUpdateLog.saveStep(maxLastUpdateIndex,dbName,"表字段需要升级");
            return true;
        }else{
            iUpdateLog.saveStep(maxLastUpdateIndex,dbName,"表字段不需要升级");
        }
    .
    .
    .        
        //3 表字段的长度需要升级
        //4 表字段是否需要删除
        //5 检测表字段类型是否需要升级
        //6 检查数据是否需要更新
        return false;
    }
//代码3.3 进入配置(最新的需要升级的表)检测是否要更新 
/**
     * 检查数据库表是否存在
     *
     * @return
     */
    private static boolean checkIsNeedUpdateTable_Acc() {
        return !UOperateCheckDB.isSysObjExists("表1名字")//检测当前数据库是否存在该表
            .
            .
            .
               || !UOperateCheckDB.isSysObjExists("表9名字")
               || !UOperateCheckDB.isSysObjExists("表10名字");
    }
//!!!一般配置10个当前系统最新的需要升级的表,即如果最新的都存在,则以前的需要升级的表就存在。这样就不用每一个表都去检测了。
//代码3.4 进入表升级sql配置中,获取sql进行处理
 public Boolean update_AccDB() throws Exception {
        UpdateTable.updateAllTable();//表升级的统一配置类 对应代码 3.5
        AlterField.updateAllField();//表更改的统一配置类
        return true;
    }
//代码3.5 进行表升级sql配置
public static void updateAllTable() throws Exception{
        UpdateTable2021.updateTable();
       .
       .
       .
        UpdateTable2023.updateTable();//对应代码 3.5
    }
//此处又进行了一次区分,目的是为了将不同年度或者模块区分,因为检测底层是否需要升级表时,或将底层需要升级的表的配置都走一边,所以,当系统使用到一定程度,有些表结构已经全部更新到了所有客户数据库中,那么此时,在这里就可以就行注释或使用统一进行管理。
//与此同时,如果想所有更新表的sql一并更新,可以试试在此类中做处理
//代码3.5 如果是按年度进行区分,那么此类里面是按模块进行区分的,以便更好的进行管理
public static void updateTable(){
    UpdateModelTable_A.updateTable();//该模块sql对应代码3.6
    ...
    UpdateModelTable_G.updateTable();
}
//代码3.6 如果配置了更新表sql,都要在这里留下记录。
//代码逻辑是先检测是否,存在则在相对应的类的方法中获取到sql
public static void updateTable() {
        if (!UOperateCheckDB.isSysObjExists("表1名")) {
            XXX.updateSQLTran(表1名所在类.updateTableSql());//获取sql(对应代码3.7),并进行相应的处理
        }
        ...
        if(!UOperateCheckDB.isSysObjExists("表2名")){
            XXX.updateSQLTran(表1名所在类.updateTableSql());
        }
​
    }
//代码3.7 配置相关sql 创建以及更改表述
public static String updateTable(){
        return "CREATE TABLE [表1名] (\n" +
                "[字段1]                   uniqueidentifier default newid() not null,\n" +
                "[字段2]                   money default 0 not null,\n" +
                "[字段3]                  int default 0 not null,\n" +
                "PRIMARY KEY CLUSTERED ([字段1])\n" +
                ")\n" +
                "EXEC sp_addextendedproperty 'MS_Description', '表描述...', 'SCHEMA', 'dbo', 'TABLE', '表1名'\n" +
                "EXEC sp_addextendedproperty 'MS_Description', '主键', 'SCHEMA', 'dbo', 'TABLE', '表1名', 'COLUMN','字段1'\n" +
                "EXEC sp_addextendedproperty 'MS_Description', '字段2描述', 'SCHEMA', 'dbo', 'TABLE', '表1名', 'COLUMN','字段2'\n" +
                "EXEC sp_addextendedproperty 'MS_Description', '字段3描述', 'SCHEMA', 'dbo', 'TABLE', '表1名', 'COLUMN','字段3'";
    }

注意,以上代码并没有指明获取相关sql之后需要怎么去执行(看了代码应该是获取到一条sql执行一次),但是我个人的建议是,统一获取全部相关sql一并执行或者将sql存入记录表中然后之后统一取出再执行。

问题
  1. 万一对象内容出错,对象sql语句不完整如何处理?

    如上代码所示,其实每进行一步,都会进行进度的保存、情况的保存、sql的保存,虽然不涉及sql的处理,但是在一定程度上会起到日志一样的作用。

    因此,其实对于这个过程的执行,我个人是比较建议将对应的sql进行统一的封装或存储,然后进行统一的获取和执行。

  2. 可以先升级字段再升级表吗?

    不能,有一种情况一定需要考虑。即如果进行字段升级时,对应的表不存在,则此时进行的字段sql一定会出错,因而,必须先进行表升级,继而进行字段升级。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

希仔~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值