Spring Boot 學習筆記(1.2):如何在 Spring Boot 項目中使用 Mysql
本系列:
Spring Boot大大簡化了持久化任務,幾乎不需要寫SQL語句,之前我寫過一篇關于Mongodb的—— RESTful:Spring Boot with Mongodb 。
本文將會演示如何在Spring Boot項目中使用mysql數據庫。
1.建立數據庫連接(database connection)
在上篇文章中我們新建了一個Spring Boot應用程序,添加了jdbc和data-jpa等starters,以及一個h2數據庫依賴,這里我們將配置一個H2數據庫。
對于H2、HSQL或者Derby這類嵌入型數據庫,只要在pom文件中添加對應的依賴就可以,不需要額外的配置。當spring boot在classpath下發現某個數據庫依賴存在且在代碼中有關于 Datasource Bean 的定義時,就會自動創建一個數據庫連接。我們通過修改之前的bookpub程序說明這個問題,需要修改StartupRunner.java文件,代碼如下:
package org.test.bookpub; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import javax.sql.DataSource; public class StartupRunner implements CommandLineRunner { protected static final Logger logger = LoggerFactory.getLogger(StartupRunner.class); @Autowired private DataSource ds; @Override public void run(String... strings) throws Exception { logger.info("Datasource: " + ds.toString()); } }
啟動應用程序,可以看到如下輸出:driverClassName=org.h2.Driver;因此,可以證明,Spring Boot根據我們自動織入DataSource的代碼,自動創建并初始化了一個H2數據庫。不過,這個數據庫并沒什么用,因為存放其中的數據會在系統停止后就丟失。通過修改配置,我們可以將數據存放在磁盤上。關于H2數據庫的配置文件如下:
spring.datasource.url = jdbc:h2:~/test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE spring.datasource.username = sa spring.datasource.password =
然后啟動應用程序,并檢查你的home目錄下是否存在test.mv.db文件。通過“~/test”,就告訴Spring Boot,H2數據庫的數據會存放在test.mv.db這個文件中。
綜上,可以看出,Spring Boot試圖通過spring.datasource分組下的一系列配置項來簡化用戶對數據庫的使用,我們經常使用的配置項有:url,username,password以及driver-class-name等等。PS:driverClassName或者driver-class-name都可以,Spring Boot會在內部進行統一處理。
最常用的開源數據庫是Mysql,在Spring Boot通過下列配置項來配置mysql:
spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/springbootcookbook spring.datasource.username=root spring.datasource.password=
如果希望通過Hibernate依靠Entity類自動創建數據庫和數據表,則還需要加上配置項—— spring.jpa.hibernate.ddl-auto=create-drop 。PS:在生產環境中不要使用create-drop,這樣會在程序啟動時先刪除舊的,再自動創建新的,最好使用update;還可以通過設置 spring.jpa.show-sql = true 來顯示自動創建表的SQL語句,通過 spring.jpa.database = MYSQL 指定具體的數據,如果不明確指定Spring boot會根據classpath中的依賴項自動配置。
在Spring項目中,如果數據量比較簡單,我們可以考慮使用JdbcTemplate,而不是直接定義Datasource,配置jdbc的代碼如下:
@Autowired private JdbcTemplate jdbcTemplate;
只要定義了上面這個代碼,Spring Boot會自動創建一個Datasource對象,然后再創建一個jdbctemplate對象來管理datasource,通過jdbctemplate操作數據庫可以減少大量模板代碼。如果你對SpringBoot的原理感興趣,可以在org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration類中查看其具體實現。
2.創建數據倉庫服務(data repository service)
連接數據庫并直接執行SQL語句這種思路非常古老,早在很多年前就已經出現了ORM(Object Relational Mapping)框架來簡化這部分工作,最有名的是Hibernate,但是現在更火的好像是Mybatis。關于spring boot和Mybatis的整合,可以參考: mybatis-spring-boot 。我們這里使用Hibernate進行演示。我們將會增加一些實體類,這些實體類決定了數據庫的表結構,還要定義一個CrudRepository接口,用于操作數據。
示例程序是一個圖書管理系統,顯然,數據庫中應該具備以下領域對象(domain object):Book、Author、Reviewrs以及Publisher。首先在src/main/java/org/test/bookpub下建立包domain,然后再在這個包下建立相應的實體類。具體代碼列舉如下(為了節省空間,省去了getter和setter):
- Book.java
package com.test.bookpub.domain; import javax.persistence.*; import java.util.List; @Entity public class Book { @Id @GeneratedValue private Long id; private String isbn; private String title; private String description; @ManyToOne private Author author; @ManyToOne private Publisher publisher; @ManyToMany private List reviewers; protected Book() { } public Book(Author author, String isbn, Publisher publisher, String title) { this.author = author; this.isbn = isbn; this.publisher = publisher; this.title = title; } }
- Author.java
package com.test.bookpub.domain; import javax.persistence.*; import java.util.List; @Entity public class Author { @Id @GeneratedValue private Long id; private String firstName; private String lastName; @OneToMany(mappedBy = "author") private List books; protected Author() { } public Author(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } }
- Publisher.java
package com.test.bookpub.domain; import javax.persistence.*; import java.util.List; @Entity public class Publisher { @Id @GeneratedValue private Long id; private String name; @OneToMany(mappedBy = "publisher") private List books; protected Publisher() { } public Publisher(String name) { this.name = name; } @Entity public class Reviewer { @Id @GeneratedValue private Long id; private String firstName; private String lastName; protected Reviewer() { } public Reviewer(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } } }
- repository層:創建完實體類,還需要創建BookRepository接口,該接口繼承自CrudRepository,這個接口放在src/main/java/com/test/bookpub/repository包中,具體代碼如下:
package com.test.bookpub.repository; import com.test.bookpub.domain.Book; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; @Repository public interface BookRepository extends CrudRepository { Book findBookByIsbn(String isbn); }
- 織入BookRepository,最后需要再StartupRunner中定義BookRepository對象,并自動織入。
package com.test.bookpub; import com.test.bookpub.repository.BookRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; public class StartupRunner implements CommandLineRunner { protected final Logger logger = LoggerFactory.getLogger(StartupRunner.class); @Autowired private BookRepository bookRepository; @Override public void run(String... strings) throws Exception { logger.info("Number of books: " + bookRepository.count()); } }
可能讀者朋友你也注意到了,到此為止,我們都沒有寫一行SQL語句,也沒有在代碼中涉及到數據庫連接、建立查詢等方面的內容。只有實體類上的各種注解表明我們在于數據庫做交互:@Entity,@Repository,@Id,@GeneratedValue,@ManyToOne,@ManyToMany以及@OneToMany,這些注解屬于Java Persistance API。我們通過CrudRespository接口的子接口與數據庫交互,同時由Spring建立對象與數據庫表、數據庫表中的數據之間的映射關系。下面依次說明這些注解的含義和使用:
- @Entity,說明被這個注解修飾的類應該與一張數據庫表相對應,表的名稱可以由類名推斷,當然了,也可以明確配置,只要加上 @Table(name = "books") 即可。需要特別注意,每個Entity類都應該有一個protected訪問級別的無參構造函數,用于給Hibernate提供初始化的入口。
- @Id and @GeneratedValue:@Id注解修飾的屬性應該作為表中的主鍵處理、@GeneratedValue修飾的屬性應該由數據庫自動生成,而不需要明確指定。
- @ManyToOne, @ManyToMany表明具體的數據存放在其他表中,在這個例子里,書和作者是多對一的關系,書和出版社是多對一的關系,因此book表中的author和publisher相當于數據表中的外鍵;并且在Publisher中通過@OneToMany(mapped = “publisher”)定義一個反向關聯(1——>n),表明book類中的publisher屬性與這里的books形成對應關系。
- @Repository 用來表示訪問數據庫并操作數據的接口,同時它修飾的接口也可以被component scan機制探測到并注冊為bean,這樣就可以在其他模塊中通過@Autowired織入。
- CrudRepository,直接查看源代碼,CrudRepository的代碼如下:
public interface CrudRepository extends Repository { S save(S entity); //保存給定的entity T findOne(ID primaryKey);//根據給定的id查詢對應的entity Iterable findAll(); //查詢所有entity Long count();//返回entity的個數 void delete(T entity); //刪除給定的entity boolean exists(ID primaryKey); //判斷給定id的entity是否存在 // … more functionality omitted. }
我們可以添加自定義的接口函數,JPA會提供對應的SQL查詢,例如,在本例中的BookRepository中可以增加findBookByIsbn(String isbn)函數,JPA會自動創建對應的SQL查詢——根據isbn查詢圖書,這種將方法名轉換為SQL語句的機制十分方便且功能強大,例如你可以增加類似findByNameIgnoringCase(String name)這種復雜查詢。
最后,我們利用 mvn spring-boot:run 運行應用程序,觀察下Hibernate是如何建立數據庫連接,如何檢測數據表是否存在以及如何自動創建表的過程。

spring with mysql