搜尋
首頁Javajava教程SpringBoot如何啟動並初始化執行sql腳本

    SpringBoot啟動並初始化執行sql腳本

    如果我們想在專案啟動的時候去執行一些sql腳本該怎麼辦呢,SpringBoot給我們提供了這個功能,可以在啟動SpringBoot的專案時,執行腳本,下面我們來看看。

    我們先看一下原始碼

    SpringBoot如何啟動並初始化執行sql腳本

    boolean createSchema() {
    	//会从application.properties或application.yml中获取sql脚本列表
    	List<Resource> scripts = this.getScripts("spring.datasource.schema", this.properties.getSchema(), "schema");
        if (!scripts.isEmpty()) {
        	if (!this.isEnabled()) {
            	logger.debug("Initialization disabled (not running DDL scripts)");
                return false;
            }
    
            String username = this.properties.getSchemaUsername();
            String password = this.properties.getSchemaPassword();
            //运行sql脚本
            this.runScripts(scripts, username, password);
        }
        return !scripts.isEmpty();
    }
    private List<Resource> getScripts(String propertyName, List<String> resources, String fallback) {
    	if (resources != null) {
    		//如果配置文件中配置,则加载配置文件
        	return this.getResources(propertyName, resources, true);
       	} else {
       		//指定schema要使用的Platform(mysql、oracle),默认为all
        	String platform = this.properties.getPlatform();
            List<String> fallbackResources = new ArrayList();
            //如果配置文件中没配置,则会去类路径下找名称为schema或schema-platform的文件
            fallbackResources.add("classpath*:" + fallback + "-" + platform + ".sql");
           	fallbackResources.add("classpath*:" + fallback + ".sql");
           	return this.getResources(propertyName, fallbackResources, false);
        }
    }
    private List<Resource> getResources(String propertyName, List<String> locations, boolean validate) {
    	List<Resource> resources = new ArrayList();
    	Iterator var5 = locations.iterator();
    
        while(var5.hasNext()) {
        	String location = (String)var5.next();
            Resource[] var7 = this.doGetResources(location);
            int var8 = var7.length;
    
            for(int var9 = 0; var9 < var8; ++var9) {
            	Resource resource = var7[var9];
            	//验证文件是否存在
            	if (resource.exists()) {
                	resources.add(resource);
               	} else if (validate) {
                	throw new InvalidConfigurationPropertyValueException(propertyName, resource, "The specified resource does not exist.");
                }
            }
        }
        return resources;
    }

    從原始碼觀察,大致知道是什麼意思了,SpringBoot預設會從類別路徑下去找腳本文件,但是類別路徑下只能放規定名稱為schema或schema-platform的腳本文件,如果我們想要分好多個腳本文件,那麼這種方式就不合適了,那麼就需要我們在application.properties或application.yml中去配置腳本列表,那麼這個初始化腳本操作能不能在設定檔中控制呢,可以的,有一個initialization-mode屬性,可以設定三個值,always為始終執行初始化,embedded只初始化記憶體資料庫(預設值) ,如h3等,never為不執行初始化。

    spring:
      datasource:
        username: root
        password: liuzhenyu199577
        url: jdbc:mysql://localhost:3306/jdbc
        driver-class-name: com.mysql.cj.jdbc.Driver
        initialization-mode: always

    下面我們驗證這兩種方式

    1.預設放置schema或schema-platform的腳本檔案

    SpringBoot如何啟動並初始化執行sql腳本##

    CREATE TABLE IF NOT EXISTS department (ID VARCHAR(40) NOT NULL, NAME VARCHAR(100), PRIMARY KEY (ID));

    查看資料庫沒有department這個表,接下來我們啟動程式

    SpringBoot如何啟動並初始化執行sql腳本

    啟動之後,我們再看一下,就執行了

    SpringBoot如何啟動並初始化執行sql腳本

    2.設定檔中指定多個sql腳本

    spring:
      datasource:
        username: root
        password: liuzhenyu199577
        url: jdbc:mysql://localhost:3306/jdbc
        driver-class-name: com.mysql.cj.jdbc.Driver
        initialization-mode: always
        schema:
          - classpath:department.sql
          - classpath:department2.sql
          - classpath:department3.sql

    SpringBoot如何啟動並初始化執行sql腳本

    三個sql腳本都是插入語句

    INSERT INTO department (ID,NAME) VALUES (&#39;1&#39;,&#39;2&#39;)
    INSERT INTO department (ID,NAME) VALUES (&#39;2&#39;,&#39;3&#39;)
    INSERT INTO department (ID,NAME) VALUES (&#39;3&#39;,&#39;4&#39;)

    現在表中無任何數據,接下來我們啟動程式

    SpringBoot如何啟動並初始化執行sql腳本

    啟動之後,我們再看一下,表中就有了三個資料

    SpringBoot如何啟動並初始化執行sql腳本

    就是SpringBoot啟動並初始化sql腳本的步驟

    SpringBoot專案在啟動時執行指定sql檔

    1. 啟動時執行

    當有在專案啟動時先執行指定的sql語句的需求時,可以在resources資料夾下新增需要執行的sql文件,文件中的sql語句可以是DDL腳本或DML腳本,然後在組態加入對應的組態即可,如下:

    spring:
      datasource:
        schema: classpath:schema.sql # schema.sql中一般存放的是DDL脚本,即通常为创建或更新库表的脚本 data: classpath:data.sql # data.sql中一般是DML脚本,即通常为数据插入脚本

    2. 執行多個sql檔

    spring.datasource.schema和spring.datasource.data都是支援接收一個列表,所以當需要執行多個sql檔時,可以使用以下設定:

    spring:
      datasource:
        schema: classpath:schema_1.sql, classpath:schema_2.sql data: classpath:data_1.sql, classpath:data_2.sql 或 spring: datasource: schema: - classpath:schema_1.sql - classpath:schema_2.sql data: - classpath:data_1.sql - classpath:data_2.sql

    3. 不同運行環境執行不同腳本

    一般情況下,都會有多個運行環境,例如開發、測試、生產等。而不同運行環境通常需要執行的sql會有所不同。為解決這個問題,可以使用通配符來實現。

    建立不同環境的資料夾

    在resources資料夾建立不同環境對應的資料夾,如dev/、sit/、prod/。

    設定

    application.yml

    spring:
      datasource:
        schema: classpath:${spring.profiles.active:dev}/schema.sql 
        data: classpath:${spring.profiles.active:dev}/data.sql

    附註:${}通配符支援預設值。如上面的配置中的${spring.profiles.active:dev},其中分號前是取屬性spring.profiles.active的值,而當該屬性的值不存在,則使用分號後面的值,即dev。

    bootstrap.yml

    spring:
      profiles:
        active: dev # dev/sit/prod等。分别对应开发、测试、生产等不同运行环境。

    提醒:spring.profiles.active屬性一般在bootstrap.yml或bootstrap.properties中配置。

    4. 支援不同資料庫

    因為不同資料庫的語法有所差異,所以要實現同樣的功能,不同資料庫的sql語句可能會不一樣,所以可能會有多份不同的sql檔。當需要支援不同資料庫時,可以使用以下配置:

    spring:
      datasource:
        schema: classpath:${spring.profiles.active:dev}/schema-${spring.datasource.platform}.sql
        data: classpath:${spring.profiles.active:dev}/data-${spring.datasource.platform}.sql
        platform: mysql

    提醒:platform屬性的預設值是'all',所以當有在不同資料庫切換的情況下才使用如上配置,因為預設值的情況下,spring boot會自動偵測目前使用的資料庫。

    附註:此時,以dev允許環境為例,resources/dev/資料夾下必須存在下列檔案:schema-mysql.sql和data-mysql.sql。

    5. 避坑

    5.1 坑

    當在執行的sql檔中存在預存程序或函數時,在啟動專案時會報錯。

    例如現在有這樣的需求:專案啟動時,掃描某張表,當表記錄數為0時,插入多筆記錄;大於0時,跳過。

    schema.sql檔案腳本如下:

    -- 当存储过程`p1`存在时,删除。
    drop procedure if exists p1;
     
    -- 创建存储过程`p1`
    create procedure p1() 
    begin declare row_num int; select count(*) into row_num from `t_user`; if row_num = 0 then INSERT INTO `t_user`(`username`, `password`) VALUES (&#39;zhangsan&#39;, &#39;123456&#39;); end if; end; -- 调用存储过程`p1` call p1(); drop procedure if exists p1;

    啟動項目,報錯,原因如下:

    Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'create procedure p1() begin declare row_num int' at line 1

    大致的意思是:'create procedure p1() begin declare row_num int'这一句出现语法错误。刚看到这一句,我一开始是懵逼的,吓得我赶紧去比对mysql存储过程的写法,对了好久都发现没错,最后看到一篇讲解spring boot配置启动时执行sql脚本的文章,发现其中多了一项配置:spring.datasource.separator=$$。然后看源码发现,spring boot在解析sql脚本时,默认是以';'作为断句的分隔符的。看到这里,不难看出报错的原因,即:spring boot把'create procedure p1() begin declare row_num int'当成是一条普通的sql语句。而我们需要的是创建一个存储过程。

    5.2 解决方案

    修改sql脚本的断句分隔符。如:spring.datasource.separator=$$。然后把脚本改成:

    -- 当存储过程`p1`存在时,删除。
    drop procedure if exists p1;$$
     
    -- 创建存储过程`p1`
    create procedure p1() 
    begin declare row_num int; select count(*) into row_num from `t_user`; if row_num = 0 then INSERT INTO `t_user`(`username`, `password`) VALUES (&#39;zhangsan&#39;, &#39;123456&#39;); end if; end;$$ -- 调用存储过程`p1` call p1();$$ drop procedure if exists p1;$$

    5.3 不足

    因为sql脚本的断句分隔符从';'变成'$$',所以可能需要在DDL、DML语句的';'后加'$$',不然可能会出现将整个脚本当成一条sql语句来执行的情况。比如:

    -- DDL
    CREATE TABLE `table_name` (
      -- 字段定义
      ... 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;$$
     
    -- DML
    INSERT INTO `table_name` VALUE(...);$$

    以上是SpringBoot如何啟動並初始化執行sql腳本的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述
    本文轉載於:亿速云。如有侵權,請聯絡admin@php.cn刪除
    如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

    本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

    如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

    本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

    如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

    本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

    如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

    本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

    Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

    Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

    See all articles

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    AI Hentai Generator

    AI Hentai Generator

    免費產生 AI 無盡。

    熱門文章

    R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
    3 週前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.最佳圖形設置
    3 週前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.如果您聽不到任何人,如何修復音頻
    3 週前By尊渡假赌尊渡假赌尊渡假赌
    WWE 2K25:如何解鎖Myrise中的所有內容
    3 週前By尊渡假赌尊渡假赌尊渡假赌

    熱工具

    MinGW - Minimalist GNU for Windows

    MinGW - Minimalist GNU for Windows

    這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

    PhpStorm Mac 版本

    PhpStorm Mac 版本

    最新(2018.2.1 )專業的PHP整合開發工具

    SublimeText3 Linux新版

    SublimeText3 Linux新版

    SublimeText3 Linux最新版

    SecLists

    SecLists

    SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

    Atom編輯器mac版下載

    Atom編輯器mac版下載

    最受歡迎的的開源編輯器