单数据源配置

     数据源是一种用来提高数据库连接性能的常规手段,数据源会负责维持一个数据库连接池,当程序创建数据源实例时,系统会一次性地创建多个数据库连接,并把这些数据库连接保存在连接池中。当程序需要进行数据库访问时,无须重新获得数据库连接,而是从连接池中取出一个空闲的数据库连接,当程序使用数据库连接访问结束后,无须关闭数据库连接,而是将数据库连接归还给连接池即可。通过这种方式,就可比避免频繁地获取数据库连接,关闭数据库连接所导致的性能下降。

无论采用哪一种数据源配置,首先需要有数据库驱动包和spring-jdbc模块,这里采用MySQL,所以添加以下依赖:

<!-- mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>

<!--Spring JDBC-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
</dependency>

一、普通DriverManagerDataSource

 DriverManagerDataSource是Spring自带的数据源插件,没有连接池的概念。即每次都会创建新的数据库连接。 不推荐使用,会有以下问题:

  • 增加系统性能开销。 
  • 数据库操作效率低,每次都要创建、释放链接无意增加操作时间。 
  • 如果有长连接未释放,会导致数据库连接不够使用
在resourcs文件夹下创建dmd.properties
# DriverManagerDataSource
dmd.jdbc.driverClassName=com.mysql.jdbc.Driver
dmd.jdbc.url=jdbc:mysql://127.0.0.1:3305/spring?characterEncoding=utf-8
dmd.jdbc.username=root
dmd.jdbc.password=123456
数据库配置类
public class DmdSource {
    @Value("${dmd.jdbc.driverClassName}")
    private String driverClassName;
    @Value("${dmd.jdbc.url}")
    private String url;
    @Value("${dmd.jdbc.username}")
    private String username;
    @Value("${dmd.jdbc.password}")
    private String password;

    public String getDriverClassName() {
        return driverClassName;
    }

    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * 创建数据源对象
     *
     * @return DataSource
     */
    @Bean(name = "defaultDataSource")
    public DataSource defaultDataSource() {
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName(driverClassName);
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        return ds;
    }
}
修改Spring根容器配置类:SpringConfig

在类上添加以下内容,用以将数据库配置类加入到Spring IoC容器中

@Import(value = DmdSource.class)
@PropertySource(value = {"classpath:dmd.properties"}) //读取resources下的配置文件
测试数据库配置
@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextHierarchy({
        @ContextConfiguration(classes = SpringConfig.class),
        @ContextConfiguration(classes = SpringMVCConfig.class)
})
public class DbTest {

    @Autowired
    private DataSource defaultDataSource;

    @Test
    public void test() throws SQLException {
        // 测试数据库是否正确连接
        System.out.println(defaultDataSource.getConnection());
    }
}

二、DruidDataSource

添加druid依赖
<!-- druid dataSource -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.6</version>
</dependency>

主要类:com.alibaba.druid.pool.DruidDataSource

