写点什么

Spring Boot「17」数据库连接池

作者:Samson
  • 2022-10-27
    上海
  • 本文字数:3319 字

    阅读完需:约 11 分钟

Spring Boot 2.x 之后,默认使用 HikariCP 作为其默认的数据库连接池组件,在 1.x 版本中,使用的是 Tomcat Connection Pool。使用数据库连接池的出发点与线程池类似,通过将链接保存在连接池中来减少频繁创建、关闭连接的性能损失,以提升应用的整体性能。

01-简易的连接池实现

虽然业界已经存在许多非常成熟、性能优良的数据库连接池组件,例如 HikariCP、Tomcat Connection Pool、DBCP、C3P0 等。从价值上看,重复造轮子是一件费力不讨好的事情;但从学习连接池基本思想的角度上看,通过实现一个简易的连接池来探究数据库连接池的基本工作原理是非常有意义,且有价值的。


首先,我们定义一个连接池接口:


public interface MyConnectionPool {    Connection getConnection();    boolean releaseConnection(Connection connection);
String getUrl(); String getUser(); String getPassword();}
复制代码


它虽然简单,但是基本上涵盖了一个数据库连接池应当支持的最基础操作。之后,我们可以尝试实现它。


public class MyNaiveConnectionPoolImpl implements MyConnectionPool {    private final static Integer DEFAULT_CONNECTION_POOL_SIZE = 10;    static {
} public static MyNaiveConnectionPoolImpl createPool( String url, String user, String password) throws SQLException{ List<Connection> pool = new ArrayList<>(DEFAULT_CONNECTION_POOL_SIZE); for (int i = 0; i < DEFAULT_CONNECTION_POOL_SIZE; ++i) { pool.add(createConnection(url, user, password)); }
return new MyNaiveConnectionPoolImpl(url, user, password, pool); }
public static MyNaiveConnectionPoolImpl createPool( String url, String user, String password, Integer maxSize) throws SQLException{
final MyNaiveConnectionPoolImpl pool = createPool(url, user, password); pool.setMaxSize(maxSize); return pool; }
private String url; private String user; private String password;
private Integer maxSize; private List<Connection> connectionPool; private List<Connection> usedConnections = new ArrayList<>();
public MyNaiveConnectionPoolImpl(String url, String user, String password, Integer maxSize, List<Connection> connectionPool) { this.url = url; this.user = user; this.password = password; this.connectionPool = connectionPool; this.maxSize = maxSize; }
public MyNaiveConnectionPoolImpl(String url, String user, String password, List<Connection> connectionPool) { this(url, user, password, DEFAULT_CONNECTION_POOL_SIZE, connectionPool); }

@Override public Connection getConnection() throws SQLException { if (this.connectionPool.isEmpty()) { if (usedConnections.size() < maxSize) { this.connectionPool.add(createConnection(url, user, password)); } } final Connection conn = this.connectionPool.remove(connectionPool.size() - 1); this.usedConnections.add(conn); return conn; }
private static Connection createConnection(String url, String user, String password) throws SQLException{ return DriverManager.getConnection(url, user, password); }
@Override public boolean releaseConnection(Connection connection) { this.connectionPool.add(connection); return this.usedConnections.remove(connection); }
@Override public String getUrl() { return this.url; }
@Override public String getUser() { return this.user; }
@Override public String getPassword() { return this.password; }
public void setMaxSize(Integer maxSize) { this.maxSize = maxSize; }}
复制代码


如何使用自定义的数据库连接池呢?


MyConnectionPool cp = MyNaiveConnectionPoolImpl.createPool("jdbc:h2:mem:testdb", "sa", "password", 20);
复制代码


如何关闭连接池?


public void shutdown() throws SQLException{    this.usedConnections.forEach(this::releaseConnection);    for (Connection connection : this.connectionPool) {    connection.close();    }    connectionPool.clear();}
复制代码

02-常用的连接池组件

业界常用的数据库连接池组件有:HikariCP、Apache Commons DBCP、C3P0、Tomcat Connection Pool 等;Spring Boot 2.x 版本以后,默认使用 HikariCP。如果想使用其他的数据库连接池可以按照如下方法替换:


  1. 在 pom.xml 中排除 HikariCP 的依赖


<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-jpa</artifactId>    <exclusions>        <exclusion>            <groupId>com.zaxxer</groupId>            <artifactId>HikariCP</artifactId>        </exclusion>    </exclusions></dependency>
复制代码


  1. 增加其他的数据库连接池实现,例如 Tomcat Connection Pool(Spring Boot 1.x 默认的数据库连接池)


<dependency>    <groupId>org.apache.tomcat</groupId>    <artifactId>tomcat-jdbc</artifactId>    <version>9.0.10</version></dependency>
复制代码


运行 Spring Boot 应用,发现 DataSource 已经是org.apache.tomcat.jdbc.pool.DataSource类型。关于 Spring Boot 查找数据库链接池的算法细节,可以参考官网Supported Connection Pools


不同数据库连接池使用得 DataSource 类型(Spring Boot 会根据 classpath 下 jar 包自动创建 DataSource Bean):


  • HikariCP,com.zaxxer.hikari.HikariDataSource

  • Tomcat Connection Pool,org.apache.tomcat.jdbc.pool.DataSource

  • Commons DBCP2,org.apache.commons.dbcp2.BasicDataSource


如果要自定义各种设置,可以通过如下方式:


public class DataSourceConfig {    private static HikariConfig hikariConfig = new HikariConfig();    private static HikariDataSource hikariDataSource;
static { hikariConfig.setJdbcUrl("jdbc:h2:mem:test"); hikariConfig.setUsername("user"); hikariConfig.setPassword("password"); hikariConfig.addDataSourceProperty("cachePrepStmts", "true"); hikariConfig.addDataSourceProperty("prepStmtCacheSize", "250"); hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); hikariDataSource = new HikariDataSource(hikariConfig); }
public static Connection getConnection() throws SQLException { return hikariDataSource.getConnection(); }
public DataSourceConfig() { }}
复制代码


上述 DataSource 也支持通过 Spring DataSourceBuilder 手动创建。例如(等价于上述的写法):


@Beanpublic DataSource dataSource() {    DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();    dataSourceBuilder.driverClassName("org.h2.Driver");    dataSourceBuilder.url("jdbc:h2:mem:test");    dataSourceBuilder.username("user");    dataSourceBuilder.password("password");    return dataSourceBuilder.build();    }
复制代码


除此之外,还支持下述类型的 DataSource。


  • Spring JDBC,org.springframework.jdbc.datasource.SimpleDriverDataSource

  • H2 JdbcDataSource

  • PostgreSQL PGSimpleDataSource

  • C3P0,com.mchange.v2.c3p0.ComboPooledDataSource

发布于: 刚刚阅读数: 3
用户头像

Samson

关注

还未添加个人签名 2019-07-22 加入

InfoQ签约作者 | 阿里云社区签约作者

评论

发布
暂无评论
Spring Boot「17」数据库连接池_Java_Samson_InfoQ写作社区