1. 程式人生 > >SpringBoot文檔翻譯系列——29.SQL數據源

SpringBoot文檔翻譯系列——29.SQL數據源

tor _exit 開始 pre 細粒度 osi connect uniq 3.6

原創作品,可以轉載,但是請標註出處地址:

因為需要使用到這方面內容,所有對這一部分進行了翻譯。

29 使用SQL數據源

  SpringBoot為SQL數據源提供了廣泛支持,從直接使用JdbcTemplate的JDBC訪問到完整的ORM(關系映射型)框架(例如Hibernate)。String Data提供了一份經典的功能級別,直接從接口創建存儲庫實現,並使用約定從方法名生成查詢。

29.1 配置數據源

  java的javax.sql.DataSource接口提供了一個經典的方法來使用SQL數據源。一般來說,一個數據源需要一個帶有驗證的URL來創建一個數據庫連接。

29.1.1 嵌入式數據庫支持

  使用嵌入內存的數據源來開發一個應用很方便。顯然,內存嵌入式數據源並不支持持久存儲,因此你必須在應用開始的時候進行數據填充,並在應用停止時有丟失數據的準備。

  SpringBoot可以自動配置需要嵌入的數據源:H2、HSQL和Derby等。這並不需要你提供鏈接URL,僅僅只需要添加對應的數據源依賴即可。

  註意:如果你在你的測試中使用了嵌入式數據庫,為防止你的整個測試套件中的所有應用上下文會共用同一個數據源,需要做以下設置:spring.datasource.generate-unique-name=true

  例如:經典的POM依賴為

1         <dependency
> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-data-jpa</artifactId> 4 </dependency> 5 <dependency> 6 <groupId>org.hsqldb</groupId> 7 <artifactId>hsqldb</
artifactId> 8 <scope>runtime</scope> 9 </dependency>

  註意:為了實現嵌入式數據源的自動配置,你需要添加Spring-jdbc的依賴,在這個實例中Spring-jdbc的依賴被spring-boot-starter-data-jpa所導入(言外之意,你無須關心這一點,因為已經被自動導入了)。

  註意:如果因為一些原因,你需要為嵌入式數據源配置URL,一定要記得將該數據源的自動shutdown功能關閉。如果你使用的是H2數據源,你需要配置DB_CLOSE_ON_EXIT=FALSE;如果你使用的是HSQLDB數據源,你需要確保shutdown=true失效。禁用嵌入式數據源的自動shutdown功能之後當數據源被關閉時轉由SpringBoot來進行控制,這樣一來不必再確保數據源只被一次訪問。

29.1.2 連接生產數據庫

  生產的數據庫也可以進行自動配置,只需要使用一個數據源池。下面是一些實現方式:

  (1)我們一般熱衷於HikariCP ,因為它的高性能和高並發性,一般情況下我們都會選擇它。
  (2)另外,如果tomcat的數據源池可用,我們也可以選擇使用它。
  (3)如果前兩個都不能使用,而DBCP2可用的話,我們選擇它。

  如果是添加了spring-boot-starter-jdbc或者是spring-boot-starter-data-jpa依賴starter的話,它們會自動添加對HikariCP的依賴。

  註意:你完全可以忽視其實現算法,而使用spring.datasource.type屬性來指定連接池。當你的應用正在使用默認的tomcat-jdbc運行在Tomcat容器時,尤其要註意這一點。

  註意:額外的連接池可以通過手動進行配置,如果你自定義了DataSource的Bean實例,那麽自動配置將不會生效。

  數據源的配置由外部屬性配置文件:spring.datasource.*來配置。例如:你可以在application.properties文件中申明如下配置:

spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

  註意:你至少要使用spring.datasource.url屬性來指定url鏈接,或者由SpringBoot自動配置一個內嵌數據源(內嵌數據源不需要指定url)

  註意:你一般不需要指定driver-class-name,因為SpringBoot可以從url之中自動識別出大多數數據庫的驅動類名。

  註意:要想得到一個數據源池,我們需要確保對應的驅動類是有效的,這項工作需要最先進行驗證。例如:如果你設置spring.datasource.driver-class-name=com.mysql.jdbc.Driver的話,那麽這個驅動類必須是可被加載的。

  參照DataSourceProperties類可查看更多配置項。不論實際上如何實現,這些都是一些標準的配置項。還可以通過一些帶有前綴的指定配置進行微調(例如:spring.datasource.hikari.*、spring.datasource.tomcat.*、spring.datasource.dbcp2.*等)。更多信息請參考你使用的連接池的實現文檔。

  例如:如果你使用的是Tomcat連接池,你需要如下額外配置內容:

# Number of ms to wait before throwing an exception if no connection is available.(如果連接無效,等待多久拋出異常)
spring.datasource.tomcat.max-wait=10000

# Maximum number of active connections that can be allocated from this pool at the same time.(連接池中可同時分配的最大連接數量)
spring.datasource.tomcat.max-active=50

# Validate the connection before borrowing it from the pool.(獲取池中連接前是否進行連接驗證)
spring.datasource.tomcat.test-on-borrow=true

29.1.3 連接一個JNDI數據源

  如果你正在將你的應用部署到一個應用服務器中,你肯能會想要使用JDNI和服務器特性來配置和管理你的數據源。

  spring.datasource.jndi-name屬性可被用來替換spring.datasource.url、spring.datasource.username和spring.datasource.password三個屬性來達成定位連接一個JNDI數據源的目的。例如:在application.properties文件中進如下配置可以顯示如何連接JBoss中定義的數據源。

spring.datasource.jndi-name=java:jboss/datasources/customers

29.2使用Jdbc Template(Jdbc模板)

  Spring中的JdbcTemplate類和NamedParameterJdbcTemplate類可被自動配置,你可以使用@Autowired註解來將其自動配置到自定義的Bean中。

 1 import org.springframework.beans.factory.annotation.Autowired;
 2 import org.springframework.jdbc.core.JdbcTemplate;
 3 import org.springframework.stereotype.Component;
 4 
 5 @Component
 6 public class MyBean {
 7 
 8     private final JdbcTemplate jdbcTemplate;
 9 
10     @Autowired
11     public MyBean(JdbcTemplate jdbcTemplate) {
12         this.jdbcTemplate = jdbcTemplate;
13     }
14 
15     // ...
16 
17 }

  你可以使用spring.jdbc.template.*系列屬性自定義一些Template的屬性值,例如:

spring.jdbc.template.max-rows=500

  註意:NamedParameterJdbcTemplate在幕後需要使用同一個JdbcTemplate實例,當你定義了超多一個JdbcTemplate實例並且未指定主要 候選對象的情況下,NamedParameterJdbcTemplate將不會被自動配置。

29.3 JPA和Spring Data

  Java持久化API是一個很經典的技術,它可以實現對象到數據源的映射。spring-boot-starter-data-jpa的POM提供了一種快速達成的方式,它提供了一下主要依賴:

    Hibernate——最流行的JPA實現之一

    Spring Data JPA——簡化基於JPA的數據源實現

    Spring ORMs——來自Spring框架的核心ORM支持

  註意:這裏我們不會深入討論JPA和Spring Data的詳情。你可以通過閱讀對應的引用文檔來進行詳細了解。