可配置属性
name: 数据源名称,多数据源下有用,例:druid-1
driverClassName:数据库驱动类型,根据url自动识别,可以不配置,例:com.mysql.jdbc.Driver
url:连接数据库的url,例:jdbc:mysql://127.0.0.1:3305/spring?characterEncoding=utf-8
username:用户名,例:root
password:密码,例:123456。可以使用druid提供的ConfigTools进行加密,命令java -cp druid-1.1.16.jar com.alibaba.druid.filter.config.ConfigTools 123456,配置加密的密码后需要配置connectionProperties,包含config.decrypt=true
initialSize:初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时, 默认是0
maxActive:最大连接池数量,默认是8个
minIdle: 最小连接池数量
maxWait:取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。例:10000
poolPreparedStatements: 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。默认是false
maxOpenPreparedStatements: 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100。
validationQuery:用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。例:select 1
testOnBorrow:申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。例:true
testOnReturn: 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。例: false
testWhileIdle:建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。例:true
timeBetweenEvictionRunsMillis:关闭空闲连接的检测时间间隔,单位毫秒
minEvictableIdleTimeMillis:连接的最小生存时间,单位毫秒
connectionInitSqls:物理连接初始化的时候执行的sql(集合)。例:["set names utf8mb4;"]
filters:属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall。例:stat,wall,log4j
defaultAutoCommit:配置提交方式,默认就是true,可以不用配置。例:true
useGlobalDataSourceStat: 是否合并多个DruidDataSource的监控数据,例:false
asyncInit:asyncInit是1.1.4中新增加的配置,如果有initialSize数量较多时,打开会加快应用启动时间。例:true
timeBetweenLogStatsMillis:配置监控统计日志的输出间隔,单位毫秒,每次输出所有统计数据会重置,酌情开启。例:120000
clearFiltersEnable:是否启动清除过滤器。例:true
useUnfairLock: 是否使用非公平锁。例:true
resetStatEnable: 是否启动重置功能,重置后,会导致所有计数器清零,重新计数。例:true
notFullTimeoutRetryCount: 设置获取连接时的重试次数,-1为不重试。
failFast:设置获取连接出错时是否马上返回错误,true为马上返回。例:true
breakAfterAcquireFailure:true表示向数据库请求连接失败后,就算后端数据库恢复正常也不进行重连,客户端对pool的请求都拒绝掉.false表示新的请求都会尝试去数据库请求connection.默认为false。
maxWaitThreadCount:druid的丢弃策略。默认值是-1,表示不启用,大于0表示启用。意思就是在连接不够用时最多让多少个业务线程发生阻塞,不会造成大量的线程阻塞。例:2
phyTimeoutMillis:连接不管是否空闲,存活phyTimeoutMillis后强制回收,用于Destroy线程清理连接的时候的检测时间。例:3600000
maxEvictableIdleTimeMillis:连接的最大存活时间,如果连接的最大时间大于maxEvictableIdleTimeMillis,则无视最小连接数强制回收。例:3600000
keepAlive:打开后,增强timeBetweenEvictionRunsMillis的周期性连接检查,minIdle内的空闲连接,每次检查强制验证连接有效性。例:true
killWhenSocketReadTimeout: socket连接超时时间, 单位秒
initVariants:
initGlobalVariants:
connectProperties:通过connectProperties属性来打开mergeSql功能;慢SQL记录。例:spring.datasource.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
maxPoolPreparedStatementPerConnectionSize:设置PSCache值,例:20
timeBetweenConnectErrorMillis:连接出错后重试时间间隔,单位毫秒。例:300000
queryTimeout: 查询的超时时间,单位秒。
并且从借出时间起已超过removeAbandonedTimeout时间,则强制归还连接到连接池中。removeAbandoned:连接泄露检查,打开removeAbandoned功能 , 连接从连接池借出后,长时间不归还,将触发强制回连接。回收周期随timeBetweenEvictionRunsMillis进行,如果连接为从连接池借出状态,并且未执行任何sql,例:true
removeAbandonedTimeout:连接泄露检查超时时间, 单位秒
logAbandoned:关闭abanded连接时输出错误日志,这样出现连接泄露时可以通过错误日志定位忘记关闭连接的位置。例:true
transactionQueryTimeout:事务超时时间,单位秒
defaultTransactionIsolation:指定连接的事务的默认隔离级别。
transactionThresholdMillis:事务使用时长,单位毫秒。
connectionErrorRetryAttempts:连接出错后再尝试连接三次
在resourcs文件夹下创建druiddb.properties
# DruidDataSource + mysql
druid.jdbc.name=druid-default
druid.jdbc.driverClassName=com.mysql.jdbc.Driver
druid.jdbc.url=jdbc:mysql://127.0.0.1:3305/spring?characterEncoding=utf-8&useSSL=false
druid.jdbc.username=root
druid.jdbc.password=123456
druid.jdbc.initialSize=1
druid.jdbc.maxActive=10
druid.jdbc.minIdle=1
druid.jdbc.maxWait=10000
druid.jdbc.testOnBorrow=true
druid.jdbc.testOnReturn=false
druid.jdbc.testWhileIdle=true
druid.jdbc.timeBetweenEvictionRunsMillis=60000
druid.jdbc.minEvictableIdleTimeMillis=300000
druid.jdbc.poolPreparedStatements=true
druid.jdbc.maxOpenPreparedStatements=20
druid.jdbc.asyncInit= true
druid.jdbc.filters=stat
druid.jdbc.validationQuery=select 1

druid数据库配置类

public class DruidDBConfig {

