package com.gitee.swsk33.sqlinitdemo.config;
import cn.hutool.core.io.resource.ClassPathResource;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 用于第一次啟動時,初始化數(shù)據(jù)庫的配置類
*/
@Slf4j
@Configuration
public class DatabaseInitialize {
/**
* 讀取連接地址
*/
@Value("${spring.datasource.url}")
private String url;
/**
* 讀取用戶名
*/
@Value("${spring.datasource.username}")
private String username;
/**
* 讀取密碼
*/
@Value("${spring.datasource.password}")
private String password;
/**
* 檢測當(dāng)前連接的庫是否存在(連接URL中的數(shù)據(jù)庫)
*
* @return 當(dāng)前連接的庫是否存在
*/
private boolean currentDatabaseExists() {
// 嘗試以配置文件中的URL建立連接
try {
Connection connection = DriverManager.getConnection(url, username, password);
connection.close();
} catch (SQLException e) {
// 若連接拋出異常則說明連接URL中指定數(shù)據(jù)庫不存在
return false;
}
// 正常情況下說明連接URL中數(shù)據(jù)庫存在
return true;
}
/**
* 執(zhí)行SQL腳本
*
* @param path SQL腳本文件的路徑
* @param isClasspath SQL腳本路徑是否是classpath路徑
* @param connection 數(shù)據(jù)庫連接對象,通過這個連接執(zhí)行腳本
*/
private void runSQLScript(String path, boolean isClasspath, Connection connection) {
try (InputStream sqlFileStream = isClasspath ? new ClassPathResource(path).getStream() : new FileInputStream(path)) {
BufferedReader sqlFileStreamReader = new BufferedReader(new InputStreamReader(sqlFileStream, StandardCharsets.UTF_8));
// 創(chuàng)建SQL腳本執(zhí)行器對象
ScriptRunner scriptRunner = new ScriptRunner(connection);
// 使用SQL腳本執(zhí)行器對象執(zhí)行腳本
scriptRunner.runScript(sqlFileStreamReader);
// 最后關(guān)閉文件讀取器
sqlFileStreamReader.close();
} catch (Exception e) {
log.error("讀取文件或者執(zhí)行腳本失敗!");
e.printStackTrace();
}
}
/**
* 執(zhí)行SQL腳本以創(chuàng)建數(shù)據(jù)庫
*/
private void createDatabase() {
try {
// 修改連接語句,重新建立連接
// 重新建立的連接不再連接到指定庫,而是直接連接到整個MySQL
// 使用URI類解析并拆解連接地址,重新組裝
URI databaseURI = new URI(url.replace("jdbc:", ""));
// 得到連接地址中的數(shù)據(jù)庫平臺名(例如mysql)
String databasePlatform = databaseURI.getScheme();
// 得到連接地址和端口
String hostAndPort = databaseURI.getAuthority();
// 得到連接地址中的庫名
String databaseName = databaseURI.getPath().substring(1);
// 組裝新的連接URL,不連接至指定庫
String newURL = "jdbc:" + databasePlatform + "://" + hostAndPort + "/";
// 重新建立連接
Connection connection = DriverManager.getConnection(newURL, username, password);
Statement statement = connection.createStatement();
// 執(zhí)行SQL語句創(chuàng)建數(shù)據(jù)庫
statement.execute("create database if not exists `" + databaseName + "`");
// 關(guān)閉會話和連接
statement.close();
connection.close();
log.info("創(chuàng)建數(shù)據(jù)庫完成!");
} catch (URISyntaxException e) {
log.error("數(shù)據(jù)庫連接URL格式錯誤!");
throw new RuntimeException(e);
} catch (SQLException e) {
log.error("連接失??!");
throw new RuntimeException(e);
}
}
/**
* 該方法用于檢測數(shù)據(jù)庫是否需要初始化,如果是則執(zhí)行SQL腳本進(jìn)行初始化操作
*/
@PostConstruct
private void initDatabase() {
log.info("開始檢查數(shù)據(jù)庫是否需要初始化...");
// 檢測當(dāng)前連接數(shù)據(jù)庫是否存在
if (currentDatabaseExists()) {
log.info("數(shù)據(jù)庫存在,不需要初始化!");
return;
}
log.warn("數(shù)據(jù)庫不存在!準(zhǔn)備執(zhí)行初始化步驟...");
// 先創(chuàng)建數(shù)據(jù)庫
createDatabase();
// 然后再次連接,執(zhí)行腳本初始化庫中的表格
try (Connection connection = DriverManager.getConnection(url, username, password)) {
runSQLScript("/create-table.sql", true, connection);
log.info("初始化表格完成!");
} catch (Exception e) {
log.error("初始化表格時,連接數(shù)據(jù)庫失??!");
e.printStackTrace();
}
}
}
文章來源地址http://www.zghlxwxcb.cn/news/detail-650198.html
文章來源:http://www.zghlxwxcb.cn/news/detail-650198.html
到了這里,關(guān)于Spring Boot實現(xiàn)第一次啟動時自動初始化數(shù)據(jù)庫流程詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!