手搓的一款基于sql脚本的数据初始化组件

news2025/1/19 17:54:04

产口孵化新项目时,表中需要提前预置部份数据。如字典,角色、菜单、配置等。以达到快速布署的目的。这部份数据会随着某些因素的影响。如地区变化、系统定制方面。无法使用统一的一份sql。旧方案是在代码里面动态的作insert操作。在项目启动的时候初始化这部份数据。但玩着玩着失控了。主要是看不见、摸不着,不晓得往库里加了些什么数据。烽烟四起,四处报警。在此基础上进行了改良。使用了sql脚本+占位符的模式。并引入了初始化脚本和增量脚本的功能。将脚本执行情况记录到一张表中,防止重复执行。
代码结构:
在这里插入图片描述

代码如下:


@Component
@Slf4j
@ConditionalOnProperty(
        prefix = GlobalConstant.CONFIG_PREFIX + "dependence", name = "enable-squirrel-execute", havingValue = "true")
public class SquirrelExecutor implements EasyApplicationRunner, SquirrelConstant {

    @Autowired
    private DataSource dataSource;
    @Autowired
    private AreaMapper areaMapper;
    @Autowired
    private DeployMapper deployMapper;
    @Autowired
    private SquirrelContextBuilder squirrelContextBuilder;
    @Autowired
    private MinioTemplate minioTemplate;

    @SneakyThrows
    @Override
    public void doBusiness() {
        SquirrelContext context = squirrelContextBuilder.buildSquirrelContext();
        if (context.isStop()) {
            return;
        }
        if (context.hasGlobalInit()) {
            // 执行初始化操作
            doAddScript(context);
        } else {
            // 做增量操作
            doInitScript(context);
        }

        // 记录执行次数
        recordExecuteTimes(context.getExecuteTimes());
    }

    public void doAddScript(SquirrelContext context) {
        // 增量脚本
        List<String> addFileNames = new ArrayList<>();
        Map<String, String> addScripts = context.getAddScripts();
        addScripts.forEach((fileName, script) -> {
            if (!context.hasExecute(fileName)) {
                executeScript(script, context);
                addFileNames.add(fileName);
            }
        });
        if (ZYListUtils.isNotEmptyList(addFileNames)) {
            List<Deploy> addSigns = ZYListUtils.list2list(addFileNames, Deploy::new);
            deployMapper.insertBatch(addSigns);
        }
    }

    public void doInitScript(SquirrelContext context) {
        // 从地区库中挑选出需要的地区保存地区
        List<Area> areas = context.getInitAreas();
        areaMapper.insertSplitBatch(areas, 200);

        List<String> initScripts = context.getInitScripts();
        for (String initScript : initScripts) {
            executeScript(initScript, context);
        }
        // 标记已初始化
        List<Deploy> signs = new ArrayList<>();
        Deploy signInitDeploy = new Deploy(INIT_KEY);
        signs.add(signInitDeploy);
        // 标记当前增量脚本已执行
        Map<String, String> addScripts = context.getAddScripts();
        addScripts.forEach((fileName, script) -> {
            Deploy signAddDeploy = new Deploy(fileName);
            signs.add(signAddDeploy);
        });

        // 导入附件
        // initAttachment();

        deployMapper.insertBatch(signs);
    }


    private void executeScript(String script, SquirrelContext context) {
        Reader reader = ScriptBuilder.of(script, context).buildExecuteReader();
        if (null == reader) {
            return;
        }
        try (Connection connection = dataSource.getConnection()) {
            // 建表
            ScriptRunner sr = new ScriptRunner(connection);
            sr.setAutoCommit(true);
            sr.setStopOnError(false);
            sr.setSendFullScript(true);
            sr.runScript(reader);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("初始化系统表失败" + script);
        }
    }

    private void recordExecuteTimes(int hasExecuteTimes) {
        Deploy signTimes = new Deploy();
        signTimes.setConfigKey(InitParam.EXECUTE_TIMES);
        signTimes.setConfigValue(String.valueOf(hasExecuteTimes + 1));
        if (hasExecuteTimes > 0) {
            deployMapper.updateById(signTimes);
        } else {
            deployMapper.insert(signTimes);
        }
    }