    @Value("${druid.jdbc.name}")
    private String dataSourceName;
    @Value("${druid.jdbc.driverClassName}")
    private String driverClassName;
    @Value("${druid.jdbc.url}")
    private String url;
    @Value("${druid.jdbc.username}")
    private String username;
    @Value("${druid.jdbc.password}")
    private String password;
    @Value("${druid.jdbc.initialSize}")
    private Integer initialSize;
    @Value("${druid.jdbc.maxActive}")
    private Integer maxActive;
    @Value("${druid.jdbc.minIdle}")
    private Integer minIdle;
    @Value("${druid.jdbc.maxWait}")
    private Integer maxWait;
    @Value("${druid.jdbc.poolPreparedStatements}")
    private Boolean poolPreparedStatements;
    @Value("${druid.jdbc.maxOpenPreparedStatements}")
    private Integer maxOpenPreparedStatements;
    @Value("${druid.jdbc.validationQuery}")
    private String validationQuery;
    @Value("${druid.jdbc.testOnBorrow}")
    private Boolean testOnBorrow;
    @Value("${druid.jdbc.testOnReturn}")
    private Boolean testOnReturn;
    @Value("${druid.jdbc.testWhileIdle}")
    private Boolean testWhileIdle;
    @Value("${druid.jdbc.timeBetweenEvictionRunsMillis}")
    private Long timeBetweenEvictionRunsMillis;
    @Value("${druid.jdbc.minEvictableIdleTimeMillis}")
    private Long minEvictableIdleTimeMillis;
    @Value("${druid.jdbc.filters}")
    private String filters;
    @Value("${druid.jdbc.asyncInit}")
    private Boolean asyncInit;


    /**
     * 创建数据源对象
     * 返回值不能返回 javax.sql.DataSource, 否则在web监控时数据源tab源无任何显示
     * @return DruidDataSource
     */
    @Bean(name="druidDataSource",destroyMethod = "close", initMethod = "init")
    public DruidDataSource druidDataSource() throws SQLException {
        DruidDataSource ds = new DruidDataSource();
        ds.setName(dataSourceName);
        ds.setDriverClassName(driverClassName);
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        ds.setInitialSize(initialSize);
        ds.setMaxActive(maxActive);
        ds.setMinIdle(minIdle);
        ds.setMaxWait(maxWait);
        ds.setPoolPreparedStatements(poolPreparedStatements);
        ds.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
        ds.setValidationQuery(validationQuery);
        ds.setTestOnBorrow(testOnBorrow);
        ds.setTestOnReturn(testOnReturn);
        ds.setTestWhileIdle(testWhileIdle);
        ds.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        ds.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        ds.setFilters(filters);
        ds.setAsyncInit(asyncInit);
        return ds;
    }
}

同理,只需要在SpringConfig中将@Import的DmdSource改为DruidDBConfig及修改读取的properties文件即可。

druid的web监控配置

druid也提供简单的界面化监控。

在resources目录下创建druid-web.properties ,内容如下:

