技术派数据库表自动初始化(学习)

不需要在db中手动创建或者导入相关的schema、data,项目启动自动创建对应的表,并初始化。实现该过程。

Liquibase数据库版本管理

依赖配置

在paicoding-web模块中,pom.xml 文件中添加

        <dependency><groupId>org.liquibase</groupId><artifactId>liquibase-core</artifactId></dependency>

然后就是核心配置,首先是application.yml配置文件中,有两个关键参数

spring:liquibase:change-log: classpath:liquibase/master.xmlenabled: true # 当实际使用的数据库不支持liquibase,如 mariadb 时,将这个参数设置为false

说明:

  • 对于使用的数据库不支持liquibase,如 mariadb 时,将这个参数设置为false 
  • change-log:对应的是核心的数据库版本变更配置

master.xml文件中的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<databaseChangeLogxmlns="http://www.liquibase.org/xml/ns/dbchangelog"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangeloghttp://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"><include file="liquibase/changelog/000_initial_schema.xml" relativeToChangelogFile="false"/></databaseChangeLog>

注意上面这个include,这个就是告诉liqubase,所有的变更记录,都放在

liquibase/changelog/000_initial_schema.xml这个文件中

现在只有一个include标签,但是实际上是可以有多个的,一个好的建议是,项目首次初始化表、初始化数据可以是一个include标签;后续每次大的版本迭代,对应一个新的include。

再看一下000_initial_schema.xml里面的文件内容

<?xml version="1.0" encoding="utf-8"?>
<databaseChangeLogxmlns="http://www.liquibase.org/xml/ns/dbchangelog"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"><property name="now" value="now()" dbms="mysql"/><property name="autoIncrement" value="true"/><changeSet id="00000000000001" author="YiHui"><sqlFile dbms="mysql" endDelimiter=";" encoding="UTF-8" path="liquibase/data/init_schema_221209.sql"/></changeSet><changeSet id="00000000000002" author="YiHui"><sqlFile dbms="mysql" endDelimiter=";" encoding="UTF-8" path="liquibase/data/init_data_221209.sql"/></changeSet><changeSet id="00000000000003" author="YiHui"><sqlFile dbms="mysql" endDelimiter=";" encoding="UTF-8" path="liquibase/data/init_data_221210.sql"/></changeSet><changeSet id="00000000000005" author="YiHui"><sqlFile dbms="mysql" endDelimiter=";" encoding="UTF-8" path="liquibase/data/init_data_221216.sql"/></changeSet><!--  专栏类型,新增免费开始时间、结束时间  --><changeSet id="00000000000006" author="YiHui"><sqlFile dbms="mysql" endDelimiter=";" encoding="UTF-8" path="liquibase/data/update_schema_221223.sql"/></changeSet><!-- user_info表添加ip字段,用于记录访问用户所在地   --><changeSet id="00000000000007" author="YiHui"><sqlFile dbms="mysql" endDelimiter=";" encoding="UTF-8" path="liquibase/data/update_schema_221229.sql"/></changeSet><!-- 配置表新增 extra 字段 --><changeSet id="00000000000008" author="YiHui"><sqlFile dbms="mysql" endDelimiter=";" encoding="UTF-8" path="liquibase/data/update_schema_230103.sql"/></changeSet><!-- 技术派介绍文章 --><changeSet id="00000000000009" author="YiHui"><sqlFile dbms="mysql" endDelimiter=";" encoding="UTF-8" path="liquibase/data/init_data_230103.sql"/></changeSet><!-- 重新更新标签 --><changeSet id="00000000000012" author="LouZai"><sqlFile dbms="mysql" endDelimiter=";" encoding="UTF-8" path="liquibase/data/init_data_230105.sql"/></changeSet><!-- 添加审核中 --><changeSet id="00000000000013" author="LouZai"><sqlFile dbms="mysql" endDelimiter=";" encoding="UTF-8" path="liquibase/data/init_data_230130.sql"/></changeSet><!-- 添加用户角色 --><changeSet id="00000000000014" author="YiHui"><sqlFile dbms="mysql" endDelimiter=";" encoding="UTF-8" path="liquibase/data/update_schema_230131.sql"/></changeSet>
</databaseChangeLog>

说明:

  • changeSet标签,id必须唯一,不能出现冲突
  • sqlFile里面的path,对应的可以是标准的sql文件,也可以是xml格式的数据库表定义、数据库操作文件
  • 一旦写上去,changeSet的顺徐不要调整

