Spring容器初始化之前,利用SpringBoot监听器做一些数据库方面的检查

之所以把数据库的连接、结构、最小初始化等检查项放到SpringBoot监听器而不是Spring容器的初始过程。是有原因的。
1:SpringBoot监听器是SpringBoot初始化过程中,最先被执行的那一批周期函数。
2:数据库连接测试能很快的获得结果。
3:Spring容器初始化时,里面的ApplicationListener,ApplicationRunner,初始化方法等有部分实现是异步预热缓存数据。如果不前置检查数据表结构,很容易报sql异常。当产品有更新表结构时,项目发布时,很容易出现该问题。

public class PrepareTableCheckListener implements SpringApplicationRunListener {private static List<String> MYSQL_PRODUCT_NAMES = new ArrayList<>();static {MYSQL_PRODUCT_NAMES.add("kingbase8");MYSQL_PRODUCT_NAMES.add("mysql");}public PrepareTableCheckApplicationRunListener(SpringApplication application, String[] args) {}@Overridepublic void contextPrepared(ConfigurableApplicationContext context) {ConfigurableEnvironment environment = context.getEnvironment();String jdbcDriver = environment.getProperty("spring.datasource.driver-class-name");String jdbcUrl = environment.getProperty("spring.datasource.url");String jdbcUserName = environment.getProperty("spring.datasource.username");String jdbcUserPassword = environment.getProperty("spring.datasource.password");String testNetworkSQL = environment.getProperty("spring.datasource.hikari.connection-test-query");if (null == jdbcUrl || null == jdbcUserPassword || null == jdbcUserName) {return;}loadDriverClass(jdbcDriver);// 数据库连接检查DriverManager.setLoginTimeout(2);try (Connection conn = DriverManager.getConnection(jdbcUrl, jdbcUserName, jdbcUserPassword)) {Statement statement = conn.createStatement();statement.execute(testNetworkSQL);} catch (Exception e) {log.warn("+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");log.warn("...................★");log.warn("..................▍..★");log.warn("..................▍.一 .☆");log.warn("................. ▍ ..帆. ★");log.warn("..................▍ ... 风. ☆");log.warn("..................▍ ... ..顺. ★");log.warn("................. ▍.万 事 如 意. ☆");log.warn("..................▍☆ .★ .☆ .★. ☆");log.warn("..................▍");log.warn("..▍∵ ☆ ★...▍▍....█▍ ☆ ★∵▍..");log.warn("◥█▅▅██▅▅██▅▅▅▅▅███◤");log.warn(".◥███████████████◤");log.warn("~~~~◥█████████████◤~~~~");log.warn("~~~~~~~~~~~~~~~~~~~~~~~~~");log.warn("~~~哦豁,连不上数据库,哈哈哈哈哈~~~~~~~");log.warn("~~~~~~~~~~~~~~~~~~~~~~~~~");log.warn("+jdbcDriver={}", jdbcDriver);log.warn("+jdbcUrl={}", jdbcUrl);log.warn("+jdbcUserName={}", jdbcUserName);log.warn("+jdbcUserPassword={}", jdbcUserPassword);log.warn("+testNetworkSQL={}", testNetworkSQL);log.warn("+exception class =" + e.getClass().getName());log.warn("+exception message =" + e.getMessage());log.warn("+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");System.exit(0);}// 预定义表结构检查Set<String> prepareSqls;String urlLower = jdbcUrl.toLowerCase();if (ZYListUtils.anyMatch(MYSQL_PRODUCT_NAMES, urlLower::contains)) {prepareSqls = readSql("db_prepare_mysql");} else {prepareSqls = readSql("db_prepare_oracle");}if (prepareSqls.isEmpty()) {return;}try (Connection conn = DriverManager.getConnection(jdbcUrl, jdbcUserName, jdbcUserPassword)) {conn.setAutoCommit(true);Statement stmt = conn.createStatement();for (String prepareSql : prepareSqls) {try {stmt.executeUpdate(prepareSql);} catch (Exception e) {log.warn("execute table check sql 【{}】 false ,the column or table may exit!", prepareSql);}}} catch (Exception e) {log.warn("execute table check sql  false ,the Connection get false!");}}public Set<String> readSql(String dir) {Set<String> sqls = new HashSet<>();Resource[] resources;try {resources = new PathMatchingResourcePatternResolver().getResources("classpath*:/" + dir + "/**/*.sql");} catch (IOException e) {return sqls;}if (resources.length == 0) {return sqls;}for (Resource resource : resources) {try (InputStream inputStream = resource.getInputStream()) {String sqlText = IoUtil.read(inputStream, Charset.defaultCharset());String[] sqlArr = sqlText.split(";");for (String sql : sqlArr) {List<String> sqlItems = new ArrayList<>();StringTokenizer stringTokenizer = new StringTokenizer(sql);while (stringTokenizer.hasMoreTokens()) {String item = stringTokenizer.nextToken();sqlItems.add(item);}String finalSql = ZYStrUtils.join(sqlItems, " ");sqls.add(finalSql);}} catch (Exception e) {log.warn("sql read false");}}return sqls;}private void loadDriverClass(String jdbcDriver) {try {Class.forName(jdbcDriver);} catch (ClassNotFoundException ex) {throw new LocalException("数据库驱动文件不存在,请检查是否缺少驱动包或spring.datasource.driver-class-name配置不正确!");}}
}

spring.factories配置

org.springframework.boot.SpringApplicationRunListener =xxx.framework.mybatis.PrepareTableCheckListener 

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

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

相关文章

FME学习之旅---day24

我们付出一些成本&#xff0c;时间的或者其他&#xff0c;最终总能收获一些什么。 高级地理数据库 教程&#xff1a;地理数据库转换 上述教程包括 如何使用 Esri 模板地理数据库 该内容在FME学习之旅day19 已经学习过 使用地理数据库属性域&#xff1a;编写编码属性域 属…

机器学习实训 Day1(线性回归练习)

线性回归练习 Day1 手搓线性回归 随机初始数据 import numpy as np x np.array([56, 72, 69, 88, 102, 86, 76, 79, 94, 74]) y np.array([92, 102, 86, 110, 130, 99, 96, 102, 105, 92])from matplotlib import pyplot as plt # 内嵌显示 %matplotlib inlineplt.scatter…

古月·ROS2入门21讲——学习笔记(一)核心概念部分1-14讲

讲解视频地址&#xff1a;1.ROS和ROS2是什么_哔哩哔哩_bilibili 笔记分为上篇核心概念部分和下篇常用工具部分 下篇&#xff1a;古月ROS2入门21讲——学习笔记&#xff08;二&#xff09;常用工具部分15-21讲-CSDN博客 目录 第一讲&#xff1a;ROS/ROS2是什么 1. ROS的诞生…

Python-GEE遥感云大数据分析、管理与可视化及多领域案例实践应用

随着航空、航天、近地空间遥感平台的持续发展&#xff0c;遥感技术近年来取得显著进步。遥感数据的空间、时间、光谱分辨率及数据量均大幅提升&#xff0c;呈现出大数据特征。这为相关研究带来了新机遇&#xff0c;但同时也带来巨大挑战。传统的工作站和服务器已无法满足大区域…

海外代理IP在跨境电商中发挥什么作用?

在我国跨境电商的发展中&#xff0c;海外代理IP的应用日益广泛&#xff0c;它不仅帮助商家成功打入国际市场&#xff0c;还为他们在多变的全球电商竞争中保持优势。下面是海外代理IP在跨境电商中五个关键的应用场景。 1、精准的市场分析 了解目标市场的消费者行为、产品趋势以…

金蝶云星空与泛微OA对接案例-实现流程一体化

摘要&#xff1a;在企业数字化中&#xff0c;集成内部各业务系统以实现数据共享与流程协同&#xff0c;已成为提升运营效率、优化决策的重要选择。本文将以某企业成功实现金蝶云星空与泛微OA系统对接为例&#xff0c;详细解析双方在人员信息、组织架构、销售合同、付款申请、报…

Java中数组的使用

在Java编程中&#xff0c;数组是一种非常重要的数据结构&#xff0c;它允许我们存储相同类型的多个元素。对于初学者来说&#xff0c;理解数组的基本概念、初始化、遍历、默认值以及内存分配和使用注意事项是非常关键的。 一、数组的概念 数组是一个可以容纳多个相同类型数据…

es 深入了解和索引生命周期管理

1.1 目标人群 适用人员&#xff1a;使用过ES (elasticsearch), 对 ES 有初步的了解&#xff0c;想要深一步深入学习的人 知识点&#xff1a;以 ES 索引生命周期为知识点&#xff0c;这一个月查看文档的初步收集 1.es 结构初识。 2. es 基础知识 3.es索引生命周期使用 1.3 ES…

快速探索随机树-RRT

文章目录 简介原理算法运动规划的变体和改进简介 快速探索随机树(RRT)是一种算法,旨在通过随机构建空间填充树来有效搜索非凸高维空间。该树是从搜索空间随机抽取的样本中逐步构建的,并且本质上偏向于向问题的大型未搜索区域生长。RRT 由 Steven M. LaValle 和 James J. K…

CommunityToolkit.Mvvm笔记---ObservableRecipient

ObservableRecipient 类型是可观察对象的基类&#xff0c;这些对象还充当消息收件人&#xff0c;是 ObservableObject 的扩展&#xff0c;它还对使用 IMessenger 类型提供内置支持。这使得在不直接引用其他组件的情况下&#xff0c;组件之间可以相互通信。在MVVM架构中&#xf…

面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!

时间片 超线程 上下文切换 切换查看 线程调度 引起线程上下文切换的因素 由于现在大多计算机都是多核CPU&#xff0c;多线程往往会比单线程更快&#xff0c;更能够提高并发&#xff0c;但提高并发并不意味着启动更多的线程来执行。更多的线程意味着线程创建销毁开销加大、…

AI系列:大语言模型的function calling

目录 大语言模型(LLM) 的function calling实验&#xff1a;OpenAI之function calling序列图&#xff1a;function calling如何工作详情: 对话内容参考代码 后续: 使用LangChain实现function calling参考 大语言模型(LLM) 的function calling 大语言模型(LLM)可以使用自然语言与…

Android中的Context

前言 在Android开发中&#xff0c;当我们要创建或启动四大组件时&#xff0c;不能通过简单的new关键字实现&#xff0c;而是要通过他们的上下文环境&#xff0c;也就是我们要讨论的Context。 Android的应用模型是基于组件的应用设计模式&#xff0c;而组件的运行需要一个完整…

python数据结构与算法之线性表

1、线性表 是一种由n个元素&#xff08;n> 0 &#xff09;数据元素组成的有限序列&#xff0c;所包含的元素数量通常被称为表的长度 n 0 的表被称为空表&#xff0c;线性表的数据元素可以单一也可以复杂&#xff0c;可以是整数&#xff0c;字符串&#xff0c;也可以是由几…

c---内置函数模拟(memset,memcmp,memcpy,memmove)

void* my_memset(void* s1, int zifu, int num) {//引用string.h assert(s1); void* ret &s1; while (num--) { *(char*)s1 (char)zifu; s1 (char*)s1 1; } return ret; } int my_memcmp(const void* s1,const void* s2,int num)…

python_31-32

目录 1.进程 2.同步进程&#xff1a; 3.守护进程&#xff1a; 1.进程 # ### 进程 process import os,time""" # ps -aux 查看进程号 # ps -aux | grep 2784 过滤查找2784这个进程# 强制杀死进程 kill -9 进程号# 获取当前进程号 res os.getpid() print(res)…

进程间通信--管道

1.有名管道 管道的分类:有名管道和无名管道 有名管道也成为命名管道.区别:有名管道在任意两个进程之间通信,无名管道在父子进程之间通信. 1.创建有名管道使用命令:mkfifo 2.打开管道:open(); 关闭管道:close(); 读数据:read(); 写入数据:write(); 2.有名管道来演示进程间通信:…

高光谱遥感数据处理与机器学习深度应用

高光谱遥感数据处理的基础、python开发基础、机器学习和应用实践。重点解释高光谱数据处理所涉及的基本概念和理论&#xff0c;旨在帮助学员深入理解科学原理。结合Python编程工具&#xff0c;专注于解决高光谱数据读取、数据预处理、高光谱数据机器学习等技术难题&#xff0c;…

将自己的项目上传至Git

一、安装Git 官网:Git (git-scm.com) 二、注册gitee 官网:工作台 - Gitee.com 进入“我的”出现以下界面 三、创建仓库 点击加号&#xff0c;新建仓库 根据自己的需求取名&#xff0c;描述仓库&#xff0c;开源还是私有&#xff0c;点击创建即可&#xff0c;点击我的即可…

[docker] 核心知识 - 容器/镜像的管理和操作

[docker] 核心知识 - 容器/镜像的管理和操作 想要查看完整的指令&#xff0c;可以通过 docker --help 列举所有的指令&#xff0c;这里会提到一些比较常用的核心指令 查看容器的状态 这个应该是最常用的指令&#xff0c;语法为 docker ps&#xff0c; ps 为 process status …