数据源,简单理解为数据源头,提供了应用程序所需要数据的位置。数据源保证了应用程序与目标数据之间交互的规范和协议,它可以是数据库,文件系统等等。其中数据源定义了位置信息,用户验证信息和交互时所需的一些特性的配置,同时它封装了如何建立与数据源的连接,向外暴露获取连接的接口。应用程序连接数据库无需关注其底层是如何如何建立的,也就是说应用业务逻辑与连接数据库操作是松耦合的。 以下只讨论当数据源为数据库的情况,且为Java环境下JDBC规范下的如何建立与数据库的连接,其他情况类似。
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 数据源。
在类路径下的spring中配置文件中,加入以下代码即可,其中jdbc.properties则是一些配置信息。
"dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
"driverClass" value="${jdbc.driverClassName}"/>
"jdbcUrl" value="${jdbc.url}"/>
"user" value="${jdbc.username}"/>
"password" value="${jdbc.password}"/>
"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提供了很多自动化配置的操作,大大简化了开发者在配置上花费的时间。比如数据源,基于版本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
另一种就是使用上面写的配置类。
Loading class
com.mysql.jdbc.Driver
. This is deprecated. The new driver class iscom.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