比如库表创建的sql

项目演示

在技术派的项目中,还做了一个事情,就是初始化库,在下面的DataSourceInitializer中有介绍;如果是一个新的项目,接入Liquibase之后,数据库,请注意还是需要自己来创建的

项目启动之后,一切正常的话,直接连接上数据库可以看到库表创建成功,数据也初始化完成,当然也可以是直接观察控制台的输出。

下面红框中的ChangeSet xxx run successfully  in 401ms 就表示对应的sql执行成功了

注意事项

非常重要的一个点是,上面的每个ChangeSet只会执行一次,因此当执行完毕之后发现不对,要回滚怎么办,或者需要修改怎么办?需要Liquibase提供的回滚机制。简单说明。

当Change执行完毕之后,对应的sql文件/xml文件(即path定义的文件)不允许在修改,因为db中会记录这个文件的md5,当修改这个文件之后,这个MD5也会随之发生改变

有两个方案解决:新增一个changeSte

删除DATABASECHANFELOG表中changeSet id对应的记录,然后重新走一遍

DataSourceInitializer首次初始化方案

我们这里主要借助DataSourceInitializer来实现初始化,其核心有两个配置

  • DatabasePopulator:通过addCcripts来指定对应的的sql文件
  • DataSourceInitializer#setEnable;判断是否需要执行初始化

我们主要借助DataSourceInitializer来实现Liquibase的表的创建、数据变更等操作;但是在此之前,我们还做了一个库的初始化

库初始化

接下来重点要看的就是needInit方法,我们在这个方法里面,需要判断数据库是否存在,若不存在时,则创建数据库;然后判断表是否存在,以此来决定是否需要执行初始化方法。

