Spring Boot初始化數據庫和導入數據

0. 前言


本文參考的主要是Spring Boot 1.5.8官方文檔,寫這篇文章的原因是,在做Spring Boot的項目時,跑Unit Test,需要利用DDL重新建表,以及要在建表后想通過Spring Boot 或者Hibernate自動插入基礎測試數據。

1. 數據庫初始化


Spring Boot提供兩種方法來定義數據庫的表結構以及添加數據。

  1. 使用Hibernate提供的工具來創建表結構,該機制會自動搜索@Entity實體對象并創建對應的表,然后使用import.sql文件導入測試數據;
  2. 利用舊的Spring JDBC,通過schema.sql文件定義數據庫的表結構、通過data.sql導入測試數據。

JPA有個生成DDL的特性,并且可以設置為在數據庫啟動時運行,這可以通過兩個外部屬性進行控制:

  1. spring.jpa.generate-ddl ( boolean )控制該特性的關閉和開啟,跟實現者沒關系。
  2. 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屬性被設置為 createcreate-drop)。這在demos或測試時很有用,但在生產環境中可能不期望這樣。這是Hibernate的特性,和Spring沒有一點關系。

2.2 利用Spring JDBC實現數據庫初始化

Spring Boot可以自動創建DataSource的模式(DDL腳本)并初始化它(DML腳本),并從標準的位置 schema.sqldata.sql (位于classpath根目錄)加載SQL,腳本的位置可以通過設置 spring.datasource.schemaspring.datasource.data 來改變。此外,Spring Boot將加載 schema-${platform}.sqldata-${platform}.sql 文件(如果存在),在這里 platformspring.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. 實驗

本文的實驗會用兩種方式實現數據庫建表以及插入數據的操作:

  1. 使用Hibernate提供的工具來創建表結構;
  2. 利用舊的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;
 }

}

  1. 新建application.yml,設置spring.hibernate.ddl-autocreate,該機制會自動搜索@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項目:同上

  1. 新建application.yml,如果想要在一個JPA應用中使用 schema.sql ,那如果Hibernate試圖創建相同的>表, ddl-auto=create-drop 將導致錯誤產生。設置spring.hibernate.ddl-autonone,可以避免錯誤的>產生。
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
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,237評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,957評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,248評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,356評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,081評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,485評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,534評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,720評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,263評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,025評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,204評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,787評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,461評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,874評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,105評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,945評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,205評論 2 375

推薦閱讀更多精彩內容