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

news/发布时间2024/9/20 5:33:49

不需要在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.bcls.cn/hWnJ/9430.shtml

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

相关文章

音视频数字化(数字与模拟-电视)

上一篇文章【音视频数字化(数字与模拟-音频广播)】谈了音频的广播,这次我们聊电视系统,这是音频+视频的采集、传输、接收系统,相对比较复杂。 音频系统的广播是将声音转为电信号,再调制后发射出去,利用“共振”原理,收音机接收后解调,将音频信号还原再推动扬声器,我…

力扣链表篇

以下刷题思路来自代码随想录以及官方题解 文章目录 203.移除链表元素707.设计链表206.反转链表24.两两交换链表中的节点19.删除链表的倒数第N个节点面试题 02.07. 链表相交142.环形链表II 203.移除链表元素 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链…

wcf 简单实践 数据绑定 数据更新ui

1.概要 2.代码 2.1 xaml <Window x:Class"WpfApp3.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/expr…

基于x86架构的OpenHarmony应用生态挑战赛等你来战!

为了更快速推进OpenHarmony在PC领域的进一步落地&#xff0c;加快x86架构下基于OpenHarmony的应用生态的繁荣&#xff0c;为北向应用开发者提供一个更加便捷的开发环境&#xff0c;推动OpenHarmony北向应用开发者的增加&#xff0c;助力OpenHarmony在PC领域实现新的突破&#x…

Linux系统Docker部署Nexus Maven并实现远程访问本地管理界面

文章目录 1. Docker安装Nexus2. 本地访问Nexus3. Linux安装Cpolar4. 配置Nexus界面公网地址5. 远程访问 Nexus界面6. 固定Nexus公网地址7. 固定地址访问Nexus Nexus是一个仓库管理工具&#xff0c;用于管理和组织软件构建过程中的依赖项和构件。它与Maven密切相关&#xff0c;可…

Sui在AIBC Eurasia奖项评选中被评为2024年度最佳区块链解决方案

自2023年主网上线以来&#xff0c;经历了爆炸性增长的Layer1区块链Sui在2月25–27日迪拜举办的第二届AIBC Eurasia活动中获得“2024最佳区块链解决方案奖”&#xff08;Best Real World Application Award 2024&#xff09;。这个盛大的活动以世界级的参与者和往届获奖者而闻名…

一篇关于,搬运机器人的介绍

搬运机器人是一种能够自动运输和搬运物品的机器人。它们通常配备有传感器和导航系统&#xff0c;可以在工厂、仓库、医院或其他场所自主移动&#xff0c;并且可以根据预先设定的路径或指令进行操作。 搬运机器人可以用于搬运重物、物料搬运、装卸货物、仓库管理等任务。它们可以…

Python程序的流程

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 年轻是我们唯一拥有权利去编制梦想的时…

springboot227旅游管理系统

springboot旅游管理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本旅游管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助使用者在…

《大模型时代-ChatGPT开启通用人工智能浪潮》精华摘抄

原书很长&#xff0c;有19.3w字&#xff0c;本文尝试浓缩一下其中的精华。 知识点 GPT相关 谷歌发布LaMDA、BERT和PaLM-E&#xff0c;PaLM 2 Facebook的母公司Meta推出LLaMA&#xff0c;并在博客上免费公开LLM&#xff1a;OPT-175B。 在GPT中&#xff0c;P代表经过预训练(…

如何运行github上的项目

为了讲明白这个过程&#xff0c;特意做了一个相对来说比较好读懂的原理图&#xff0c;希望和我一样初学的小伙伴也能很快上手哈&#x1f60a; 在Github中找到想要部署的项目&#xff0c;这里以BartoszJarocki/CV&#xff08;线上简历&#x1f4c4;&#xff09;项目为例 先从头…

前端视角对Rust的浅析

概述 本文将从 Rust 的历史&#xff0c;前端的使用场景和业界使用案例一步步带你走进 Rust的世界。并且通过一些简单的例子&#xff0c;了解 Rust 如何应用到前端&#xff0c;提高前端的生产效率。 Rust简史 2006年&#xff0c;软件开发者Graydon Hoare在Mozilla工作期间&#…

C#与VisionPro联合开发——INI存储和CSV存储

1、INI存储 INI 文件是一种简单的文本文件格式&#xff0c;通常用于在 Windows 环境中存储配置数据。INI 文件格式由一系列节&#xff08;section&#xff09;和键值对&#xff08;key-value pairs&#xff09;组成&#xff0c;用于表示应用程序的配置信息。一个典型的 INI 文…

Flink代码单词统计 ---批处理

flatMap&#xff1a;一对多转换操作&#xff0c;输入句子&#xff0c;输出分词后的每个词groupBy&#xff1a;按Key分组&#xff0c;0代表选择第1列作为Keysum&#xff1a;求和&#xff0c;1代表按照第2列进行累加print&#xff1a;打印最终结果 1.WordCount代码编写 需求&am…

k8s资源管理之声明式管理方式

1 声明式管理方式 1.1 声明式管理方式支持的格式 JSON 格式&#xff1a;主要用于 api 接口之间消息的传递 YAML 格式&#xff1a;用于配置和管理&#xff0c;YAML 是一种简洁的非标记性语言&#xff0c;内容格式人性化&#xff0c;较易读 1.2 YAML 语法格式&#xff1a; ●…

C# Onnx 使用onnxruntime部署实时视频帧插值

目录 介绍 效果 模型信息 项目 代码 下载 C# Onnx 使用onnxruntime部署实时视频帧插值 介绍 github地址&#xff1a;https://github.com/google-research/frame-interpolation FILM: Frame Interpolation for Large Motion, In ECCV 2022. The official Tensorflow 2…

五.AV Foundation 视频播放 - 标题和字幕

引言 本篇博客主要介绍使用AV Foundation加载视频资源的时候&#xff0c;如何获取视频标题&#xff0c;获取字幕并让其显示到播放界面。 设置标题 资源标题的元数据内容&#xff0c;我们需要从资源的commonMetadata中获取&#xff0c;在加载AVPlayerItem的时候我们已经指定了…

【Vue】路由

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;Vue ⛺️稳中求进&#xff0c;晒太阳 目录 路由 单页应用程序 总结&#xff1a; VueRouter 核心步骤&#xff1a; 组件存放目录的问题 路由的封装 声明式导航 声明式导航 - 导航链…

二叉树(1)

目录 1. 树型结构 1.1 概念 1.2 概念 1.3 树的表示形式 ​编辑 2. 二叉树 2.1 概念 2.2 两种特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储 2.5 二叉树的基本操作 2.5.1 前置说明 2.5.2 二叉树的遍历 1. NLR&#xff1a;前序遍历(亦称先序遍历): 2. LNR&#xff1a;中序遍历…

Unity中URP实现水体(整理优化)

文章目录 前言一、优化水的深度1、我们把 水流动的方向 和 水深浅过渡值&#xff0c;整合到一个四维变量中2、修改 水体流动方向3、在片元着色器中&#xff0c;修改使用过渡变量 二、优化泡沫三、优化水下的扭曲1、修复原本扰动UV的计算 四、优化水面高光1、把高光强度、光滑度…
推荐文章