資料來源(DataSource)是什麼以及SpringBoot中資料來源配置

Special__Yang發表於2018-08-09

資料來源

資料來源,簡單理解為資料來源頭,提供了應用程式所需要資料的位置。資料來源保證了應用程式與目標資料之間互動的規範和協議,它可以是資料庫,檔案系統等等。其中資料來源定義了位置資訊,使用者驗證資訊和互動時所需的一些特性的配置,同時它封裝瞭如何建立與資料來源的連線,向外暴露獲取連線的介面。應用程式連線資料庫無需關注其底層是如何如何建立的,也就是說應用業務邏輯與連線資料庫操作是鬆耦合的。 以下只討論當資料來源為資料庫的情況,且為Java環境下JDBC規範下的如何建立與資料庫的連線,其他情況類似。

DriverManager

JDBC(Java DataBase Connectivity, 簡稱JDBC)是Java中用於規範應用程式如何來訪問資料庫的應用程式介面(API),它提供了查詢和更新資料庫中資料的方法。
在基於Java的應用程式中,我們需要使用JDBC驅動程式與資料庫進行互動,其中最重要的一步就是獲取與資料庫的連線。在傳統的JDBC時代,我們通常寫一個通用的方法來封裝與資料庫的建立操作:

    public Connection getConnection() throws SQLException {

        Connection conn = null;
        Properties connectionProps = new Properties();
        connectionProps.put("user", this.userName);
        connectionProps.put("password", this.password);
        //獲取獲取連線
        conn = DriverManager.getConnection(
                   "jdbc:" + this.dbms + "://" +
                   this.serverName +
                   ":" + this.portNumber + "/",
                   connectionProps);
        return conn;
    }

以上的程式碼對於早些的程式設計師是再熟悉不過了,我們利用驅動管理器為應用程式提供資料庫連線,雖然使用形式簡單,但有個很大的問題就是:程式設計師需要自己去寫建立連線的操作,且該方法已經與我們的應用程式是緊耦合的,在後續需要更改資料庫時,需要程式設計師手動修改這裡。在面對多資料來源的情況下,該方法可能變成了簡單工廠模式那種慵懶的樣子,不符合設計模式中“對修改關閉,對擴充套件開放”的原則。

資料來源

資料來源是對資料庫以及對資料庫互動操作的抽象,它封裝了目標源的位置資訊,驗證資訊和建立與關閉連線的操作。資料來源可以看做程式中一個元件,它把傳統中需要在程式碼裡編寫配置資訊和獲取連線等操作抽象出一個規範或者介面,這樣不同的第三方可以自行實現該介面提供不同的策略。這樣,資料來源就是對應用程式是透明的,開發者只需為應用程式配置特定的資料來源即可與資料庫進行連線等操作。當需要更換資料庫伺服器或者更換資料庫種類時,只需修改配置中資訊即可,無需修改程式程式碼。
資料來源大致分為2種:不提供連線池提供連線池管理

不提供連線池的資料來源

Spring中提供的資料來源就是不提供連線池功能的,比如DriverManagerDataSource。該資料來源對於應用程式的每一個連線請求都建立新的連線,當應用程式使用完畢後,再執行銷燬操作。當與資料庫互動頻繁時,這種模式會嚴重影響程式的效能。時間和空間消耗大多數消耗在連線和銷燬中,而非資料庫處理。所以Spring建議我們僅在測試中使用該資料來源。以下為原話:

Only use the DriverManagerDataSource class should only be used for testing purposes since it does not provide pooling and will perform poorly when multiple requests for a connection are made.

提供連線池的資料來源

提供連線池的資料來源則是第三方提供的,比較流行的有Apache Jakarta Commons DBCP and C3P0。Spring中並不提供帶池化管理的資料來源,它的目的在於整合市面上優秀的資料來源元件。這裡,提個插曲,Spring的口號就是不與市場上優秀的第三方元件競爭,而是以包容的心態為他們提供平臺,方便開發者使用它們
連線池是一種建立和管理一組連線物件的技術,這些連線物件可供任何需要它的執行緒使用。連線池可以極大地提高Java應用程式的效能,避免了建立新的連線例項時所必需的初始化和認證時間,同時減少整體資源使用,可以大大提高併發web的響應速度。這種資料來源會在初始化的時候根據使用者配置建立一組連線。當應用程式與資料庫互動時,就可以快速從連線池中選擇一個空閒的連線使用;當使用完畢,把該連線歸還給連線池即可。

配置

這裡僅僅展示一下如何配置C3P0 資料來源。

xml配置

在類路徑下的spring中配置檔案中,加入以下程式碼即可,其中jdbc.properties則是一些配置資訊。

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClass" value="${jdbc.driverClassName}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <context:property-placeholder location="jdbc.properties"/>

當然也可以通過Java程式碼來配置,使用Spring的註解@Configuration來定義配置類,這樣在IOC容器初始化時會例項化該資料來源。

package com.specialyang.questionanswer.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.jboss.C3P0PooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

/**
 * Created by Special on 2018/8/9 15:32
 */
@Configuration
public class DataSourceConfiguration {

    @Bean
    public DataSource dataSource() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver
        dataSource.setJdbcUrl( "jdbc:postgresql://localhost/testdb" );
        dataSource.setUser("swaldman");
        dataSource.setPassword("test-password");
        return dataSource;
    }

}

資料來源在SpringBoot中的使用

我們知道SpringBoot中是約定優於配置,springboot提供了很多自動化配置的操作,大大簡化了開發者在配置上花費的時間。比如資料來源,基於版本2.1.0,SpringBoot採用以下演算法來自動化配置資料來源:
1. 我們更喜歡HikariCP的效能和併發性。 如果HikariCP可用,我們總是選擇它。
2. 否則,如果Tomcat池化DataSource可用,我們將使用它。
3. 如果HikariCP和Tomcat池化資料來源都不可用,並且Commons DBCP2可用,我們就會使用它。

以上都是在沒有顯示配置資料來源的情況進行的步驟,若手動顯示配置了指定資料來源,則以上步驟失效。

一般情況下,springboot都是採用HikariCP來作為預設的資料來源。

那麼如何更改預設的資料來源呢?
如果我們想定義特定的資料來源,一種簡單的方法就是直接在application.properties指定:

//指定使用c3p0, 當然你需要新增該資料來源的依賴包,因為springboot不預設提供
spring.datasource.type=com.mchange.v2.c3p0.ComboPooledDataSource

另一種就是使用上面寫的配置類

問題錦集

問題1

Loading class com.mysql.jdbc.Driver. This is deprecated. The new driver class is com.mysql.cj.jdbc.Driver. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.

上面說的已經很清楚了,com.mysql.jdbc.Driver已經被廢棄,要使用新的jdbc驅動程式:com.mysql.cj.jdbc.Driver,並且該驅動可以被自動載入,手動載入是沒必要的。所以我們的application.properties無需在為mysql指定驅動類了。 以上可以在JDBC官方文件找到答案:

When this class first attempts to establish a connection, it automatically loads any JDBC 4.0 drivers found within the class path. Note that your application must manually load any JDBC drivers prior to version 4.0.

參考

[1]https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/reference/htmlsingle/#boot-features-configure-datasource
[2]https://docs.oracle.com/javase/tutorial/jdbc/basics/sqldatasources.html#datasource_connection
[3]https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-usagenotes-j2ee-concepts-connection-pooling.html

相關文章