參考博客: 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.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 ('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
腳本的斷句分隔符從';'
變成'$$'
,所以可能需要在DDL
、DML
語句的';'
后加'$$'
,不然可能會出現將整個腳本當成一條sql
語句來執行的情況。比如:
-- DDL
CREATE TABLE `table_name` ( -- 字段定義 ... ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;$$ -- DML INSERT INTO `table_name` VALUE(...);$$