29.3.1 Entity Classes(實體類)

  一般情況下,JPA實體類在persistence.xml文件中指定。在SpringBoot中不再需要這個文件,而是使用Entity Scanner(實體類掃描器)來完成同樣的功能。默認情況下,所有位於啟動配置類(被註解@EnableAutoConfiguration或者@SpringBootApplication標註的類)所在目錄之下的包都將會被掃描。

  任何一個使用註解@Entity, @Embeddable或者@MappedSuperclass標註的類都將會被掃描到。下面展示一個經典的實體類樣板:

 1 package com.example.myapp.domain;
 2 
 3 import java.io.Serializable;
 4 import javax.persistence.*;
 5 
 6 @Entity
 7 public class City implements Serializable {
 8 
 9     @Id
10     @GeneratedValue
11     private Long id;
12 
13     @Column(nullable = false)
14     private String name;
15 
16     @Column(nullable = false)
17     private String state;
18 
19     // ... additional members, often include @OneToMany mappings
20 
21     protected City() {
22         // no-args constructor required by JPA spec
23         // this one is protected since it shouldn‘t be used directly
24     }
25 
26     public City(String name, String state) {
27         this.name = name;
28         this.country = country;
29     }
30 
31     public String getName() {
32         return this.name;
33     }
34 
35     public String getState() {
36         return this.state;
37     }
38 
39     // ... etc
40 
41 }

  註意:你可以使用@EntityScan註解來自定義實體掃描器的掃描路徑(標註於啟動類),詳見第78.4節內容