    public void initAttachment() {
        SquirrelAttachment squirrelAttachment = new SquirrelAttachment();
        squirrelAttachment.findAttachment();
        if (squirrelAttachment.isEmpty()) {
            return;
        }
        squirrelAttachment.forEach((fileName, fileInput) -> {
            try (InputStream is = fileInput) {
                FileWrapper fileWrapper = new FileWrapper();
                fileWrapper.setNewFileName(fileName);
                fileWrapper.setExtName(ZYFileUtils.extName(fileName));
                minioTemplate.uploadInputStream(fileWrapper, is, MediaType.APPLICATION_OCTET_STREAM.toString());
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }


}
public class SquirrelContextBuilder {

    @Autowired
    private AreaRepositoryMapper areaRepositoryMapper;
    @Autowired
    private DeployMapper deployMapper;
    @Autowired
    private DependenceProperties dependenceProperties;

    public SquirrelContext buildSquirrelContext() {
        SquirrelContext context = new SquirrelContext();

        // 布署参数配置
        List<Deploy> deploys = deployMapper.selectList(Wrappers.query());
        InitParam initParam = new InitParam(deploys);
        context.setInitParam(initParam);

        Integer squirrelMaxExecuteTimes = dependenceProperties.getSquirrelMaxExecuteTimes();
        int hasExecuteTimes = initParam.hasExecuteTimes();
        // 为保证系统稳定,达到一次脚本初始化次数后将不会再执行。
        if (hasExecuteTimes > squirrelMaxExecuteTimes) {
            log.warn("已达脚本最大初始化次数");
            context.setStop(true);
            return context;
        }

        String rootAreaId = initParam.getRootAreaId();
        if (ZYStrUtils.isNull(rootAreaId)) {
            throw new LocalException("初始化地区根id不能为空");
        }

        AreaRepository rootArea = areaRepositoryMapper.get(rootAreaId);
        if (null == rootArea) {
            throw new LocalException("地区表尚未初始化");
        }

        // 地区层级
        int areaLevel = initParam.getAreaLevel();
        if (areaLevel == 0) {
            throw new LocalException("地区层级未配置");
        }

        // 查询子级地区
        List<AreaRepository> subAreas = findSubAreasByLevel(rootAreaId, rootArea, areaLevel);

        List<AreaRepository> areaContainer = findSubAreasByLevel(rootAreaId, rootArea, 6);
        Map<String, List<AreaRepository>> parentAreaContainer = new HashMap<>();
        for (AreaRepository parentArea : areaContainer) {
            String parentAreaId = parentArea.getId();
            if (ZYTreeUtils.isRootTree(parentAreaId)) {
                continue;
            }
            for (AreaRepository subArea : areaContainer) {
                String subAreaParentIdId = subArea.getParentId();
                if (subAreaParentIdId.equals(parentAreaId)) {
                    ZYMapUtils.flushMapList(parentAreaId, parentAreaContainer, subArea);
                }

            }
        }

        context.setScriptWrapper(new ScriptWrapper());
        context.setParentAreaContainer(parentAreaContainer);
        context.setRootArea(rootArea);
        context.setSubArea(subAreas);

        return context;
    }

    public List<AreaRepository> findSubAreasByLevel(String rootAreaId, AreaRepository rootArea, int areaLevel) {
        List<AreaRepository> subAreas = new ArrayList<>();
        subAreas.add(rootArea);
        List<String> parentIds = Collections.singletonList(rootAreaId);
        for (int i = 1; i < areaLevel; i++) {
            List<AreaRepository> subAreaItems = findAreaByParentIds(parentIds);
            if (ZYListUtils.isEmptyList(subAreaItems)) {
                break;
            }
            parentIds = ZYListUtils.collectField(subAreaItems, AreaRepository::getId);
            subAreas.addAll(subAreaItems);
        }
        return subAreas;
    }

    private List<AreaRepository> findAreaByParentIds(List<String> parentIds) {
        if (ZYListUtils.isEmptyList(parentIds)) {
            return Collections.emptyList();
        }
        LambdaQueryWrapper<AreaRepository> wrapper = Wrappers.lambdaQuery();
        wrapper.in(AreaRepository::getParentId, parentIds);
        return areaRepositoryMapper.selectList(wrapper);
    }
}

public class ScriptWrapper implements SquirrelConstant {

    List<String> initScripts = new ArrayList<>();
    Map<String, String> addScripts = new HashMap<>();

    public ScriptWrapper() {
        Resource[] resources = null;
        try {
            resources = new PathMatchingResourcePatternResolver().getResources("xxx");
        } catch (IOException e) {
            log.warn("脚本文件读取失败");
        }
        if (null == resources) {
            return;
        }

        for (Resource resource : resources) {
            String filename = resource.getFilename();
            if (null == filename) {
                continue;
            }

            // 项目类型A的脚本
            if (filename.startsWith(a)) {
                if (!b) {
                    continue;
                }
            }
            // 项目类型B的脚本
            if (filename.startsWith(b)) {
                if (!b) {
                    continue;
                }
            }

            try (InputStream inputStream = resource.getInputStream()) {
                String sqlScript = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
                if (SquirrelConstant.isInitScript(filename)) {
                    initScripts.add(sqlScript);
                } else if (SquirrelConstant.isAddScript(filename)) {
                    addScripts.put(filename, sqlScript);
                }
            } catch (IOException e) {
                log.warn("脚本文件读取失败");
            }
        }
    }
}

squirrel是松鼠的意思是,该组件寓意把初始化脚本初始化多多弄好。项目多时就有粮可吃。不用加班。好像解释有点牵强。那就是乱起的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/951150.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IPIDEA确认参加2023 CCEE(深圳)雨果跨境全球电商展览会

9月1日—9月3日&#xff0c;雨果跨境将在深圳会展中心&#xff08;福田&#xff09;举办 “2023CCEE&#xff08;深圳&#xff09;雨果跨境全球电商展览会”。 届时&#xff0c;IPIDEA将参加此次跨境年度盛会。作为一家专业的全球HTTP代理商&#xff0c;IPIDEA为与会商家准备了…

MES管理系统数据建模有哪些注意事项

在进行MES管理系统数据建模时&#xff0c;需要注意以下几个方面&#xff0c;以确保建立高效、可靠且适应性强的数据模型&#xff0c;为企业的生产管理提供有力的支持。 首先&#xff0c;精确理解业务需求是进行数据建模的前提。与相关部门和人员进行充分的沟通&#xff0c;了解…

基于web的图书管理系统java书店进销存 jsp源代码Mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 基于web的图书管理系统 系统有1权限:管理员 二、主要…

小程序中如何给会员发送微信服务通知

通过发送微信服务通知&#xff0c;可以及时向会员推送最新的活动、优惠信息等重要通知&#xff0c;从而增加用户参与度和购买意愿。下面就介绍怎么给会员发送微信服务通知的方法和步骤。 1. 找到指定的会员卡。在管理员后台->会员管理处&#xff0c;找到需要接收服务通知的…

【Navicat Premium 16】使用Navicat将excel的数据进行单表的导入,详细操作

业务场景&#xff1a;经常与数据打交道嘛&#xff0c;有的时候会需要将excel的数据导入到数据库中&#xff0c;后面发现对于单表的数据导入&#xff0c;使用Navicat还是非常方便的&#xff0c;仅仅需要将字段关系映射好就可以了 一、开始操作 前提条件&#xff1a;已经成功连接…

算法通关村第9关【白银】| 二分查找与搜索树高频问题

基于二分查找的拓展问题 1.山脉数组的峰顶索引 思路&#xff1a;二分查找 山峰有三种状态&#xff1a;需要注意数组边界 1.顶峰&#xff1a;arr[mid]>arr[mid1]&&arr[mid]>arr[mid-1] 2.上坡&#xff1a;arr[mid]<arr[mid1] 3.下坡&#xff1a;arr[mid]…

【树DP】2021ICPC南京 H

Problem - H - Codeforces 题意&#xff1a; 思路&#xff1a; 这题应该算是铜牌题 铜牌题 简单算法 基础思维 简单复盘一下思路 首先&#xff0c;我们发现有个很特殊的条件&#xff1a; ti < 3 然后看一下样例&#xff1a; 注意到&#xff0c;对于一个结点 u &#…

1.3.2背包模型(二)

1.二维费用的背包问题 有 N N N件物品和一个容量是 V V V的背包&#xff0c;背包能承受的最大重量是 M M M。 每件物品只能用一次。体积是 v i v_{i} vi​&#xff0c;重量是 m i m_{i} mi​&#xff0c;价值是 w i w_{i} wi​。 求解将哪些物品装入背包&#xff0c;可使物…

想要搞懂接口测试和功能测试有什么区别,那就必须知道他们的基本原理

本文主要分为两个部分&#xff1a; 第一部分&#xff1a;主要从问题出发&#xff0c;引入接口测试的相关内容并与前端测试进行简单对比&#xff0c;总结两者之前的区别与联系。但该部分只交代了怎么做和如何做&#xff1f;并没有解释为什么要做&#xff1f; 第二部分&#xf…

图形化管理工具ossbrowser

文章目录 一、OSS介绍二、通过工具管理OSS三、安装四、使用-通过AK五、免责声明摘抄 一、OSS介绍 云对象存储OSS&#xff08;Object Storage Service&#xff09;是一款海量、安全、低成本、高可靠的云存储服务&#xff0c;可提供99.9999999999%&#xff08;12个9&#xff09;…

WebGL:基于web的交互式2D/3D图形引擎

推荐&#xff1a;使用 NSDT编辑器 快速搭建3D应用场景 在本指南中&#xff0c;我们旨在回答与WebGL技术相关的大多数问题。首先&#xff0c;让我们从WebGL定义开始。 什么是WebGL&#xff1f; WebGL&#xff08;Web图形库&#xff09;是一个JavaScript应用程序编程接口&#x…

Python学习 -- 异常捕获技巧

在编写Python代码时&#xff0c;异常处理是确保程序稳定性的关键。Python提供了灵活的异常捕获机制&#xff0c;包括try...except语句、try...except...else语句和try...except...finally语句。本文将详细介绍这些异常处理技巧&#xff0c;并为每种情况提供代码案例。 一、try…

数字孪生:先进技术与未来发展的洞察

数字孪生&#xff1a;先进技术与未来发展的洞察 随着数字技术的迅猛发展&#xff0c;数字孪生作为新兴的概念和技术应运而生。数字孪生能够将现实世界与虚拟世界紧密连接&#xff0c;通过实时监测、数据分析和模拟仿真&#xff0c;为企业提供优化运营、提高效率和质量的解决方案…

透明度高达70%:OLED透明屏原屏在展示器材上的创新应用

OLED透明屏原屏作为一种领先的显示技术&#xff0c;正在引起越来越多企业和消费者的关注。 根据最新的行业数据和报告&#xff0c;OLED透明屏原屏在各个应用领域都展现出卓越的性能和创新的设计特点。 本文将通过深入探讨OLED透明屏原屏的优势和特点、应用领域、技术发展以及…

python的异步编程async

一、介绍 在Python 3.5中引入了async和await关键字&#xff0c;用于异步编程。async关键字用于定义一个协程&#xff08;coroutine&#xff09;&#xff0c;而await关键字则用于等待一个协程完成。 注&#xff1a;协程&#xff08;coroutine&#xff09;是是一种轻量级的线程…

易趋亮相PMOPM大会,分享项目型业务数字化方法与实践

8月26-27日&#xff0c;第二届中国PMO&PM大会在北京、上海、深圳三地同步举行并圆满落幕。大会以“价值交付•重塑未来”为主题&#xff0c;设置了包括“项目管理方法论”、“PMO管理运营”、“组织项目治理”、“创新变革管理”、“项目管理人才”、“前沿趋势和技术”等六…

leetcode 2483. Minimum Penalty for a Shop(商店的最少代价)

字符串customers只包含’Y’和’N’两种字母, 表示 i 时刻商店是否有客人来。 如果商店在 i 时刻处于开门状态&#xff0c;Y’的代价是0&#xff0c;N’的代价是1.&#xff08;开门了却没有客人就算损失&#xff09;。 反之&#xff0c;在 i 时刻处于关门状态&#xff0c;N’的…

【Linux】centos8安装cmake3.27.4

第一步&#xff0c;去官网下安装包&#xff0c;一定不要下错了 下好了之后&#xff0c;用ftp软件传到云服务器或者虚拟机上&#xff0c;我用的是centos8系统&#xff0c;安装之前先准备好这些依赖项 yum install -y gcc gcc-c make automake yum install -y openssl openssl-…

Docker原理详细剖析-Namespace

一、简介 docker容器技术从2013年开始火了以后&#xff0c;2014年左右当时有幸在学校能和学院教授一起做些项目以及学习。其中docker技术在当时来说还算是比较新的技术&#xff0c;国内关于这块的资料以及使用也才刚刚开始&#xff0c;讨论docker技术&#xff0c;算是相对时髦的…

华为OD机试 - 生日礼物 - 二分查找(Java 2023 B卷 100分)

目录 一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 一、题目描述 小牛的孩子生日快要到了&#xff0c;他打算给孩子买蛋糕和小礼物&#xff0c;蛋糕和小礼物…