数据库连接池
概念:数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。能明显提高对数据库操作的性能。
优点:
1.节约资源
2.高效
数据库连接池的原理
连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。
使用完毕后,用户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。而连接的建立、断开都由连接池自身来管理。同时,还可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大空闲时间等等,也可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。
常见的数据库连接池介绍
C3P0
主要特性:1、编码的简单易用
缺点:C3P0 本身存在BUG,容易造成死锁
Druid
主要特性:
1、 强大的监控特性,通过Druid提供的监控功能,可以清楚知道连接池和SQL
a.监控SQL的执行时间、ResultSet持有时间、返回行数、更新行数、错误次数、错误堆栈信息;
b. SQL执行的耗时区间分布。什么是耗时区间分布呢?比如说,某个SQL执行了1000次,其中01毫秒区间50次,110毫秒800次,10100毫秒100次,1001000毫秒30次,1~10秒15次,10秒以上5次。通过耗时区间分布,能够非常清楚知道SQL的执行耗时情况。
c. 监控连接池的物理连接创建和销毁次数、逻辑连接的申请和关闭次数、非空等待次数、PSCache命中率等。
2、便于扩展。Druid提供了Filter-Chain模式的扩展API,可以自己编写Filter拦截JDBC中的任何方法,可以在上面做任何事情,比如说性能监控、SQL审计、用户名密码加密、日志等等。
HikariCP
主要特性:快速,简单,可靠,稳定性高,据说是性能最好是一个高性能的JDBC连接池。Spring Boot将在2.0版本中把HikariCP作为其默认的JDBC连接池。配置方便,默认就是它了。
HikariCP(待测试)
(CP:Connect Pool)
依赖
maven仓库: https://mvnrepository.com/artifact/com.zaxxer/HikariCP
1 2 3 4 5
| <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>5.0.1</version> </dependency>
|
它是 Spring Boot2.0 后默认的数据库连接池,更具体的说,由 spring-boot-starter-jdbc 模块引入。
配置数据源
配置文件方式
配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| spring: datasource: driver-class-name: com.mysql.jdbc.Driver type: com.zaxxer.hikari.HikariDataSource url: mysql://localhost:5588/database?useUnicode=true&characterEncoding=UTF8&allowMultiQueries=true username: root password: root hikari: pool-name: MyHikariCP minimum-idle: 5 maximum-pool-size: 10 idle-timeout: 600000 max-lifetime: 1800000 auto-commit: true connection-test-query: SELECT 1 connection-timeout: 30000 connection-init-sql: null validation-timeout: 5000 transactionIsolation: null metric-registry: health-check-registry: initialization-fail-timeout: driver-class-name: jdbc-url: username: password:
|
配置Mybatis扫描mapper的路径
1 2 3 4 5 6
| @MapperScan(basePackages = "com.zhaolq.service.*.dao", sqlSessionTemplateRef = "pgsqlSqlSessionTemplate") public class ServiceApplication { public static void main(String[] args) SpringApplication.run(ServiceApplication.class, args); } }
|
配置类+配置文件方式
配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| @Configuration
@MapperScan("com.zhaolq.service.*.dao") public class DataSourceConfiguration { @Value("${jdbc.driver}") private String jdbcDriver;
@Value("${jdbc.url}") private String jdbcUrl;
@Value("${jdbc.username}") private String jdbcUserName;
@Value("${jdbc.password}") private String jdbcPassWord;
@Bean(name = "dataSource") public DataSource getHikariDataSource() { HikariConfig config = new HikariConfig(); config.setJdbcUrl(jdbcUrl); config.setUsername(jdbcUserName); config.setPassword(jdbcPassWord); config.setDriverClassName(jdbcDriver); config.setAutoCommit(false);
config.setMinimumIdle(3); config.setMaximumPoolSize(10); config.setIdleTimeout(600000); config.setConnectionTimeout(30000); config.setMaxLifetime(1800000); config.setConnectionTestQuery("select 1");
HikariDataSource ds = new HikariDataSource(config); return ds; }
}
|
druid-spring-boot-starter
使用Spring boot封装的Druid依赖(支持配置文件和配置类两种方式)。
依赖
1 2 3 4 5 6
| <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency>
|
配置数据源
配置文件方式
配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| spring: datasource: type: com.alibaba.druid.pool.DruidDataSource druid: driver-class-name: org.postgresql.Driver url: jdbc:postgresql://127.0.0.1:5432/testDB username: test password: test initial-size: 10 min-idle: 10 max-active: 30 time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false
pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20
filters: stat stat-view-servlet: url-pattern: /druid/* reset-enable: false login-username: admin login-password: admin enabled: true web-stat-filter: url-pattern: /* exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*" enabled: true
|
配置Mybatis扫描mapper的路径
1 2 3 4 5 6
| @MapperScan(basePackages = "com.zhaolq.service.*.dao", sqlSessionTemplateRef = "pgsqlSqlSessionTemplate") public class ServiceApplication { public static void main(String[] args) SpringApplication.run(ServiceApplication.class, args); } }
|
druid内置的监控页面:http://ip:port/server.servlet.context-path/druid/login.html,账号、密码见配置文件。
需要配置监控访问路径不拦截。
配置类+配置文件方式
配置文件
1 2 3 4 5 6 7 8 9 10
| pgsql: driver-class-name: org.postgresql.Driver rl: jdbc:postgresql://127.0.0.1:5432/testDB username: test password: test
druid: login-username: admin login-password: admin
|
配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| @Configuration @MapperScan(basePackages = "com.zhaolq.service.*.dao", sqlSessionTemplateRef = "pgsqlSqlSessionTemplate") @Slf4j public class PgsqlDataSourceConfiguration { @Value("${pgsql.driver}") private String jdbcDriver;
@Value("${pgsql.url}") private String jdbcUrl;
@Value("${pgsql.username}") private String jdbcUserName;
@Value("${pgsql.password}") private String jdbcPassWord;
@Value("${druid.login-username}") private String loginUsername;
@Value("${druid.login-password}") private String loginPassword;
@Bean(name = "pgsqlDataSource") public DataSource createDataSource() throws SQLException { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(jdbcDriver); dataSource.setUrl(jdbcUrl); dataSource.setUsername(jdbcUserName); dataSource.setPassword(jdbcPassWord);
dataSource.setInitialSize(10); dataSource.setMinIdle(10); dataSource.setMaxActive(30); dataSource.setTimeBetweenEvictionRunsMillis(60000); dataSource.setMinEvictableIdleTimeMillis(300000);
dataSource.setValidationQuery("select '1'"); dataSource.setTestWhileIdle(true); dataSource.setTestOnBorrow(false); dataSource.setTestOnReturn(false);
dataSource.setPoolPreparedStatements(false); dataSource.setMaxOpenPreparedStatements(10); dataSource.setMaxPoolPreparedStatementPerConnectionSize(10);
dataSource.setFilters("stat");
return dataSource; }
@Bean public ServletRegistrationBean druidStatViewServlet() { ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); servletRegistrationBean.addInitParameter("resetEnable", "false"); servletRegistrationBean.addInitParameter("loginUsername", loginUsername); servletRegistrationBean.addInitParameter("loginPassword", loginPassword); servletRegistrationBean.addInitParameter("ehabled", "true"); return servletRegistrationBean; }
@Bean public FilterRegistrationBean druidStatFilter() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter()); filterRegistrationBean.addUrlPatterns("/*"); filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*,/jdbc/*"); filterRegistrationBean.addInitParameter("ehabled", "true"); return filterRegistrationBean; } }
|
注:
避免配置文件过长,除了数据库连接,其他的配置全写死在配置类中。
单数据源使用配置文件方式即可。如果是多数据源,就要用配置类方式。
druid
druid 和 druid-spring-boot-starter
1)druid-spring-boot-starter只是在druid基础上进行了一次封装,专门用来整合spring-boot项目,两者配置都相同;
2)使用druid,需要手动编写配置类并注入到bean中,并加载对应的配置参数。druid-spring-boot-starter 只需要在配置文件中配置,就可实现数据库连接池的配置。
配置方式的选择
1)两种都可用的情况下,druid-spring-boot-starter 更方便,不用编写配置类。
2)druid-spring-boot-starter 由于未入库,所以开源扫描不通过,可以挂靠到其它。因此应选择 druid 依赖。
依赖
1 2 3 4 5 6
| <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.8</version> </dependency>
|
配置数据源(配置文件+配置类)
配置文件:只需要配置数据库连接相关参数,其他写死在配置类即可。
1 2 3 4 5 6 7 8 9 10
| pgsql: driver-class-name: org.postgresql.Driver rl: jdbc:postgresql://127.0.0.1:5432/testDB username: test password: test
druid: login-username: admin login-password: admin
|
配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
| @Configuration @MapperScan(basePackages = "com.zhaolq.service.*.dao", sqlSessionTemplateRef = "pgsqlSqlSessionTemplate") @Slf4j public class PgsqlDataSourceConfiguration { @Value("${pgsql.driver}") private String jdbcDriver;
@Value("${pgsql.url}") private String jdbcUrl;
@Value("${pgsql.username}") private String jdbcUserName;
@Value("${pgsql.password}") private String jdbcPassWord;
@Value("${druid.login-username}") private String loginUsername;
@Value("${druid.login-password}") private String loginPassword;
@Bean(name = "pgsqlDataSource") public DataSource createDataSource() throws SQLException { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(jdbcDriver); dataSource.setUrl(jdbcUrl); dataSource.setUsername(jdbcUserName); dataSource.setPassword(jdbcPassWord);
dataSource.setInitialSize(10); dataSource.setMinIdle(10); dataSource.setMaxActive(30); dataSource.setTimeBetweenEvictionRunsMillis(60000); dataSource.setMinEvictableIdleTimeMillis(300000);
dataSource.setValidationQuery("select '1'"); dataSource.setTestWhileIdle(true); dataSource.setTestOnBorrow(false); dataSource.setTestOnReturn(false);
dataSource.setPoolPreparedStatements(false); dataSource.setMaxOpenPreparedStatements(10); dataSource.setMaxPoolPreparedStatementPerConnectionSize(10);
dataSource.setFilters("stat");
return dataSource; }
@Bean public ServletRegistrationBean druidStatViewServlet() { ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); servletRegistrationBean.addInitParameter("resetEnable", "false"); servletRegistrationBean.addInitParameter("loginUsername", loginUsername); servletRegistrationBean.addInitParameter("loginPassword", loginPassword); servletRegistrationBean.addInitParameter("ehabled", "true"); return servletRegistrationBean; }
@Bean public FilterRegistrationBean druidStatFilter() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter()); filterRegistrationBean.addUrlPatterns("/*"); filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*,/jdbc/*"); filterRegistrationBean.addInitParameter("ehabled", "true"); return filterRegistrationBean; }
@Bean(name = "pgsqlSqlSessionFactory") public SqlSessionFactory sqlSessionFactory(@Qualifier("pgsqlDataSource") DataSource dataSource) throws IOException { SqlSessionFactory sql = null; try { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setMapperLocations( new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*/*.xml"));
Properties properties = new Properties(); properties.setProperty("helperDialect", "postgresql"); properties.setProperty("offsetAsPageNum", "true"); properties.setProperty("rowBoundsWithCount", "true"); properties.setProperty("reasonable", "true"); properties.setProperty("supportMethodsArguments", "true"); properties.setProperty("params", "pageNum=pageNumKey;pageSize=pageSizeKey;"); Interceptor interceptor = new PageInterceptor(); interceptor.setProperties(properties); factoryBean.setPlugins(new Interceptor[]{interceptor}); factoryBean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
sql = factoryBean.getObject(); } catch (Exception e) { log.error(e.getMessage(), e); } return sql; }
@Bean(name = "pgsqlTransactionManager") public DataSourceTransactionManager transactionManager(@Qualifier("pgsqlDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
@Bean(name = "pgsqlSqlSessionTemplate") public SqlSessionTemplate sqlSessionTemplate( @Qualifier("pgsqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } }
|
需要配置监控访问路径不拦截