入口在实现ForumDataSourceInitializer

  /*** 检测一下数据库中表是否存在,若存在则不初始化;否则基于 schema-all.sql 进行初始化表** @param dataSource* @return*/private boolean needInit(DataSource dataSource) {if (autoInitDatabase()) {return true;}// 根据是否存在表来判断是否需要执行sql操作JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);List list = jdbcTemplate.queryForList("SELECT table_name FROM information_schema.TABLES where table_name = 'user_info' and table_schema = '" + database + "';");return CollectionUtils.isEmpty(list);}/*** 数据库不存在时,尝试创建数据库*/private boolean autoInitDatabase() {// 查询失败,可能是数据库不存在,尝试创建数据库之后再次测试URI url = URI.create(SpringUtil.getConfig("spring.datasource.url").substring(5));String uname = SpringUtil.getConfig("spring.datasource.username");String pwd = SpringUtil.getConfig("spring.datasource.password");try (Connection connection = DriverManager.getConnection("jdbc:mysql://" + url.getHost() + ":" + url.getPort() +"?useUnicode=true&characterEncoding=UTF-8&useSSL=false", uname, pwd);Statement statement = connection.createStatement()) {ResultSet set = statement.executeQuery("select schema_name from information_schema.schemata where schema_name = '" + database + "'");if (!set.next()) {// 不存在时,创建数据库String createDb = "CREATE DATABASE IF NOT EXISTS " + database;connection.setAutoCommit(false);statement.execute(createDb);connection.commit();log.info("创建数据库({})成功", database);if (set.isClosed()) {set.close();}return true;}set.close();log.info("数据库已存在,无需初始化");return false;} catch (SQLException e2) {throw new RuntimeException(e2);}}

上面的实现比较清晰了,首先是判断数据库是否存在,这里需要注意的就是,我们需要自己额创建db的连接,并执行相关库的判断、初始化sql执行。

为什么不直接使用spring.datasource.url来创建连接?

        因为库不存在时,直接使用下面这个url进行连接会抛出异常

表初始化

表初始化,其实可以理解为项目启动后要执行的一些sql,这时主要借助就是initializer.setDatabasePopulator

核心知识点

虽然技术派新增了一个DbChangeSetLoader类来实现初始化sql的加载,但实际上,若你完全抛开Liquibase,单纯的希望项目启动后执行某些sql,可以非常简单的实现,直接用下面这种就可以了啦。

  • 通过@Value来加载需要初始化的sql文件
  • 直接通过ResourceDatabasePoplulator添加sql资源

Liquibase兼容方案

在技术派中,做了Liquibase的兼容,即找那些sql需要进行初始化,完全在遵循了Liquibase中定义的xml文件

要想要在技术派中使用这种方式进行初始化,如使用marizadb时,需要修改配置参数

spring.liquibase.enable:false

核心的实现如下:

对于liquibase的xml文件解析,核心逻辑在DbChangeSetLoader中,借助sax来进行xml文件的解析(Spring也是用sax解析xml的)

实现看源码,有两个知识点:

1.如何加载xml文件

        下面的传参set是相对路径,如liquibase/data/init_data_221216.sql

2、sax的xml解析

小结

介绍项目启动之后库表的初始化操作,结合实际的代码介绍了两种使用姿势

  • Liquibase:代表的数据库版本管理方式
  • DataSourceInitializer:代表的项目启动之后执行某些初始化方式

更多关注:

DataSourceInitializer方式-数据库初始化方式

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

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

相关文章

自 JDK 8 到 JDK 21 以来所有 Java 和 JVM 特性的分类列表

请参看文章&#xff1a;自 JDK 8 到 JDK 21 以来所有 Java 和 JVM 特性的分类列表

【ECMAScript语法】讲解

ECMAScript语法介绍 ECMAScript&#xff08;通常缩写为ES&#xff09;是一种由Ecma国际&#xff08;前称为欧洲计算机制造商协会&#xff09;标准化的脚本程序语言的标准化&#xff0c;它被用来创建客户端和服务器端的应用程序&#xff0c;但是它最为人所熟知的应用环境还是作…

python爬虫之协程知识点记录

一、协程 概念 协程 又称微线程(纤程)&#xff0c;是一种用户态的轻量级线程 子程序 在所有的语言中都是层级调用的&#xff0c;比如A中调用B&#xff0c;B在执行过程中调用C&#xff0c;C执行完返回&#xff0c;B执行完返回&#xff0c;最后是A执行完毕。这是通过栈实现的&a…

01 MySQL之连接

1. 连接 1.0 基础认知 多表(主表)和一表(从表的区别): 多表一般是主表&#xff0c;一般存储主要数据&#xff0c;每个字段都可能存在重复值&#xff0c;没有主键&#xff0c;无法根据某个字段定位到准确的记录&#xff1b; 一表一般是从表&#xff0c;一般存储辅助数据&…

2024年腾讯云优惠活动——十大活动TOP10来看看

腾讯云服务器多少钱一年&#xff1f;62元一年起&#xff0c;2核2G3M配置&#xff0c;腾讯云2核4G5M轻量应用服务器218元一年、756元3年&#xff0c;4核16G12M服务器32元1个月、312元一年&#xff0c;8核32G22M服务器115元1个月、345元3个月&#xff0c;腾讯云服务器网txyfwq.co…

「板块轮动」和「经济周期」的关系

这是 溪踪投研 的第 005 篇文章 初涉股市&#xff0c;如身在山中&#xff0c;丘壑纵横&#xff0c;不知所处。这时不妨把时间拉长、范围拓宽&#xff0c;视野格局大为不同&#xff0c;就更容易找到投资方向&#xff0c;趋利而动、避害而行。 一、逃不开的「经济周期」 如同人…

阿里云4核16G服务器多少钱?幻兽帕鲁配置报价

2024阿里云幻兽帕鲁专用服务器价格表&#xff1a;4核16G幻兽帕鲁专用服务器26元一个月、149元半年&#xff0c;默认10M公网带宽&#xff0c;8核32G幻兽帕鲁服务器10M带宽价格90元1个月、271元3个月。阿里云提供的Palworld服务器是ECS经济型e实例&#xff0c;CPU采用Intel Xeon …

Android使用AtomicReference

AtomicReference 是 Java 中用来提供原子操作的类之一&#xff0c;它可以在多线程环境下安全地对对象引用进行读取和更新操作。在 Kotlin 中&#xff0c;我们也可以直接使用 AtomicReference 来实现线程安全的参数。 以下是一个简单的示例&#xff0c;演示了如何在 Kotlin 中使…

迎接2024年3月5-7日国际生物发酵展-华运机械

参展企业介绍 合肥华运机械制造有限公司初创于1995年&#xff0c;系国内专业性流体机械设备制造的高新技术企业、安徽省专精特新企业&#xff0c;公司位于国家级开发区合肥双凤工业园&#xff0c;拥有15000㎡现代化厂房&#xff0c;几十台精密数控机床和焊接机器人&#xff0c…

vue3使用echarts绘制地图

vue3使用echarts绘制地图 安装echarts npm install echarts下载地图的json数据【我这里是把json数据单独粘出来然后新建了一个文件china.json】 下载中国及各个省份的地图数据引入 import chinaJson from ./china.json绘制地图 <template><div ref"myChart&q…

msql 查询json类型数据

模糊查询数组类型数据 SELECT * FROM table_name WHERE JSON_EXTRACT(column_name, $) LIKE %value%;# table_name 表名 # column_name:字段名 # $ 固定写死模糊查询键值对类型数据 SELECT * FROM table_name WHERE JSON_EXTRACT(column_name, $.key) LIKE %value%;# table_n…

JVM(3)

垃圾回收(GC)相关 在C/C中,当我们使用类似于malloc的内存开辟,还需要手动释放内存空间,这样的机制在使用时给我们造成了诸多不便,但在Java中,有垃圾回收这样的机制,这就是指:我们不再需要手动释放,程序会自动判定,某个内存空间是否可以继续使用,如果内存不使用了,就会自动释放…

前端面试知识整理:vue的钩子函数

vue的钩子函数有好几类 一、生命周期钩子函数 &#xff08;1&#xff09;beforeCreate&#xff08;&#xff09; 实例创建前触发 &#xff08;2&#xff09;created&#xff08;&#xff09; 实例创建完成&#xff0c; &#xff08;3&#xff09;beforeM…

swoole协程

协程执行顺序 //hyperf框架 use Co;go(function () {Co::sleep(1); // Io等待一秒echo "hello go1 \n";});echo "hello main \n";go(function () {echo "hello go2 \n";});//打印结果hello mainhello go2hello go1/*运行此段代码, 系统启动一个…

数据抽取平台pydatax介绍--实现和项目使用

数据抽取平台pydatax实现过程中&#xff0c;有2个关键点&#xff1a; 1、是否能在python3中调用执行datax任务&#xff0c;自己测试了一下可以&#xff0c;代码如下&#xff1a; 这个str1就是配置的shell文件 try:result os.popen(str1).read() except Exception as …

【附学习笔记合集】零基础自学网络安全,从入门到精通,还学不会我退出网安圈!

一、自学网络安全学习的误区和陷阱 1.不要试图先以编程为基础的学习再开始学习 我在之前的回答中&#xff0c;我都一再强调不要以编程为基础再开始学习网络安全&#xff0c;一般来说&#xff0c;学习编程不但学习周期长&#xff0c;而且实际向安全过渡后可用到的关键知识并不…

面试经典150题——插入区间

"The future belongs to those who believe in the beauty of their dreams." - Eleanor Roosevelt 1. 题目描述 2. 题目分析与解析 2.1 思路一 解决这个问题的思路是基于区间排序和合并的经典算法。这个问题的关键在于如何处理新区间与现有区间的关系&#xff0c…

测评ONLYOFFICE 8.0版本:办公利器再升级

测评ONLYOFFICE 8.0版本&#xff1a;办公利器再升级 前言注册使用升级功能速览全新外观设计wordexcelPPTPDF 协作功能强化更强大的功能复杂表单的填写 移动端优化结语 前言 随着科技的不断发展&#xff0c;办公软件在提升用户体验和工作效率方面扮演着越来越重要的角色。作为一…

18V/5A桥式驱动芯片-SS6285L兼容替代RZ7889

SS6285L是一款由工采网代理的率能DC双向马达驱动电路芯片&#xff1b;该芯片采用SOP8封装&#xff0c;符合ROHS规范&#xff0c;引脚框架100%无铅&#xff1b;它适用于玩具等类的电机驱动、自动阀门电机驱动、电磁门锁驱动等应用。 &#xff08;1&#xff09;产品描述&#xff…

[蓝桥杯 2021 省 AB2] 小平方

每日一道算法题之小平方 一、题目描述二、思路三、C代码 一、题目描述 题目来源&#xff1a;洛谷 [蓝桥杯 2021 第二轮省赛 A 组 F 题&#xff08;B 组 G 题&#xff09;] 小平方小蓝发现&#xff0c;对于一个正整数 n 和一个小于 n 的正整数 v&#xff0c;将 v 平方后对 n 取…