Spring boot 随笔 1 DatasourceInitializer
0. 为啥感觉升级了 win11 之后,电脑像是刚买回来的,很快
这篇加餐完全是一个意外:时隔两年半,再看 Springboot-quartz-starter
集成实现的时候,不知道为啥我的h2 在应用启动的时候,不能自动创建quartz相关的schema。后面看了 springboot 的文档,据说是可以做到的,AI也是这么说的。
没办法,只能看 QuartzAutoConfiguration
源码了。于是乎,就有了这么个好活
没办法,就当是一个支线任务了
1. AbstractScriptDatabaseInitializer
下面是熟悉的,阉割后的 源码
package org.springframework.boot.sql.init;/*** Base class for an {@link InitializingBean} that performs SQL database initialization* using schema (DDL) and data (DML) scripts.** @author Andy Wilkinson* @since 2.5.0*/
public abstract class AbstractScriptDatabaseInitializer implements ResourceLoaderAware, InitializingBean {// 构造入参配置private final DatabaseInitializationSettings settings;private volatile ResourceLoader resourceLoader;@Overridepublic void afterPropertiesSet() throws Exception {// 初始化后,就执行逻辑了initializeDatabase();}/*** Initializes the database by applying schema and data scripts.* @return {@code true} if one or more scripts were applied to the database, otherwise* {@code false}*/public boolean initializeDatabase() {ScriptLocationResolver locationResolver = new ScriptLocationResolver(this.resourceLoader);// 先后执行 schema, data 的脚本boolean initialized = applySchemaScripts(locationResolver);return applyDataScripts(locationResolver) || initialized;}// 真正执行脚本前,会走这个判断,决定是否要执行脚本private boolean isEnabled() {if (this.settings.getMode() == DatabaseInitializationMode.NEVER) {return false;}return this.settings.getMode() == DatabaseInitializationMode.ALWAYS || isEmbeddedDatabase();}/*** Returns whether the database that is to be initialized is embedded.* @return {@code true} if the database is embedded, otherwise {@code false}* @since 2.5.1*/protected boolean isEmbeddedDatabase() {throw new IllegalStateException("Database initialization mode is '" + this.settings.getMode() + "' and database type is unknown");}private boolean applySchemaScripts(ScriptLocationResolver locationResolver) {return applyScripts(this.settings.getSchemaLocations(), "schema", locationResolver);}private boolean applyDataScripts(ScriptLocationResolver locationResolver) {return applyScripts(this.settings.getDataLocations(), "data", locationResolver);}private boolean applyScripts(List<String> locations, String type, ScriptLocationResolver locationResolver) {List<Resource> scripts = getScripts(locations, type, locationResolver);if (!scripts.isEmpty() && isEnabled()) {runScripts(scripts);return true;}return false;}// 根据配置的 路径的字符串 -> spring.Resource 类型private List<Resource> getScripts(List<String> locations, String type, ScriptLocationResolver locationResolver) {if (CollectionUtils.isEmpty(locations)) {return Collections.emptyList();}List<Resource> resources = new ArrayList<>();for (String location : locations) {for (Resource resource : doGetResources(location, locationResolver)) {if (resource.exists()) {resources.add(resource);}}}return resources;}private List<Resource> doGetResources(String location, ScriptLocationResolver locationResolver) {return locationResolver.resolve(location);}private void runScripts(List<Resource> resources) {runScripts(resources, this.settings.isContinueOnError(), this.settings.getSeparator(),this.settings.getEncoding());}protected abstract void runScripts(List<Resource> resources, boolean continueOnError, String separator,Charset encoding);private static class ScriptLocationResolver {private final ResourcePatternResolver resourcePatternResolver;private List<Resource> resolve(String location) throws IOException {// ...}}}
再看几个它的实现类,加载上配置类,基本上,可以知道它的使用方法了
2. 吾のDemo
始于测试类
package org.pajamas.spring.boot;import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.pajamas.example.starter.core.entity.AlbumEntity;
import org.pajamas.example.starter.core.repo.AlbumRepo;
import org.pajamas.example.test.AbstractApplicationTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.TestPropertySource;import java.util.List;/*** @author william* @since 2024/5/30*/
@DisplayName("what the interesting component")
@TestPropertySource(properties = {"spring.application.name=service-example-test",// 屏蔽 liquibase 的干扰 "spring.liquibase.enabled=false"
})
@Import(ExampleDatabaseInitializer.class)
public class DatabaseInitializerTest extends AbstractApplicationTest {// 其实就,一个 jpa 实体类的 repository@AutowiredAlbumRepo repo;// @Disabled@DisplayName("execute DDL, DML automatically, as App startup")@Testpublic void t0() throws Exception {// 预期的结果:启动启动时,自动创建表,并插入一条记录List<AlbumEntity> all = this.repo.findAll();printErr(all);}
}
既然是测试,就走简单的方式,注册这个bean
package org.pajamas.spring.boot;import org.springframework.boot.autoconfigure.sql.init.SqlDataSourceScriptDatabaseInitializer;
import org.springframework.boot.autoconfigure.sql.init.SqlInitializationProperties;
import org.springframework.boot.sql.init.DatabaseInitializationMode;import java.util.Collections;import javax.sql.DataSource;/*** @author william* @since 2024/5/30*/
public class ExampleDatabaseInitializer extends SqlDataSourceScriptDatabaseInitializer {public ExampleDatabaseInitializer(DataSource dataSource) {super(dataSource, getProperty());}private static SqlInitializationProperties getProperty() {SqlInitializationProperties properties = new SqlInitializationProperties();properties.setSchemaLocations(Collections.singletonList("classpath:sql/schema.sql"));properties.setDataLocations(Collections.singletonList("classpath:sql/data.sql"));properties.setMode(DatabaseInitializationMode.ALWAYS);properties.setContinueOnError(false);return properties;}
}
schema.sql
CREATE TABLE IF NOT EXISTS `t_album`
(`id` bigint NOT NULL AUTO_INCREMENT,`album_name` varchar(32) DEFAULT NULL COMMENT 'album name',`album_year` int DEFAULT NULL COMMENT 'album publish year',`create_date` timestamp NULL DEFAULT NULL,`create_user_id` bigint DEFAULT NULL,`update_date` timestamp NULL DEFAULT NULL,`update_user_id` bigint DEFAULT NULL,`ver` int NOT NULL DEFAULT '0',`del` bigint NOT NULL DEFAULT '0',PRIMARY KEY (`id`),UNIQUE KEY `uni_album_id_del` (`id`,`del`)
) COMMENT='album table';CREATE TABLE IF NOT EXISTS `t_artist`
(`id` bigint NOT NULL AUTO_INCREMENT,`artist_name` varchar(32) DEFAULT NULL COMMENT 'artist name',`artist_from` varchar(32) DEFAULT NULL COMMENT 'shorten of country name',`create_date` timestamp NULL DEFAULT NULL,`create_user_id` bigint DEFAULT NULL,`update_date` timestamp NULL DEFAULT NULL,`update_user_id` bigint DEFAULT NULL,`ver` int NOT NULL DEFAULT '0',`del` bigint NOT NULL DEFAULT '0',PRIMARY KEY (`id`),UNIQUE KEY `uni_artist_id_del` (`id`,`del`)
) COMMENT='artist table';
data.sql
insert into`t_album`
(`album_name`,`album_year`,`create_user_id`,`update_user_id`
)
values
('Boomerang',2023,1023,1023
);
3. 话说回来:为甚么,我的h2没有自动创建quartz的schema
这是springboot.Quartz的实现
接下来,源码启动…
package org.springframework.boot.jdbc.init;/*** {@link InitializingBean} that performs {@link DataSource} initialization using schema* (DDL) and data (DML) scripts.** @author Andy Wilkinson* @since 2.5.0*/
public class DataSourceScriptDatabaseInitializer extends AbstractScriptDatabaseInitializer {@Overrideprotected boolean isEmbeddedDatabase() {try {// step into ..return EmbeddedDatabaseConnection.isEmbedded(this.dataSource);}catch (Exception ex) {logger.debug("Could not determine if datasource is embedded", ex);return false;}}
}----------// org.springframework.boot.jdbc.EmbeddedDatabaseConnection/*** Convenience method to determine if a given data source represents an embedded* database type.* @param dataSource the data source to interrogate* @return true if the data source is one of the embedded types*/public static boolean isEmbedded(DataSource dataSource) {try {return new JdbcTemplate(dataSource)// step into ....execute(new IsEmbedded());}catch (DataAccessException ex) {// Could not connect, which means it's not embeddedreturn false;}}----------// org.springframework.boot.jdbc.EmbeddedDatabaseConnection.IsEmbedded@Overridepublic Boolean doInConnection(Connection connection) throws SQLException, DataAccessException {DatabaseMetaData metaData = connection.getMetaData();String productName = metaData.getDatabaseProductName();if (productName == null) {return false;}productName = productName.toUpperCase(Locale.ENGLISH);// step into ...EmbeddedDatabaseConnection[] candidates = EmbeddedDatabaseConnection.values();for (EmbeddedDatabaseConnection candidate : candidates) {if (candidate != NONE && productName.contains(candidate.getType().name())) {// 根据jdbc.url判断是不是一个 嵌入式数据库String url = metaData.getURL();return (url == null || candidate.isEmbeddedUrl(url));}}return false;}------------public enum EmbeddedDatabaseConnection {// H2 判断是否为嵌入式数据的依据/*** H2 Database Connection.*/H2(EmbeddedDatabaseType.H2, DatabaseDriver.H2.getDriverClassName(),"jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE", (url) -> url.contains(":h2:mem")),}
破案:我的h2 使用默认的 file(xxx.mv.db) 存储,默认配置下(DatabaseInitializationMode.EMBEDDED
), 只有内存(嵌入式)的数据库会开启这个特性。
- 要么配置
DatabaseInitializationMode.ALWAYS
- 要么使用内存数据库
Anyway, h2支持好多种连接方式,新版本h2, 默认的file模式,采用mv的storeEngine 支持MVCC。所以说,对于quartz这种依赖行锁的要求,也是支持的。
4. 话又说回去… 这个东西对项目的意义是什么
- 可以试下这个:如果你有一个连接数据库的测试环境,或者你的程序很简单,又或者 有特殊的xp(内存数据库)
- 专门数据库的版本控制工具:你的程序比较复杂,或者 本身就需要数据库的版本控制工具(如 Liquibase),运行在严肃的生产环境
相关文章:

Spring boot 随笔 1 DatasourceInitializer
0. 为啥感觉升级了 win11 之后,电脑像是刚买回来的,很快 这篇加餐完全是一个意外:时隔两年半,再看 Springboot-quartz-starter 集成实现的时候,不知道为啥我的h2 在应用启动的时候,不能自动创建quartz相关…...

vue3_组件间通信方式
目录 一、父子通信 1.父传子( defineProps) 2.父传子(useAttrs) 3.子传父(ref,defineExpose ) 4.子传父(defineEmits) 5.子传父(v-model) …...

mysql的锁(全局锁)
文章目录 mysql按照锁的粒度分类全局锁概念:全局锁使用场景:全局锁备份案例: mysql按照锁的粒度分类 全局锁 概念: 全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法,命令是: Flush tables with…...

Spring Boot 整合开源 Tess4J库 实现OCR图片文字识别
😄 19年之后由于某些原因断更了三年,23年重新扬帆起航,推出更多优质博文,希望大家多多支持~ 🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志 🎐 个人CSND主页——Mi…...
使用 Docker 和 Docker Compose 部署 Vue
使用 Docker 和 Docker Compose 部署 Vue 项目有两种方式:直接使用 Docker 和使用 Docker Compose。 创建 Dockerfile 在Vue.js项目根目录下创建一个 Dockerfile 的文件 # 使用最新的官方 Node.js 镜像作为基础镜像,并命名为 builder 阶段 FROM node:…...
力扣linkedlist
反转链表、 public class reverseList { // 1->2->3->o 、 o<-1<-2<-3public ListNode reverseList(ListNode head){//反转链表ListNode prevnull;ListNode currhead;while(curr!null){ListNode nextcurr.next;curr.nextprev;prevcurr;currnext;}retu…...
springboot 启动原理、启动过程、启动机制的介绍
Spring Boot 是一种基于 Java 的框架,用于创建独立的、生产级别的 Spring 应用程序。它的主要目标是简化 Spring 应用的初始搭建和开发过程,同时提供一系列大型项目常见的非功能性特征(如嵌入式服务器、安全性、度量、健康检查和外部化配置)。以下是 Spring Boot 的一些核心…...

大模型ChatGLM的部署与微调
前言:最近大模型太火了,导师让我看看能不能用到自己的实验中,就想着先微调一个chatGLM试试水,微调的过程并不难,难的的硬件条件跟不上,我试了一下lora微调,也算跑通了吧,虽然最后评估…...
全球七家半导体工厂建设受阻:英特尔、三星、台积电等面临延期挑战
过去两年间,半导体行业经历了市场衰退、复苏慢于预期以及资金紧缩等问题,英特尔、台积电和三星等主要企业虽然继续推进扩张计划,但不断调整和放缓工厂建设的步伐与时间表,以更好地服务于长期发展目标。据统计,全球范围…...
JavaScript错误;调试;“=”,“==”,“===”的区别
try...catch语句 try..catch语句是JavaScript中用来处理异常的一种方式。它允许我们在代码块中尝试执行可能会引发错误的代码,并在发生错误时捕获并处理异常。 下面是try..catch语句的基本语法: try {// 可能会引发错误的代码 } catch (error) {// 处理…...
thinkphp6的请求
由于笔者是刚入门thinkphp,所以学习时对照thinkphp的官网,各位读者也可以对照官网学习。还麻烦各位笔者一键三连,谢谢。 1.请求对象 当前的请求对象由think\Request类负责,该类不需要单独实例化调用,通常使用依赖注入…...

ant design vue 表格错位,表头错位
ant design vue 表格错位,表头错位 在官网中,我们可以看到下面图片的描述: 好的,我们按照官网来一波,前面都设置了固定宽度,娃哈哈就不设置了.会出现下面效果 为啥会多了一个竖线(因为按照官网来一波x:1300,这个1300太小的原因) 3.那我们把1300改成1600,1700试试,结果也不是…...

【小白向】微信小程序解密反编译教程
# 前言 最近笔者有做到微信小程序的渗透测试,其中有一个环节就是对微信小程序的反编译进行源码分析,所谓微信小程序反编译,就是将访问的小程序进行反向编译拿到部分源码,然后对源码进行安全审计,分析出其中可能存在的…...
Flutter基础 -- Dart 语言 -- 类抽象接口继承函数库
目录 1. 类 class 1.1 定义、使用类 1.2 构造函数 1.3 初始化列表 1.4 命名构造函数 1.5 重定向构造函数 1.6 callable 2. 类 get set 2.1 定义、使用 get set 2.2 简化 get set 2.3 业务场景 3. 静态 static 3.1 static 定义 3.2 函数内部访问 3.3 静态方法 3…...
【TB作品】msp430单片机,播放蜂鸣器音乐,天空之城
功能 msp430单片机,连接一个无源蜂鸣器,播放蜂鸣器音乐,天空之城。 适用于所有msp430单片机。 硬件 无源蜂鸣器,接单片机P1.5,使用vcc3.3v供电。 如果根据简谱修改音乐? //第一步 //首先修改music0 的变量&…...

C语言(数据存储)
Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,欢迎欢迎~~ 💥个人主页:小羊在奋斗 💥所属专栏:C语言 本系列文章为个人学习笔记,在这里撰写成文一…...

Linux shell编程学习笔记56:date命令——显示或设置系统时间与日期
0 前言 2024年的网络安全检查又开始了,对于使用基于Linux的国产电脑,我们可以编写一个脚本来收集系统的有关信息。在收集的信息中,应该有一条是搜索信息的时间。 1. date命令 的功能、格式和选项说明 我们可以使用命令 date --help 来查看 d…...
Realsense的一些事情
Realsense的一些事情 librealsense的安装 官网教程: apt 安装教程: https://github.com/IntelRealSense/librealsense/blob/master/doc/distribution_linux.md自行clone并编译教程: https://github.com/IntelRealSense/librealsense/blo…...

CISCN 2023 初赛 被加密的生产流量
题目附件给了 modbus.pcap 存在多个协议 但是这道题多半是 考 modbus 会发现 每次的 Query 末尾的两个字符 存在规律 猜测是base家族 可以尝试提取流量中的数据 其中Word Count字段中的22871 是10进制转16进制在转ascii字符串 先提取 过滤器判断字段 tshark -r modbus.pcap …...
初识C语言第三十天——设计三子棋游戏
目录 一.设计游戏框架 1.打印游戏菜单 2.输入选择判断(玩游戏/游戏结束/输入错误重新输入) 二、玩游戏过程设计 1.设计棋格存放棋子——二维数组 2.初始化棋盘——初始化为空格 3.打印棋盘——本质上就是打印数组 4.游戏过程——1.玩家走棋 2.…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...