29.3.2 Spring Data JPA Repository

  Spring Data JPA Repository是可以使你定義連接數據的接口。JPA查詢可以通過你自定義的方法名自動創建。例如:一個CityRspository接口可以申明一個findAllByState(String state)方法來根據指定state獲取所有城市。

  你可以使用Spring Data的查詢註解來定義更加復雜的查詢。

  Spring Data Repository接口通常繼承自Repository或者CrudRepository接口,如果你正在使用自動配置功能,Respository將會在啟動配置類所在包及其下級包內被掃描到。

  下面是一個經典的Spring Data Repository:

 1 package com.example.myapp.domain;
 2 
 3 import org.springframework.data.domain.*;
 4 import org.springframework.data.repository.*;
 5 
 6 public interface CityRepository extends Repository<City, Long> {
 7 
 8     Page<City> findAll(Pageable pageable);
 9 
10     City findByNameAndCountryAllIgnoringCase(String name, String country);
11 
12 }

  註意:我們僅僅了解了Spring Data JPA的基礎知識,詳情查看引導文檔(http://projects.spring.io/spring-data-jpa/)

29.3.3 創建和丟棄JPA數據源

  默認情況下,當你使用了一個嵌入式數據庫(H2、 HSQL、Derby)時,JPA Repository將會被自動創建。你可以使用spring.jpa.*來進行JPA的相關配置。例如:為了創建和刪除表,你可以在application.properties文件中添加如下配置:

spring.jpa.hibernate.ddl-auto=create-drop

  註意:Hibernate針對該配置的內部屬性為hibernate.hbm2ddl.auto。你可以使用spring.jpa.properties.*的方式協同Hibernate的其他屬性進行一起配置,這個前綴會在添加到實體管理器之前被去除,例如:

spring.jpa.properties.hibernate.globally_quoted_identifiers=true

  通過hibernate.globally_quoted_identifiers來到達Hibernate實體管理器。

  默認情況下,DDL執行或者驗證會推遲到ApplicationContext啟動後執行。還有一個spring.jpa.generate-ddl標誌,但如果Hibernate的 autoconfig是活動狀態的,則不會使用它,因為ddl-auto設置更具細粒度。

29.3.4 Open EntityManager in View

  如果你正在運行一個web應用,SpringBoot將默認註冊OpenEntityManagerInViewInterceptor來服務於"Open EntityManager in View"模式,例如,它將會開啟懶加載功能(在web視圖中)。如果你不想要這種功能,你可以通過在application.properties中配置spring.jpa.open-in-view=false來達成。

29.3.5 使用H2的web控制臺

  H2數據庫提供了一個基於瀏覽器的web控制臺,這個可以有SpringBoot自動配置加載。控制臺在達成以下條件後將會被自動配置加載:

    你正在開發的是一個web應用

    com.h2database:h2在類路徑下

    你正在使用SpringBoot開發者工具(spring-boot-devtools)

  註意:如果你沒有正在使用SpringBoot開發者工具,但卻想要使用H2的web控制臺功能,你可以配置spring.h2.console.enabled=true來達成目的。該功能僅用於開發期間,在應用上生產環境之時,一定要將spring.h2.console.enabled=true配置去掉。

29.4.1 改變H2控制臺的路徑

  默認情況下H2控制臺只在/h2-console路徑下有效,你可以通過屬性spring.h2.console.path進行自定義H2控制臺的路徑。

29.4.2 安全化H2控制臺

  當Spring Security位於類路徑下,並且基本認證功能處於激活狀態時,H2控制臺將會自動是使用基本認證功能。下面這些屬性可被用來自定義安全配置:

    security.user.role

    security.basic.authorize-mode

    security.basic.enabled

29.5 使用jOOQ

  jOOQ(Java Object Oriented Querying:Java面向對象查詢)是一個流行的代碼生成器(根據數據源生成java代碼),並通過其API創建類型安全的SQL查詢,其商業版和開源版均被SpringBoot所支持。

29.5.1 代碼生成

  為了使用jOOQ的類型安全的查詢,你需要根據數據源結構生成Java類。你可以依據 jOOQ user manual(http://www.jooq.org/doc/3.6/manual-single-page/#jooq-in-7-steps-step3)的介紹。如果你正在使用jooq-codegen-maven插件(並且同是在使用spring-boot-starter-parent),你可以省略拆件的<version>標簽,你也可以使用SpringBoot來定義版本變量(例如:h2.version)來聲明插件的數據源依賴,下面是一個實例:

 1 <plugin>
 2     <groupId>org.jooq</groupId>
 3     <artifactId>jooq-codegen-maven</artifactId>
 4     <executions>
 5         ...
 6     </executions>
 7     <dependencies>
 8         <dependency>
 9             <groupId>com.h2database</groupId>
10             <artifactId>h2</artifactId>
11             <version>${h2.version}</version>
12         </dependency>
13     </dependencies>
14     <configuration>
15         <jdbc>
16             <driver>org.h2.Driver</driver>
17             <url>jdbc:h2:~/yourdatabase</url>
18         </jdbc>
19         <generator>
20             ...
21         </generator>
22     </configuration>
23 </plugin>  

29.5.2 使用DSLContext

  jOOQ所提供的API是通過org.jooq.DSLContext接口開啟的。SpringBoot將會自定義一個DSLContext(DSL上下文)Bean和你的應用的數據源連接起來,為了使用DSLContext,你需要@Autowired:

 1 @Component
 2 public class JooqExample implements CommandLineRunner {
 3 
 4     private final DSLContext create;
 5 
 6     @Autowired
 7     public JooqExample(DSLContext dslContext) {
 8         this.create = dslContext;
 9     }
10 
11 }

  註意:jOOQ手冊傾向於使用名為create的變量來持有DSLContext,因此我們可以使用如下代碼完成同樣的功能:

1 public List<GregorianCalendar> authorsBornAfter1980() {
2     return this.create.selectFrom(AUTHOR)
3         .where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1)))
4         .fetch(AUTHOR.DATE_OF_BIRTH);
5 }

  然後你可以使用DSLContext來構建你的查詢。

29.5.3 jOOQ SQL語言

  SpringBoot可以決定是否使用jOOQ SQL語言,除非spring.jooq.sql-dialect屬性被設置,如果該語言無法被執行,則該屬性一定被設置為DEFAULT了。

  註意:SpringBoot僅僅支持開源版本的jOOQ SQL語言。

29.5.4 自定義jOOQ

  通過自定義@Bean(這些Bean將會在jOOQ的Configuration被創建時使用),你可以獲得更多的高級定制功能。你可以使用如下jOOQ類型來定義Bean:

    ConnectionProvider
    TransactionProvider
    RecordMapperProvider
    RecordListenerProvider
    ExecuteListenerProvider
    VisitListenerProvider

  如果你想要完美的控制jOOQ的各項配置,你需要自定義org.jooq.Configuration配置類(使用@Bean註解)。

SpringBoot文檔翻譯系列——29.SQL數據源