0. 前言
本文參考的主要是Spring Boot 1.5.8官方文檔,寫這篇文章的原因是,在做Spring Boot的項目時,跑Unit Test,需要利用DDL重新建表,以及要在建表后想通過Spring Boot 或者Hibernate自動插入基礎測試數據。
1. 數據庫初始化
Spring Boot提供兩種方法來定義數據庫的表結構以及添加數據。
- 使用Hibernate提供的工具來創建表結構,該機制會自動搜索@Entity實體對象并創建對應的表,然后使用import.sql文件導入測試數據;
- 利用舊的Spring JDBC,通過schema.sql文件定義數據庫的表結構、通過data.sql導入測試數據。
JPA有個生成DDL的特性,并且可以設置為在數據庫啟動時運行,這可以通過兩個外部屬性進行控制:
spring.jpa.generate-ddl
( boolean )控制該特性的關閉和開啟,跟實現者沒關系。spring.jpa.hibernate.ddl-auto
( enum )是一個Hibernate特性,用于更細力度的控制該行為。
2.1 利用Hibernate實現數據庫初始化
spring.jpa.hibernate.ddl-auto
可以顯式設置spring.jpa.hibernate.ddl-auto
,標準的Hibernate屬性值有none , validate , update , create , create-drop
。
Spring Boot 會根據數據庫是否是內嵌類型,選擇一個默認值。具體的關系見下圖:
內嵌類型 數據庫名稱 默認值 內嵌 hsqldb, h2, derby create-drop 非內嵌 余下的所有數據庫 none
spring.jpa.hibernate.ddl-auto
的四個屬性的含義見下表:
屬性值 作用 create 每次加載hibernate時都會刪除上一次的生成的表,然后根據你的model類再重新來生成新表,哪怕兩次沒有任何改變也要這樣執行,這就是導致數據庫表數據丟失的一個重要原因。 create-drop 每次加載hibernate時根據model類生成表,但是sessionFactory一關閉,表就自動刪除。 update 最常用的屬性,第一次加載hibernate時根據model類會自動建立起表的結構(前提是先建立好數據庫),以后加載hibernate時根據 model類自動更新表結構,即使表結構改變了但表中的行仍然存在不會刪除以前的行。要注意的是當部署到服務器后,表結構是不會被馬上建立起來的,是要等應用第一次運行起來后才會。 validate 每次加載hibernate時,驗證創建數據庫表結構,只會和數據庫中的表進行比較,不會創建新表,但是會插入新值。 此外,啟動時處于classpath根目錄下的
import.sql
文件會被執行(前提是ddl-auto屬性被設置為create
或create-drop
)。這在demos或測試時很有用,但在生產環境中可能不期望這樣。這是Hibernate的特性,和Spring沒有一點關系。
2.2 利用Spring JDBC實現數據庫初始化
Spring Boot可以自動創建DataSource的模式(DDL腳本)并初始化它(DML腳本),并從標準的位置
schema.sql
和data.sql
(位于classpath根目錄)加載SQL,腳本的位置可以通過設置spring.datasource.schema
和spring.datasource.data
來改變。此外,Spring Boot將加載schema-${platform}.sql
和data-${platform}.sql
文件(如果存在),在這里platform
是spring.datasource.platform
的值,比如,可以將它設置為數據庫的供應商名稱( hsqldb , h2 , oracle , mysql , postgresql 等)。
Spring Boot默認啟用Spring JDBC初始化快速失敗特性,所以如果腳本導致異常產生,那應用程序將啟動失敗。能通過設置spring.datasource.continue-on-error
的值來控制是否繼續。一旦應用程序成熟并被部署了很多次,那該設置就很有用,例如,插入失敗時意味著數據已經存在,也就沒必要阻止應用繼續運行。
如果想要在一個JPA應用中使用 schema.sql ,那如果Hibernate試圖創建相同的表,ddl-auto=create-drop
將導致錯誤產生。為了避免那些錯誤,可以將ddl-auto
設置為""或 none 。
最后要提的一點是,spring.datasource.initialize=false
可以阻止數據初始化。
3. 實驗
本文的實驗會用兩種方式實現數據庫建表以及插入數據的操作:
- 使用Hibernate提供的工具來創建表結構;
- 利用舊的Spring JDBC,通過schema.sql文件定義數據庫的表結構、通過data.sql導入測試數據。
3.1 Hibernate 數據表初始化
0.建立maven項目,項目結構如下圖所示:
項目結構
pom.xml配置如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" >xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 >http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.syf.demo</groupId> <artifactId>spring-boot-jpa</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.5.8.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>
1.定義實體對象:Organization.java
@Entity @Table(name = "organization") public class Organization implements Serializable{ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(name = "company_name", nullable = false, length = 30) private String companyName; @Column(name = "active", nullable = false) private boolean active; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getCompanyName() { return companyName; } public void setCompanyName(String companyName) { this.companyName = companyName; } public boolean isActive() { return active; } public void setActive(boolean active) { this.active = active; } }
- 新建application.yml,設置
spring.hibernate.ddl-auto
為create
,該機制會自動搜索@Entity實體對象>(orgnization類)并創建對應的表,然后使用import.sql文件導入測試數據,
注意!注意!注意!并非所有的spring.hibernate.ddl-auto
的值都會觸發import.sql文件導入測試數據,只有當spring.hibernate.ddl-auto
的值為create, create-drop
才會,不然還是執行data.sql,不信的話可以把spring.hibernate.ddl-auto
改為update,然后再classpath下加上data.sql,你會發現執行的還是data.sql的內容。spring: application: name: spring-boot-database-initialization-hibernate jpa: generate-ddl: false show-sql: true hibernate: ddl-auto: create datasource: database: MYSQL continue-on-error: false driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/syf?useSSL=false username: root password: 123456 server: port: 9090
3.import.sql
INSERT INTO organization (company_name, active) VALUES ('Hibernate IBM', true), ('Hibernate MS', >true);
4.測試程序
@SpringBootApplication public class AppHibernate { public static void main(String[] args) { SpringApplication.run(AppHibernate.class, args); } }
結果:
結果.png
從圖中可以看出數據表自動建立,并且插入了數據。
3.2 Spring JDBC 數據表初始化
該方案通過schema.sql文件定義數據庫的表結構、通過data.sql導入測試數據。
0.建立maven項目:同上
- 新建application.yml,如果想要在一個JPA應用中使用 schema.sql ,那如果Hibernate試圖創建相同的>表, ddl-auto=create-drop 將導致錯誤產生。設置
spring.hibernate.ddl-auto
為none
,可以避免錯誤的>產生。spring: application: name: spring-boot-jpa jpa: generate-ddl: false show-sql: true hibernate: ddl-auto: none datasource: continue-on-error: false driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/syf?useSSL=false username: root password: 123456 server: port: 9090
2.schema.sql
DROP TABLE IF EXISTS `organization`; CREATE TABLE `organization` ( `id` bigint(20) NOT NULL PRIMARY KEY AUTO_INCREMENT, `active` bit(1) NOT NULL, `company_name` varchar(30) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3.data.sql
/*mock data***/ INSERT INTO organization (company_name, active) VALUES ('JDBC IBM', true), ('JDBC MS', true);
4.結果:
結果.png
從圖中可以看出數據表自動建立,并且插入了數據。
4.代碼
該項目的源碼參考如下鏈接:Github 地址
項目 名稱 Spring JDBC 數據表初始化 spring-boot-database-initialization-jdbc Hibernate 數據表初始化 spring-boot-database-initialization-hibernate