spring boot 項目在啟動時執行指定sql文件


參考博客: https://www.jianshu.com/p/88125f1cf91c

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.schemaspring.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.ymlbootstrap.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.sqldata-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 ('zhangsan', '123456'); 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 ('zhangsan', '123456'); end if; end;$$ -- 調用存儲過程`p1` call p1();$$ drop procedure if exists p1;$$ 

5.3 不足

因為sql腳本的斷句分隔符從';'變成'$$',所以可能需要在DDLDML語句的';'后加'$$',不然可能會出現將整個腳本當成一條sql語句來執行的情況。比如:

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM