sql升级更新解决方案

1.问题

随着项目版本的迭代,有时候需要更新数据库如修改字段、更新数据、删除数据等等,但是如果系统已经部署到生产环境了,让开发人员连接生产环境的数据库手动处理是不太实际的,生产环境数据库一般不允许外部连接,而且这么处理效率太低也容易出错。

2.解决方案

在项目启动时进行数据库自动更新,更新后记录执行的sql方法名

2.1创建sql升级记录表

CREATE TABLE `sys_sql_upgrade_record` (`id` varchar(100) NOT NULL COMMENT 'id',`sqlKey` varchar(100) NOT NULL COMMENT 'sqlKey',`createTime` datetime NOT NULL COMMENT '创建时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='sql升级记录';

2.2对sql升级记录表生成代码

我用的是Mybatis Plus框架,用mybatis-plus-generator工具对sys_sql_upgrade_record表生成controller, entity, mapper, service代码

2.3配置sql升级

项目启动时执行sql升级操作,使用反射机制获取SqlUpgradeRecordMapper的全部自有方法,然后查询sys_sql_upgrade_record表所有的sqlKey,判断每个方法是否存在表中,不存在则用invoke执行,然后保存方法名到sys_sql_upgrade_record表

@Component
@Slf4j
public class CustomCommandLineRunner implements CommandLineRunner {@Autowiredprivate SqlUpgradeRecordService sqlUpgradeRecordService;@Overridepublic void run(String... args) throws Exception {log.info("初始化");try {sqlUpgradeRecordService.executeSqlUpgrade();} catch (Exception e) {log.error("初始化出错", e);}log.info("初始化结束");}
}

SqlUpgradeRecordServiceImpl.java

@Service
@Slf4j
public class SqlUpgradeRecordServiceImpl extends ServiceImpl<SqlUpgradeRecordMapper, SqlUpgradeRecord> implements SqlUpgradeRecordService {@Autowiredprivate SqlUpgradeRecordMapper sqlUpgradeRecordMapper;@Overridepublic void executeSqlUpgrade() {log.info("执行sql升级");Class<SqlUpgradeRecordMapper> mapperClass = SqlUpgradeRecordMapper.class;Method[] declaredMethods = mapperClass.getDeclaredMethods();if (declaredMethods.length > 0) {QueryWrapper<SqlUpgradeRecord> wrapper = new QueryWrapper<>();List<String> list = sqlUpgradeRecordMapper.selectList(wrapper).stream().map(SqlUpgradeRecord::getSqlKey).collect(Collectors.toList());for (Method method : declaredMethods) {String methodName = method.getName();log.info("sqlKey={}", methodName);if (!list.contains(methodName)) {try {log.info("执行sql:{}", methodName);method.invoke(sqlUpgradeRecordMapper);log.info("sql执行成功:{}", methodName);SqlUpgradeRecord record = SqlUpgradeRecord.def();record.setSqlKey(methodName);sqlUpgradeRecordMapper.insert(record);} catch (Exception e) {log.error("sql执行失败", e);}}}}log.info("sql升级结束");}
}

SqlUpgradeRecord.java

@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_sql_upgrade_record")
public class SqlUpgradeRecord implements Serializable {private static final long serialVersionUID = 1L;/*** id*/@TableId(value = "id", type = IdType.ASSIGN_UUID)private String id;/*** sqlKey*/@TableField("sqlKey")private String sqlKey;/*** 创建时间*/@TableField("createTime")private LocalDateTime createTime;public static SqlUpgradeRecord def() {SqlUpgradeRecord entity = new SqlUpgradeRecord();entity.setCreateTime(LocalDateTime.now());return entity;}}

SqlUpgradeRecordMapper.java

@Mapper
public interface SqlUpgradeRecordMapper extends BaseMapper<SqlUpgradeRecord> {/*** 更新所有管理员的状态=1(测试sql更新)*/void updateManagerStatus();
}

SqlUpgradeRecordMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hhf.takeaway.service.user.module.sys.sqlupgraderecord.mapper.SqlUpgradeRecordMapper"><!-- 通用查询映射结果 --><resultMap id="BaseResultMap" type="com.hhf.takeaway.service.user.module.sys.sqlupgraderecord.entity.SqlUpgradeRecord"><id column="id" property="id" /><result column="sqlKey" property="sqlKey" /><result column="createTime" property="createTime" /></resultMap><!-- 通用查询结果列 --><sql id="Base_Column_List">id, sqlKey, createTime</sql><update id="updateManagerStatus">update usr_manager set status = 1</update></mapper>

3.总结

通过这种方案,使得sql升级实现自动化,并且记录了执行哪些sql,方便后续查看,如果希望再次执行某个sql,也可以去记录表手动删掉记录,重启系统后可以再次执行。

想到的另一个方案:

数据库建个temp表,key字段为sql_version,value字段为当前最大版本

自行定义dtd文件,然后根据dtd在resources目录下定义xml,xml里面配置sql语句和对应版本,格式如下

<sql version="1">update ...
</sql>

系统启动时扫描resources目录下的xml文件,用jsoup解析xml文件的元素,获取sql版本和语句,并查询temp表的sql_version,比较sql版本和当前最大版本,执行那些大于最大版本的sql语句,最后更新最大版本到temp表。

此方案工作量就比较大了,需要定义dtd和xml,还要扫描解析xml执行sql语句,相比之下方案一借助Mybatis省去了很多工作量。

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

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

相关文章

便宜寄快递,就选闪侠惠递,帮您省钱!

随着电子商务的发展&#xff0c;物流也越来越发达&#xff0c;人们的生活中有很多地方都与物流快递打交道。网购或者给远方的亲戚朋友寄礼物等等都需要快递。有时候就止步于昂贵的快递的&#xff0c;其实选对方法&#xff0c;寄快递并不贵... 编辑 现在一般寄快递都是选择去菜鸟…

5分钟快速掌握 XML (Extensible Markup Language)

背景 在Java开发的过程中&#xff0c;我们经常需要和配置文件打交道&#xff0c;其中接触最多的就是XML。从最初学习 JavaWeb 时在 Tomcat 中配置servlet&#xff0c;到后来接触Spring框架并在XML中编写各种配置&#xff0c;XML一直是不可或缺的一部分。然而&#xff0c;XML的…

1-2 动手学深度学习v2-基础优化方法-笔记

最常见的算法——梯度下降 当一个模型没有显示解的时候&#xff0c;该怎么办呢&#xff1f; 首先挑选一个参数的随机初始值&#xff0c;可以随便在什么地方都没关系&#xff0c;然后记为 w 0 \pmb{w_{0}} w0​在接下来的时刻里面&#xff0c;我们不断的去更新 w 0 \pmb{w_{0}…

我在代码随想录|写代码Day25 |回溯算法|93.复原IP地址 , 78.子集 , 90.子集II

学习目标&#xff1a; 博主介绍: 27dCnc 专题 : 数据结构帮助小白快速入门 &#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d;&#x1f44d; ☆*: .&#xff61;. o(≧▽≦)…

C系列-动态内存管理

&#x1f308;个人主页: 会编程的果子君 ​&#x1f4ab;个人格言:“成为自己未来的主人~” 目录 为什么要有动态内存分配 malloc和free malloc free calloc和realloc calloc realloc 常见的动态内存的错误 对NULL指针的解引用操作 ​编辑 对动态开辟空间的越界访问…

ES6-const

一、基本用法 - 语法&#xff1a;const 标识符初始值;注意:const一旦声明变量&#xff0c;就必须立即初始化&#xff0c;不能留到以后赋值 - 规则&#xff1a;1.const 声明一个只读的常量&#xff0c;一旦声明&#xff0c;常量的值就不能改变2.const 其实保证的不是变量的值不…

查看自己电脑是arm还是x64(x86);linux操作系统识别

1、查看自己电脑是arm还是x64&#xff08;x86&#xff09; linux 参考&#xff1a; https://liuweiqing.blog.csdn.net/article/details/131783851 uname -a如果输出是 x86_64&#xff0c;那么你的系统是 64 位的 x86 架构&#xff08;通常我们称之为 x64&#xff09;。如果…

2023高精地图甲级测绘资质最新名单【高德地图】

根据2023年自然资源部公布的名单显示&#xff0c;以下公司通过“地图甲级测绘资质”换证审核&#xff0c;也就意味着&#xff0c;以下这些公司可以继续从事电子地图的采集和制作、商业合作等相关业务。 而这一点&#xff0c;对于以电子地图导航为主要业务支撑的企业至关重要。…

C-C++内存管理

C/C内存分布 内存的分配方式有几种&#xff1f; 静态内存分配&#xff08;Static Memory Allocation&#xff09;&#xff1a; 静态内存分配是在编译时确定内存大小和位置的分配方式。全局变量、静态变量和常量都使用静态内存分配。这些变量在程序的整个生命周期中都存在&…

创建TextMeshPro字体文件

相比于Unity的Text组件&#xff0c;TextMesh Pro提供了更强大的文本格式和布局控制&#xff0c;更高级的文本渲染技术&#xff0c;更灵活的文本样式和纹理支持&#xff0c;更好的性能以及更易于使用的优点。但unity自带TextMeshPro字体不支持中文。这里使用普通字体文件生成Tex…

React16源码: React中event事件对象的创建过程源码实现

event 对象 1 &#xff09; 概述 在生产事件对象的过程当中&#xff0c;要去调用每一个 possiblePlugin.extractEvents 方法现在单独看下这里面的细节过程&#xff0c;即如何去生产这个事件对象的过程 2 &#xff09;源码 定位到 packages/events/EventPluginHub.js#L172 f…

Spring事件之注解@EventListener讲解

文章目录 1 注解EventListener1.1 示例Demo1.1.1 简单例子1.1.2 解耦1.1.3 Spring事件 1.2 深入EventListener1.2.1 debug调试1.2.2 问题一&#xff1a; Spring是怎么知道要去触发这个方法1.2.3 问题二&#xff1a;ApplicationListenerMethodAdapter1.2.4 问题三&#xff1a;Si…

Vue学习笔记:计算属性

计算属性 入门进阶二次进阶三次进阶四次进阶结界五次进阶六次进阶七次进阶八次进阶九次进阶终章彩蛋 入门 Vue.js中&#xff0c;计算属性示例&#xff1a; export default {data() {return {firstName: John,lastName: Doe};},computed: {// 计算属性&#xff1a;全名fullNam…

(12)喝汽水

文章目录 每日一言题目解题思路一代码 解题思路二代码 结语 每日一言 长风沛雨&#xff0c;艳阳明月。田野被喜悦铺满&#xff0c;天地间充满着生的豪情。 题目 已知1瓶汽水1元&#xff0c;2个空瓶可以换一瓶汽水&#xff0c;输入整数n&#xff08;n>0&#xff09;&#x…

Maven工程的配置及使用

一、Maven章节 Maven 是 Apache 软件基金会组织维护的一款专门为 Java 项目提供构建和依赖管理支持的工具 1.1、maven的作用 1&#xff09;依赖管理&#xff1a; 方便快捷的管理项目依赖的资源包&#xff08;jar包&#xff09;避免版本冲突 2&#xff09;统一项目结构&…

机器学习算法之逻辑回归算法(Logistic Regression)

逻辑回归算法是一种用于分类问题的经典机器学习算法。虽然它的名字中带有“回归”,但实际上逻辑回归用于解决分类问题,特别是二分类问题。本篇博文将详细介绍逻辑回归算法的工作原理、应用领域以及Python示例。 算法背景 逻辑回归起源于20世纪初,用于分析生存率数据。随后…

Android studio打开md无法显示md渲染问题

Where is Android Studio Markdown support plugin preview preference? - Stack Overflow android studio开发无法选择markdown渲染功能的问题 原因是java runtime出了问题 搜索下面功能 Choose Boot Java Runtime for the IDE 选择带JCEF的 可以选最新的java版本 重启之…

Jvm FullGC 如何排查?

使用场景 我们在使用系统时&#xff0c;有时请求和响应会变得特别慢&#xff0c;系统也变得很卡。 有可能是FullGC的问题&#xff0c;可以逐步地进行排查。 使用jps和top确定进程号pid jps可以列出正在运行的jvm进程&#xff0c;并显示jvm执行主类名称( main()函数所在的类…

浙政钉(专有钉钉)

专有钉钉是浙政钉的测试版本&#xff0c;可在正式发布之前进行业务开发。 专有钉钉 原名政务钉钉 是高安全、强管控、灵活开放的面向大型组织专有独享的协同办公平台。支持专有云、混合云等多种方式灵活部署&#xff0c;以满足客户特定场景所需为目标&#xff0c;最大化以“平…

window 镜像---负载篇

前提&#xff1a;需要修改window的powershell执行脚本的策略 步骤&#xff1a;以管理员身份打开powershell&#xff0c;执行 Get-ExecutionPolicy查看当前执行策略&#xff0c;若返回值是Restricted&#xff0c;需执行Set-ExecutionPolicy RemoteSigned powershell 版本信息&am…