拓展阅读
万字长文深入浅出数据库连接池 HikariCP/Commons DBCP/Tomcat/c3p0/druid 对比
从零开始手写 mybatis (三)jdbc pool 如何从零手写实现数据库连接池 dbcp?
万字长文深入浅出数据库连接池 HikariCP/Commons DBCP/Tomcat/c3p0/druid 对比
Database Connection Pool 数据库连接池概览
c3p0 数据池入门使用教程
alibaba druid 入门介绍
数据库连接池 HikariCP 性能为什么这么快?
Apache Tomcat DBCP(Database Connection Pool) 数据库连接池-01-入门介绍
vibur-dbcp 并发、快速且功能完备的 JDBC 连接池,提供先进的性能监控功能-01-入门介绍
前言
数据库连接池在日常开发中几乎是必备的技能,但是很多知识大多比较零散。
这里老马为大家简单做一个汇总,便于查阅学习。
连接池的作用
资源重用
由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,
另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。
更快的系统响应速度
数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。
对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
新的资源分配手段
对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,使用数据库连接池技术。
设置某一应用最大可用数据库连接数,避免某一应用独占所有数据库资源。
统一的连接管理,避免数据库连接泄漏
在较为完备的数据库连接池实现中,可根据预先设定的连接占用超时时间,强制收回被超时占用的连接。
从而避免了常规数据库连接操作中可能出现的资源泄漏(当程序存在缺陷时,申请的连接忘记关闭,这时候,就存在连接泄漏了)。
常见的优秀开源组件有哪些?
有关数据库连接池的优秀开源组件:
HikariCP: HikariCP 是一个高性能的 JDBC 连接池,被广泛认为是目前性能最好的 JDBC 连接池之一。它具有快速启动、低资源消耗和高性能等特点,适用于各种规模的应用程序。
Apache Commons DBCP: Apache Commons DBCP 是 Apache 软件基金会的一个子项目,提供了一个可靠的 JDBC 连接池实现。它支持基本的连接池功能,并且易于集成到各种 Java 应用程序中。
Tomcat JDBC Pool: Tomcat JDBC Pool 是 Apache Tomcat 项目的一个组件,提供了一个可靠的 JDBC 连接池实现。它专为在 Tomcat 环境下使用而设计,但也可以作为独立的连接池使用。
H2 Database Connection Pool: H2 Database 是一个嵌入式数据库,它也提供了一个简单而有效的 JDBC 连接池实现。虽然它主要用于嵌入式数据库的应用场景,但也可以作为独立的连接池使用。
c3p0: c3p0 是一个流行的 JDBC 连接池实现,具有丰富的配置选项和可靠的性能。它支持连接池的高度定制,并且在很多企业级应用中被广泛使用。
Druid: Druid 是阿里巴巴开源的一个数据库连接池实现,它不仅提供了连接池功能,还提供了监控、统计、防火墙等高级功能。Druid 被广泛应用于大型互联网企业的生产环境中。
对比
HikariCP 2.6.0、commons-dbcp2 2.1.1、Tomcat 8.0.24、Vibur 16.1、c3p0 0.9.5.2
以下是对上述数据库连接池组件的详细对比:
特性 | HikariCP | Apache Commons DBCP | Tomcat JDBC Pool | H2 Database Connection Pool | c3p0 | Druid |
---|---|---|---|---|---|---|
性能 | 非常高 | 一般 | 一般 | 一般 | 一般 | 非常高 |
配置简单性 | 高 | 中等 | 中等 | 低 | 中等 | 中等 |
可定制性 | 中等 | 中等 | 低 | 低 | 高 | 高 |
监控和统计功能 | 有 | 无 | 无 | 无 | 无 | 有 |
防火墙功能 | 无 | 无 | 无 | 无 | 无 | 有 |
社区活跃度 | 高 | 中等 | 中等 | 低 | 中等 | 高 |
适用场景 | 各种场景 | 一般场景 | Tomcat 环境 | 嵌入式数据库场景 | 各种场景 | 大型互联网企业环境 |
是否支持连接池复用 | 是 | 是 | 是 | 是 | 是 | 是 |
支持的数据库 | 所有主流数据库 | 所有主流数据库 | 所有主流数据库 | H2 Database | 所有主流数据库 | 所有主流数据库 |
看得出来,Druid 和 HikariCP 性能是最优异的。
不过别着急,我们慢慢来,先看看其他的。
DBCP组件
介绍
许多Apache项目支持与关系型数据库进行交互。为每个用户创建一个新连接可能很耗时(通常需要多秒钟的时钟时间),以执行可能需要毫秒级时间的数据库事务。对于一个公开托管在互联网上的应用程序,在同时在线用户数量可能非常大的情况下,为每个用户打开一个连接可能是不可行的。因此,开发人员通常希望在所有当前应用程序用户之间共享一组“池化”的打开连接。在任何给定时间实际执行请求的用户数量通常只是活跃用户总数的非常小的百分比,在请求处理期间是唯一需要数据库连接的时间。应用程序本身登录到DBMS,并在内部处理任何用户账户问题。
已经有几个数据库连接池可用,包括Apache产品内部和其他地方。这个Commons包提供了一个机会,来协调创建和维护一个高效、功能丰富的包,以Apache许可证发布。
commons-dbcp2依赖于commons-pool2中的代码,以提供底层的对象池机制。
maven 引入
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.9.0</version>
</dependency>
代码
https://github.com/apache/commons-dbcp/tree/HEAD/doc
PoolingDataSourceExample
这里的 datasource 是池化的。
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.dbcp2.ConnectionFactory;
import org.apache.commons.dbcp2.PoolableConnection;
import org.apache.commons.dbcp2.PoolingDataSource;
import org.apache.commons.dbcp2.PoolableConnectionFactory;
import org.apache.commons.dbcp2.DriverManagerConnectionFactory;
public class PoolingDataSourceExample {
public static void main(String[] args) {
//
// First we load the underlying JDBC driver.
// You need this if you don't use the jdbc.drivers
// system property.
//
System.out.println("Loading underlying JDBC driver.");
try {
Class.forName("org.h2.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("Done.");
//
// Then, we set up the PoolingDataSource.
// Normally this would be handled auto-magically by
// an external configuration, but in this example we'll
// do it manually.
//
System.out.println("Setting up data source.");
DataSource dataSource = setupDataSource(args[0]);
System.out.println("Done.");
//
// Now, we can use JDBC DataSource as we normally would.
//
Connection conn = null;
Statement stmt = null;
ResultSet rset = null;
try {
System.out.println("Creating connection.");
conn = dataSource.getConnection();
System.out.println("Creating statement.");
stmt = conn.createStatement();
System.out.println("Executing statement.");
rset = stmt.executeQuery(args[1]);
System.out.println("Results:");
int numcols = rset.getMetaData().getColumnCount();
while(rset.next()) {
for(int i=1;i<=numcols;i++) {
System.out.print("\t" + rset.getString(i));
}
System.out.println("");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (rset != null)
rset.close();
} catch (Exception e) {
}
try {
if (stmt != null)
stmt.close();
} catch (Exception e) {
}
try {
if (conn != null)
conn.close();
} catch (Exception e) {
}
}
}
// 这里的 datasource 是池化的。
public static DataSource setupDataSource(String connectURI) {
//
// First, we'll create a ConnectionFactory that the
// pool will use to create Connections.
// We'll use the DriverManagerConnectionFactory,
// using the connect string passed in the command line
// arguments.
//
ConnectionFactory connectionFactory =
new DriverManagerConnectionFactory(connectURI, null);
//
// Next we'll create the PoolableConnectionFactory, which wraps
// the "real" Connections created by the ConnectionFactory with
// the classes that implement the pooling functionality.
//
PoolableConnectionFactory poolableConnectionFactory =
new PoolableConnectionFactory(connectionFactory, null);
//
// Now we'll need a ObjectPool that serves as the
// actual pool of connections.
//
// We'll use a GenericObjectPool instance, although
// any ObjectPool implementation will suffice.
//
ObjectPool<PoolableConnection> connectionPool =
new GenericObjectPool<>(poolableConnectionFactory);
// Set the factory's pool property to the owning pool
poolableConnectionFactory.setPool(connectionPool);
//
// Finally, we create the PoolingDriver itself,
// passing in the object pool we created.
//
PoolingDataSource<PoolableConnection> dataSource =
new PoolingDataSource<>(connectionPool);
return dataSource;
}
}
更多内容,可参考
apache commons dbcp2
c3p0
是什么?
c3p0是一个易于使用的库,通过使用jdbc3规范和jdbc2的可选扩展定义的功能来扩展传统JDBC驱动程序,从而使其“企业就绪”。
从0.9.5版开始,c3p0完全支持jdbc4规范。
特别是c3p0提供了一些有用的服务:
一个类,它使传统的基于DriverManager的JDBC驱动程序适应最新的javax.sql.DataSource方案,以获取数据库连接。
DataSources后面的Connection和PreparedStatement的透明池可以“包装”传统驱动程序或任意非池化DataSources。
该库尽力使细节正确:
c3p0数据源既可引用也可序列化,因此适合绑定到各种基于JNDI的命名服务。
检入池中的Connections和Statements时,会仔细清理Statement和ResultSet,以防止客户端使用仅清理其Connections的惰性但常见的资源管理策略时资源耗尽。
该库采用JDBC 2和3规范定义的方法(即使这些与库作者的首选项冲突)。
数据源以JavaBean样式编写,提供了所有必需和大多数可选属性(以及一些非标准属性)以及无参数构造函数。
实现了所有JDBC定义的内部接口(ConnectionPoolDataSource,PooledConnection,生成ConnectionEvent的Connection等)。
您可以将c3p0类与兼容的第三方实现混合使用(尽管并非所有c3p0功能都可以与ConnectionPoolDataSource的外部实现一起使用)。
c3p0希望提供的数据源实现不适合大批量“ J2EE企业应用程序”使用。
maven 导入
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
入门代码
通过代码显式指定配置:
ComboPooledDataSource source = new ComboPooledDataSource();
source.setDriverClass("com.mysql.jdbc.Driver");
source.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8");
source.setUser("root");
source.setPassword("123456");
//获取链接
Connection connection = source.getConnection();
System.out.println(connection.getCatalog());
- 日志输出
七月 17, 2020 4:58:21 下午 com.mchange.v2.log.MLog
信息: MLog clients using java 1.4+ standard logging.
七月 17, 2020 4:58:22 下午 com.mchange.v2.c3p0.C3P0Registry
信息: Initializing c3p0-0.9.5.5 [built 11-December-2019 22:18:33 -0800; debug? true; trace: 10]
七月 17, 2020 4:58:22 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource
信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 1bqqx35abpix6b312lrdzj|7bfcd12c, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1bqqx35abpix6b312lrdzj|7bfcd12c, idleConnectionTestPeriod -> 0, initialPoolSize -> 2, jdbcUrl -> jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 30, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 10, maxStatements -> 50, maxStatementsPerConnection -> 0, minPoolSize -> 2, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
test
更多内容,可参考
c3p0
tomcat jdbc pool
是什么?
Apache Tomcat DBCP(Database Connection Pool)是一个用于管理数据库连接的组件,通常与Apache Tomcat服务器一起使用。
它提供了一种机制来有效地管理数据库连接,以便在高负载下提供更好的性能和可伸缩性。
以下是Tomcat DBCP的一些关键特性和工作原理:
连接池管理: Tomcat DBCP通过创建和维护一组预先配置的数据库连接来管理连接池。这些连接在需要时可以被应用程序使用,并在不再需要时释放回池中。
连接池参数配置: 可以通过Tomcat的配置文件(如context.xml)或者直接在应用程序中的代码中配置连接池的各种参数,例如最大连接数、最小连接数、最大等待时间等。
连接池的工作流程: 当应用程序需要与数据库进行交互时,它从连接池中请求一个数据库连接。如果连接池中有空闲的连接可用,连接池会将一个连接分配给应用程序。一旦应用程序完成了对数据库的操作,它将连接返回给连接池,以供其他应用程序使用。
连接验证: Tomcat DBCP可以配置为在从连接池中获取连接时验证连接的有效性。这可以通过执行简单的SQL查询或其他形式的连接测试来实现。这有助于确保从池中获取的连接是可用和有效的。
性能优化: 通过维护一组已经打开的数据库连接,Tomcat DBCP可以避免在每次数据库请求时都重新创建和销毁连接,从而提高了性能和效率。
异常处理: Tomcat DBCP能够处理数据库连接的异常情况,例如数据库服务器断开连接或者连接超时。它会尝试重新建立连接或者返回错误信息,以便应用程序能够适当地处理这些异常情况。
监控和管理: Tomcat DBCP提供了监控和管理连接池的功能,可以通过JMX(Java Management Extensions)接口来查看连接池的状态、活动连接数、空闲连接数等信息,并且可以通过管理工具对连接池进行操作。
为什么 tomcat 要自研,而不是用 apache dbcp 这些已有的?
Apache Tomcat 一开始确实使用了像 Commons DBCP 和 Commons Pool 这样的外部组件来管理数据库连接池。
然而,后来 Apache Tomcat 团队决定开发自己的连接池实现,即 Tomcat DBCP。
这是有几个原因的:
更好的集成: 将连接池功能直接集成到 Tomcat 中可以提供更好的性能和更好的集成。这样做可以更好地与 Tomcat 内部的线程管理、类加载器和上下文生命周期等功能集成,以便提供更一致和更可靠的连接池管理。
性能优化: Apache Tomcat 团队可以更深入地了解 Tomcat 本身的内部工作原理,以优化连接池的性能,使其更适合与 Tomcat 一起使用。自己实现的连接池可能会针对 Tomcat 的特定需求进行优化,以提供更好的性能和可靠性。
更好的控制: 通过开发自己的连接池实现,Apache Tomcat 团队可以更好地控制连接池的开发和维护过程。他们可以根据自己的需求进行定制和扩展,而不受外部库的限制。
解决特定问题: 有时候外部库可能存在一些限制或者问题,而开发自己的实现可以更灵活地解决这些问题。可能是因为在特定的使用情况下,已有的库无法满足 Tomcat 的需求,或者为了解决一些已知的问题而决定开发自己的实现。
入门例子
确保你已经在Tomcat的
lib
目录中包含commons-dbcp.jar
和commons-pool.jar
。在你的Web应用程序的
WEB-INF
目录下创建一个名为context.xml
的文件,并在其中配置数据库连接池。
以下是一个示例context.xml
文件:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="#{username}" password="#{password}"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/#{database}"/>
</Context>
- 在你的Web应用程序中,你可以通过JNDI查找来获取数据库连接。以下是一个简单的Servlet示例,演示如何获取数据库连接并执行查询:
import java.io.*;
import java.sql.*;
import javax.naming.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.sql.*;
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
Connection conn = null;
try {
// 查找上下文中的数据库连接池
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/TestDB");
// 从连接池获取连接
conn = ds.getConnection();
// 执行查询
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM your_table");
while (rs.next()) {
out.println("ID: " + rs.getInt("id") + ", Name: " + rs.getString("name"));
out.println("<br/>");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
拓展阅读:
更多细节,参见 tomcat dbcp
vibur dbcp
是什么?
Vibur DBCP 是一个并发、快速且功能完备的 JDBC 连接池,提供先进的性能监控功能,包括慢 SQL 查询的检测和记录、应用线程的非饥饿保证、语句缓存以及与 Hibernate 集成等特性。
该项目主页包含了对所有 Vibur 特性和配置选项的详细描述,以及与 Hibernate 和 Spring 的各种配置示例等内容。
Vibur DBCP 基于 Vibur Object Pool 构建,后者是一个通用的并发 Java 对象池。
特性
主要特点一览
确保没有线程会被排除在访问 JDBC 连接池连接之外。参见 poolFair 配置参数。
检测和记录慢 SQL 查询、大于预期的 ResultSet 和持续时间较长的 getConnection() 方法调用。查看相关的配置属性 这里 和 这里。
支持 Hibernate 3.6、4.x 和 5.x 的集成。
对 JDBC Statement(Prepared 和 Callable)进行缓存支持。
使用标准 Java 并发工具和动态代理构建,不使用任何 synchronized 块或方法。
Vibur DBCP 需要 Java 1.6+,并且仅有以下外部依赖项:其专用对象池、slf4j/log4j 和 ConcurrentLinkedHashMap。CLHM 依赖项是可
选的,只有在启用/使用 JDBC Statement 缓存时,应用程序才需要提供它。
其他特点
智能池大小调整 - 根据最近使用的连接数量的启发式方法,可以减少 JDBC 池中的空闲连接数量。
支持验证间隔;即,在每次使用之前,从 JDBC 池获取的连接并不会被验证,只有在连接上一次使用后经过一定时间后才会进行验证。
可以通过调用代理的 unwrap 方法从相应的代理对象中检索原始 JDBC 连接或 Statement 对象。
为当前获取的所有 JDBC 连接提供记录(通过 JMX 或日志文件),包括它们被获取时的堆栈跟踪;如果调试丢失/未关闭的连接或者应用程序
想知道当前所有连接的来源,这将非常有用。JMX 支持 - 池注册了一个 MBean,通过它可以观察和/或设置各种池参数。
maven 依赖
<dependency>
<groupId>org.vibur</groupId>
<artifactId>vibur-dbcp</artifactId>
<version>25.0</version>
</dependency>
Spring with Hibernate 3.6/4.x/5.x Configuration Snippet
<!-- Vibur DBCP dataSource bean definition: -->
<bean id="dataSource" class="org.vibur.dbcp.ViburDBCPDataSource" init-method="start" destroy-method="terminate">
<property name="jdbcUrl" value="jdbc:hsqldb:mem:sakila;shutdown=false"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
<property name="poolInitialSize">10</property>
<property name="poolMaxSize">100</property>
<property name="connectionIdleLimitInSeconds">30</property>
<property name="testConnectionQuery">isValid</property>
<property name="logQueryExecutionLongerThanMs" value="500"/>
<property name="logStackTraceForLongQueryExecution" value="true"/>
<property name="statementCacheMaxSize" value="200"/>
</bean>
<!-- For Hibernate5 set the sessionFactory class below to org.springframework.orm.hibernate5.LocalSessionFactoryBean -->
<!-- For Hibernate4 set the sessionFactory class below to org.springframework.orm.hibernate4.LocalSessionFactoryBean -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="the.project.packages"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
</props>
</property>
</bean>
<!-- For Hibernate5 set the transactionManager class below to org.springframework.orm.hibernate5.HibernateTransactionManager -->
<!-- For Hibernate4 set the transactionManager class below to org.springframework.orm.hibernate4.HibernateTransactionManager -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Programming Configuration Snippet
public DataSource createDataSourceWithStatementsCache() {
ViburDBCPDataSource ds = new ViburDBCPDataSource();
ds.setJdbcUrl("jdbc:hsqldb:mem:sakila;shutdown=false");
ds.setUsername("sa");
ds.setPassword("");
ds.setPoolInitialSize(10);
ds.setPoolMaxSize(100);
ds.setConnectionIdleLimitInSeconds(30);
ds.setTestConnectionQuery("isValid");
ds.setLogQueryExecutionLongerThanMs(500);
ds.setLogStackTraceForLongQueryExecution(true);
ds.setStatementCacheMaxSize(200);
ds.start();
return ds;
}
vibur 的性能相比较其他的,算是比较优异的。但是 github star 比较少。
配置项特别多,感兴趣的话 参见 vibur dbcp
alibaba druid
这个在国内应该算是家喻户晓了,介绍的文章非常多,这里只做简单介绍。
是什么
Druid是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能。
PS:国内的话,还是非常推荐使用这个的。
一些优秀的能力
高性能:Druid 连接池被设计为高性能的连接池,具有优秀的连接获取、归还速度以及低延迟的特点,能够满足高并发的数据库访问需求。
实时监控:Druid 连接池提供了丰富的实时监控功能,能够实时地监控连接池的状态、性能指标以及数据库访问情况,帮助用户及时发现和解决潜在的问题。
连接池扩展:Druid 连接池支持连接池的动态扩展和收缩,能够根据实际的数据库访问负载自动调整连接池的大小,提高资源利用率。
SQL防火墙:Druid 连接池内置了 SQL 防火墙功能,能够对用户提交的 SQL 进行实时的安全检查和过滤,防止 SQL 注入等安全问题。
连接泄漏检测:Druid 连接池能够检测连接的泄漏情况,及时发现并处理连接未正确关闭的情况,防止因连接泄漏导致的数据库资源浪费和性能下降。
完善的统计功能:Druid 连接池提供了丰富的统计功能,能够统计连接池的使用情况、性能指标以及数据库访问情况,帮助用户深入了解数据库访问的情况。
多数据源支持:Druid 连接池支持多种类型的数据库,包括 MySQL、Oracle、PostgreSQL 等,能够灵活适应不同类型的数据库访问需求。
maven
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.15</version>
</dependency>
配置
DruidDataSource大部分属性都是参考DBCP的,如果你原来就是使用DBCP,迁移是十分方便的。
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc_url}" />
<property name="username" value="${jdbc_user}" />
<property name="password" value="${jdbc_password}" />
<property name="filters" value="stat" />
<property name="maxActive" value="20" />
<property name="initialSize" value="1" />
<property name="maxWait" value="6000" />
<property name="minIdle" value="1" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="poolPreparedStatements" value="true" />
<property name="maxOpenPreparedStatements" value="20" />
<property name="asyncInit" value="true" />
</bean>
这个是 spring 的配置,其实配置上就是一个 POJO
感兴趣的话,可以拓展一下:
alibaba druid-01-intro 入门介绍
alibaba druid-02-FAQ druid 常见问题
druid+mysql 个人实战例子
这里以 durid 做一个实战例子,其他的也都大同小异。
mysql 数据准备
建表语句
use test;
CREATE TABLE "users" (
"id" int(11) NOT NULL,
"username" varchar(255) NOT NULL,
"email" varchar(255) NOT NULL,
PRIMARY KEY ("id")
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
插入数据
insert into users (id, username, email) values (1, 'u-1', '1@email.com');
insert into users (id, username, email) values (2, 'u-2', '2@email.com');
insert into users (id, username, email) values (3, 'u-3', '3@email.com');
数据确认:
mysql> select * from users;
+----+----------+-------------+
| id | username | email |
+----+----------+-------------+
| 1 | u-1 | 1@email.com |
| 2 | u-2 | 2@email.com |
| 3 | u-3 | 3@email.com |
+----+----------+-------------+
3 rows in set (0.00 sec)
数据库准备
maven 引入
<!-- MySQL JDBC Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version> <!-- 或者最新版本 -->
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.15</version>
</dependency>
入门代码
package com.github.houbb.calcite.learn.mysql;
import com.alibaba.druid.pool.DruidDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* druid 整合 mysql 使用
* @author 老马啸西风
*/
public class DruidMySQLExample {
public static void main(String[] args) {
// 初始化 Druid 数据源
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC");
dataSource.setUsername("admin");
dataSource.setPassword("123456");
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 从连接池获取数据库连接
conn = dataSource.getConnection();
// 创建 Statement 对象
stmt = conn.createStatement();
// 执行 SQL 查询
rs = stmt.executeQuery("SELECT * FROM users");
// 遍历结果集
while (rs.next()) {
// 处理每一行数据
int id = rs.getInt("id");
String username = rs.getString("username");
String email = rs.getString("email");
// 输出到控制台
System.out.println("ID: " + id + ", username: " + username+ ", email: " + email);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭资源
try {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
输出如下:
ID: 1, username: u-1, email: 1@email.com
ID: 2, username: u-2, email: 2@email.com
ID: 3, username: u-3, email: 3@email.com
我本来以为 druid 已经天下无敌了,没想到 HikariCP 更加勇猛。
HikariCP 是谁的部将?
HikariCP
是什么?
快速、简单、可靠。HikariCP 是一个“零额外开销”的生产就绪的 JDBC 连接池。
该库大小约为130Kb,非常轻量级。
构件 Artifacts
Java 11+ Maven 构件
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.1.0</version>
</dependency>
Java 8 Maven 构件 (维护模式)
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
配置使用
这个返回比较简单,都是统一的。
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/simpsons");
config.setUsername("bart");
config.setPassword("51mp50n");
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
HikariDataSource ds = new HikariDataSource(config);
Hikari 为什么这么快?
为什么 Hikari 可以做到性能基本无损耗?到底是如何实现的。
这也是本文的重点,也是老马为什么写这篇文章的原因。