# druid 监控配置
# 映射的URL
druid.stat-view-servlet.urlPattern=/druid/*
# 白名单,如果不配置或value为空,则允许所有
druid.stat-view-servlet.allow=
# 黑名单,与白名单存在相同IP时,优先于白名单
druid.stat-view-servlet.deny=
# 用户名
druid.stat-view-servlet.loginUsername=root
# 密码
druid.stat-view-servlet.loginPassword=sunshine
# 禁用HTML页面上的“Reset All”功能
druid.stat-view-servlet.resetEnable=false
druid.web-stat-filter.enabled=true
druid.web-stat-filter.urlPattern=/*
# 排除一些不必要的url,比如.js,gif等等
druid.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*,/static/*
# 默认sessionStatMaxCount是1000个,你也可以按需要进行配置
druid.web-stat-filter.sessionStatMaxCount=1000
# session统计功能
druid.web-stat-filter.sessionStatEnable=false
# druid 0.2.7版本开始支持profile,配置profileEnable能够监控单个url调用的sql列表
druid.web-stat-filter.profileEnable=true
# 监控当前COOKIE的用户
druid.web-stat-filter.principalCookieName=USER_COOKIE
# 监控当前SESSION的用户
druid.web-stat-filter.principalSessionName=USER_SESSION

启动时注册用到的Servlet和Filter

import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import java.io.IOException;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.web.WebApplicationInitializer;

public class ApplicationInitializer implements WebApplicationInitializer {

    private static Properties druidWebProperties = new Properties();
    private static final String DRUID_STAT_VIEW_SERVLET_PREFIX =  "druid.stat-view-servlet.";
    private static final String DRUID_WEB_STAT_FILTER_PREFIX =  "druid.web-stat-filter.";

    static {
        System.out.println("读取外部指定配置");
        //读取Properties文件
        try {
            druidWebProperties = PropertiesLoaderUtils.loadAllProperties("druid-web.properties");
        } catch (IOException e) {
            throw new RuntimeException("启动时读取配置文件appCommon.properties失败:" + e.getMessage());
        }
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        this.registerServlet(servletContext);
        this.registerFilter(servletContext);
    }


    public void registerServlet(ServletContext servletContext){
        ServletRegistration.Dynamic druidStatViewServlet = servletContext.addServlet("DruidStatViewServlet", StatViewServlet.class);
        Map<String, String> initParams = new HashMap<String, String>();
        initParams.put("allow",druidWebProperties.getProperty(DRUID_STAT_VIEW_SERVLET_PREFIX + "allow"));
        initParams.put("deny",druidWebProperties.getProperty(DRUID_STAT_VIEW_SERVLET_PREFIX + "deny"));
        initParams.put("loginUsername",druidWebProperties.getProperty(DRUID_STAT_VIEW_SERVLET_PREFIX + "loginUsername"));
        initParams.put("loginPassword",druidWebProperties.getProperty(DRUID_STAT_VIEW_SERVLET_PREFIX + "loginPassword"));
        initParams.put("resetEnable",druidWebProperties.getProperty(DRUID_STAT_VIEW_SERVLET_PREFIX + "resetEnable"));
        druidStatViewServlet.setInitParameters(initParams);
        druidStatViewServlet.addMapping(druidWebProperties.getProperty(DRUID_STAT_VIEW_SERVLET_PREFIX + "urlPattern"));
    }

    private void registerFilter(ServletContext servletContext){
        FilterRegistration.Dynamic druidStatFilter = servletContext.addFilter("DruidStatFilter", WebStatFilter.class);
        Map<String, String> initParams = new HashMap<String, String>();
        initParams.put("enabled",druidWebProperties.getProperty(DRUID_WEB_STAT_FILTER_PREFIX + "enabled"));
        initParams.put("exclusions",druidWebProperties.getProperty(DRUID_WEB_STAT_FILTER_PREFIX + "exclusions"));
        initParams.put("sessionStatMaxCount",druidWebProperties.getProperty(DRUID_WEB_STAT_FILTER_PREFIX + "sessionStatMaxCount"));
        initParams.put("sessionStatEnable",druidWebProperties.getProperty(DRUID_WEB_STAT_FILTER_PREFIX + "sessionStatEnable"));
        initParams.put("profileEnable",druidWebProperties.getProperty(DRUID_WEB_STAT_FILTER_PREFIX + "profileEnable"));
        initParams.put("principalCookieName",druidWebProperties.getProperty(DRUID_WEB_STAT_FILTER_PREFIX + "principalCookieName"));
        initParams.put("principalSessionName",druidWebProperties.getProperty(DRUID_WEB_STAT_FILTER_PREFIX + "principalSessionName"));
        druidStatFilter.setInitParameters(initParams);
        druidStatFilter.addMappingForUrlPatterns(
                EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE), false,
                druidWebProperties.getProperty(DRUID_WEB_STAT_FILTER_PREFIX + "urlPattern"));

    }

}

启动项目,访问http://ip:port/应用上下文/druid,输入用户名和密码:root/sunshine。

三、C3p0数据源

添加依赖:

<!-- C3p0 -->
<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.5</version>
</dependency>
<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>mchange-commons-java</artifactId>
    <version>0.2.19</version>
</dependency>

主要类:com.mchange.v2.c3p0.ComboPooledDataSource

在resources目录下创建c3p0.properties
# ComboPooledDataSource + mysql
c3p0.jdbc.driverClass=com.mysql.jdbc.Driver
c3p0.jdbc.jdbcUrl=jdbc:mysql://localhost:3305/spring?useSSL=false&characterEncoding=UTF-8
c3p0.jdbc.user=root
c3p0.jdbc.password=123456
c3p0.jdbc.minPoolSize=1
c3p0.jdbc.maxPoolSize=100
c3p0.jdbc.initialPoolSize=5
c3p0.jdbc.maxIdleTime=60
c3p0.jdbc.acquireIncrement=10
c3p0.jdbc.maxStatements=10
c3p0.jdbc.idleConnectionTestPeriod=30
c3p0.jdbc.acquireRetryAttempts=30
c3p0.jdbc.breakAfterAcquireFailure=true
c3p0.jdbc.testConnectionOnCheckout=false
c3p0.jdbc.automaticTestTable=true
c3p0.jdbc.checkoutTimeout=15000
c3p0.jdbc.numHelperThreads=10
c3p0.jdbc.testConnectionOnCheckin=true
c3p0数据库配置类
public class C3p0DBConfig {
    @Value("${c3p0.jdbc.driverClass}")
    private String driverClass;
    @Value("${c3p0.jdbc.jdbcUrl}")
    private String jdbcUrl;
    @Value("${c3p0.jdbc.user}")
    private String user;
    @Value("${c3p0.jdbc.password}")
    private String password;
    @Value("${c3p0.jdbc.minPoolSize}")
    private Integer minPoolSize;
    @Value("${c3p0.jdbc.maxPoolSize}")
    private Integer maxPoolSize;
    @Value("${c3p0.jdbc.initialPoolSize}")
    private Integer initialPoolSize;
    @Value("${c3p0.jdbc.maxIdleTime}")
    private Integer maxIdleTime;
    @Value("${c3p0.jdbc.acquireIncrement}")
    private Integer acquireIncrement;
    @Value("${c3p0.jdbc.maxStatements}")
    private Integer maxStatements;
    @Value("${c3p0.jdbc.idleConnectionTestPeriod}")
    private Integer idleConnectionTestPeriod;
    @Value("${c3p0.jdbc.acquireRetryAttempts}")
    private Integer acquireRetryAttempts;
    @Value("${c3p0.jdbc.breakAfterAcquireFailure}")
    private boolean breakAfterAcquireFailure;
    @Value("${c3p0.jdbc.testConnectionOnCheckout}")
    private boolean testConnectionOnCheckout;
    @Value("${c3p0.jdbc.automaticTestTable}")
    private boolean automaticTestTable;
    @Value("${c3p0.jdbc.checkoutTimeout}")
    private Integer checkoutTimeout;
    @Value("${c3p0.jdbc.numHelperThreads}")
    private Integer numHelperThreads;
    @Value("${c3p0.jdbc.testConnectionOnCheckin}")
    private boolean testConnectionOnCheckin;

    @Bean("c3p0DataSource")
    public ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {
        ComboPooledDataSource pooledDataSource = new ComboPooledDataSource();
        pooledDataSource.setDriverClass(driverClass);
        pooledDataSource.setJdbcUrl(jdbcUrl);
        pooledDataSource.setUser(user);
        pooledDataSource.setPassword(password);
        pooledDataSource.setMinPoolSize(minPoolSize);
        pooledDataSource.setMaxPoolSize(maxPoolSize);
        pooledDataSource.setInitialPoolSize(initialPoolSize);
        pooledDataSource.setMaxIdleTime(maxIdleTime);
        pooledDataSource.setAcquireIncrement(acquireIncrement);
        pooledDataSource.setMaxStatements(maxStatements);
        pooledDataSource.setIdleConnectionTestPeriod(idleConnectionTestPeriod);
        pooledDataSource.setAcquireRetryAttempts(acquireRetryAttempts);
        pooledDataSource.setBreakAfterAcquireFailure(breakAfterAcquireFailure);
        pooledDataSource.setTestConnectionOnCheckout(testConnectionOnCheckout);
        pooledDataSource.setCheckoutTimeout(checkoutTimeout);
        pooledDataSource.setNumHelperThreads(numHelperThreads);
        pooledDataSource.setTestConnectionOnCheckin(testConnectionOnCheckin);
        return pooledDataSource;
    }
}

同理,只需要在SpringConfig中将@Import的类改为C3p0DBConfig及修改读取的properties文件即可。

 

posted @ 2020-07-18 20:40  codedot  阅读(543)  评论(0编辑  收藏  举报