1.C3P0连接池
快速入门官网 https://www.mchange.com/projects/c3p0/#quickstart
<dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency>
public class C3P0Pool {
public static void main(String[] args) throws PropertyVetoException, SQLException {
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass("com.mysql.cj.jdbc.Driver");
cpds.setJdbcUrl("jdbc:mysql://localhost:3306/table?useUnicode="
+ "true&characterEncoding=utf8&characterSetResults=utf8&useSSL="
+ "false&verifyServerCertificate=false&serverTimezone=GMT%2B8 ");
cpds.setUser("root");
cpds.setPassword("cgz12345678");
//最大8
cpds.setMaxPoolSize(8);
//最小2个
cpds.setMinPoolSize(2);
//初始化2 介于MinPoolSize(2)与MaxPoolSize(8)之间
cpds.setInitialPoolSize(2);
//当连接数不足时每次补充2个
cpds.setAcquireIncrement(2);
//维护statement的总个数
cpds.setMaxStatements(70);
//每个连接可以使用的statement的个数
cpds.setMaxStatementsPerConnection(10);
//最大保持的空闲时间,否则被回收 与maxConnectionAge的区别是maxConnectionAge表示活着的总时间
cpds.setMaxIdleTime(60000);
Connection connection = cpds.getConnection();
System.out.println(connection);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<named-config name="c3p0">
<!-- 配置数据库链接地址 -->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/user?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&verifyServerCertificate=false&serverTimezone=GMT%2B8</property>
<!-- 配置数据库驱动 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<!-- 当不足时,数据库连接池一次性向数据库要多少个连接对象 ,Default:3-->
<property name="acquireIncrement">20</property>
<!-- 初始化连接数,Default:3 -->
<property name="initialPoolSize">10</property>
<!-- 最小连接数 -->
<property name="minPoolSize">5</property>
<!--最大连接数。Default: 15 -->
<property name="maxPoolSize">30</property>
<!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
如果maxStatements为0,那么maxStatementsPerConnection无效,则缓存被关闭。Default:0 -->
<property name="maxStatements">0</property>
<!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数如果设置的好能提高性能。Default: 0 -->
<property name="maxStatementsPerConnection">0</property>
<!--c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能 通过多线程实现多个操作同时被执行。Default:3 -->
<property name="numHelperThreads">3</property>
<!--用户修改系统配置参数执行前最多等待300秒。Default: 300 -->
<property name="propertyCycle">300</property>
<!-- 获取连接超时设置 默认是一直等待,单位毫秒 -->
<property name="checkoutTimeout">1000</property>
<!--每多少秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod">3</property>
<!--最大空闲时间,多少秒内未被使用则连接被丢弃。若为0则永不丢弃。单位秒,Default: 0 -->
<property name="maxIdleTime">10</property>
<!--配置连接的生存时间,单位秒,超过这个时间的连接将由连接池自动断开丢弃掉。当然正在使用的连接不会马上断开,而是等待它close再断开。配置为0的时候则不会对连接的生存时间进行限制。
不为0则保持到minPoolSize -->
<property name="maxIdleTimeExcessConnections">5</property>
<!--两次连接中间隔时间,单位毫秒。Default: 1000 -->
<property name="acquireRetryDelay">1000</property>
<!--c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试使用。Default: null -->
<property name="automaticTestTable">Test</property>
<!-- 获取connnection时测试是否有效 -->
<property name="testConnectionOnCheckin">true</property>
<!-- 活着的总时间,单位秒 -->
<property name="maxConnectionAge">12</property>
</named-config>
</c3p0-config>
备注:可以按上述提供的官网书写相应的xml文件,或者是properties文件,但是名称分别必须为c3p0-config.xml和c3p0.properties,否则找不到,一个xml中可以配置多个c3p0但是<named-config name="c3p0"> 的name不同,假如在maven的 srcmain esources目录下,那么上述的获取方式为ComboPooledDataSource cpds = new ComboPooledDataSource("c3p0");
2.DBCP
api文档: http://commons.apache.org/proper/commons-dbcp/api-2.5.0/index.html
public class DBCPPoolTest {
public static void main(String[] args) throws SQLException {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUsername("root");
dataSource.setUrl("jdbc:mysql://localhost:3306/table?useUnicode="
+ "true&characterEncoding=utf8&characterSetResults=utf8&useSSL="
+ "false&verifyServerCertificate=false&serverTimezone=GMT%2B8 ");
dataSource.setPassword("12345678");
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setInitialSize(1);// 初始化连接数
// 超过8个connection在规定的的等待时间之内得不到连接则会报错
dataSource.setMaxTotal(8);// 最大连接数
// 超过maxIdle值后,刚刚使用完的连接(刚刚空闲下来)会立即被销毁。
dataSource.setMaxIdle(3);// 最大的空闲数,一般设置为MaxTotal的一半
dataSource.setMinIdle(2);// 默认是0 ,一般设置比较小为好,尽量减少连接数的空闲占用,当不足以保证时,就维持现状,当有还给连接池的对象时,又添加来保持自己
dataSource.setMaxWaitMillis(60000);// 连接池分配连接的最大时间,超过会报出异常
// 池中的连接空闲时间,超过被回收默认值就是30分钟
dataSource.setMinEvictableIdleTimeMillis(3000000);
Connection con = dataSource.getConnection();
System.out.println(con);
con.close();// 并非真正的关闭,而是将其归还到线程池
dataSource.close();
}
}
#类似c3p0的driverClass
driverClassName=com.mysql.jdbc.Driver
#传递给JDBC驱动的用于建立连接的URL
#当设置characterEncoding时useUnicode=true必须设置,characterEncoding指按指定编码解码成字节码,autoReconnect=true当数据库连接中断时是否自动重新连接,autoReconnect=true但是这个连接两次访问数据库的时间超出了服务器端wait_timeout的时间限制,还是会CommunicationsException,dontTrackOpenResources要求驱动自动跟踪和关闭资源,如果不能明确的调用作用在语句或者结果集上的close时,会造成内存溢出,设置为true可以提高某些程序的内存效率 默认false
url=jdbc:mysql://localhost:3306/testjdbc?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&dontTrackOpenResources=true
#传递给JDBC驱动的用于建立连接的用户名
username=root
#传递给JDBC驱动的用于建立连接的密码
password=cgz12345678
#初始化连接:初始化连接数量,1.2版本后支持 默认值0 jdbc-pool默认值10
initialSize=5
#最大活动连接:如果设置为非正数则表示不限制 默认值8 jdbc-pool默认值100
maxActive=8
#最大空闲连接:超过的空闲连接将被释放,如果设置为负数表示不限制 默认值8 jdbc-pool默认值
maxIdle=20
#最小空闲连接,低于这个数量将创建新的连接,如果设置为0则不创建 默认值0 jdbc-pool默认值10
minIdle=5
#最大等待时间: (以毫秒计数),超过时间则抛出异常,如果设置为-1表示无限等待 默认值:无限 jdbc-pool默认值30000ms
maxWait=28000
#连接池创建的连接的默认的auto-commit状态,默认值true
defaultAutoCommit=true
#当设置了set-onlyread,则默认值为only-read模式,当没有设置的时候不会被调用,(不支持只读模式) (某些驱动不支持只读模式,比如:Informix)
defaultReadOnly
#连接池创建的连接的默认的TransactionIsolation状态. Jdbc事物隔离级别中的一个
defaultTransactionIsolation= READ_COMMITTED
#连接池创建的连接的默认的catalog
defaultCatalog
#是否自动回收超时连接,默认值false,这个是由前提条件的,当空闲连接数小于一定数量的时候才会被触发,类似垃圾回收,回收的前提是响应时间超过removeAbandonedTimeout时间
removeAbandoned=true
#超过相应的时间没响应就回收, 单位秒 默认300
removeAbandonedTimeout=300
#是否在自动回收超时连接的时候打印连接的超时错误,默认值false jdbc-pool默认值false
logAbandoned=true
#SQL查询验证语句至少返回一条语句
validationQuery=select 1
#指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个.
#如果设置为true后如果要生效那么validationQuery参数必须设置为非空字符串 默认值:true,对连接前进行相应的检验,检验失败,则删除连接,尝试下一条连接
testOnBorrow=true
#注意: 设置为true后如果要生效,validationQuery参数必须设置为非空字符串 默认值: false jdbc-pool默认值false,指明是否在归还到池中前进行检验
testOnReturn=true
#指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败(检测是以timeBetweenEvictionRunsMilli为依据,如果超过这个时间则进行validationQuery检测连接是否有效),则连接将被从池中去除.设置为true后如果要生效,validationQuery参数必须设置为非空字符串 默认值: false
testWhileIdle=true
#空闲连接回收器线程运行时间间隔,以毫秒为单位. 如果设置为非正数,则不运行空闲连接回收器线程 默认值: -1 jdbc-pool的默认值为5000ms
timeBetweenEvictionRunsMilli=-1
#每次空闲连接回收器线程(如果有)运行时检查的连接数量 默认值:1000 * 60 * 30
numTestsPerEvictionRun
#保存空闲而不被空闲回收器回收的间隔时间
minEvictableIdleTimeMillis
#开启池的prepared statement 池功能 默认值false
poolPreparedStatements
#statement池能够同时分配的打开的statements的最大数量, 如果设置为0表示不限制 默认值:不限制
maxOpenPreparedStatements=0
#这里可以开启PreparedStatements池. 当开启时, 将为每个连接创建一个statement池,并且被下面方法创建的PreparedStatements将被缓存起来:
#PoolGuard是否容许获取底层连接 默认值false
#如果容许则可以使用下面的方式来获取底层连接:
# Connection conn = ds.getConnection();
# Connection dconn = ((DelegatingConnection) conn).getInnermostDelegate();
# ...
# conn.close();
#注意: 不要关闭底层连接, 只能关闭前面的那个.
accessToUnderlyingConnectionAllowed
4.2创建方法
方式1
final BasicDataSource dataSource = new BasicDataSource();
dataSource.setUsername("root");
dataSource.setPassword("cgz12345678");
dataSource.setUrl("jdbc:mysql://localhost:3306/testjdbc");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setInitialSize(5);
dataSource.setMaxActive(5);
dataSource.setMinIdle(2);
dataSource.setMaxWait(1000*5);
方式2
Properties properties = new Properties();
InputStream stream = jdbctestc3p0_dbcp.class.getClassLoader().getResourceAsStream("2.properties");
try {
properties.load(stream);
DataSource dataSource =
BasicDataSourceFactory.createDataSource(properties);
BasicDataSource source =(BasicDataSource)dataSource;
} catch (Exception e) {
e.printStackTrace();
}
Properties文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/testjdbc
username=root
password=cgz12345678
DBCP 是单线程的,为了保证线程安全会锁整个连接池
DBCP 性能不佳
DBCP 太复杂,超过60个类,发展滞后
还有其它的高性能连接池,如C3P0,还有阿里系的druid等
3)DRUID
API官方文档https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE
#驱动类名。 driverClassName=com.mysql.jdbc.Driver #连接数据库的url url=jdbc:mysql://127.0.0.1:3306/day25 #数据库的用户名 username=root #数据库的密码 password=12345678 #初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 initialSize=5 #最大连接池数量 maxActive=10 #获取连接时最大等待时间 maxWait=3000 #已经不再使用,配置了也没效果 maxIdle=6 #最小连接池数量 minIdle=3
// 加载配置文件中的配置参数
InputStream is = Demo03.class.getResourceAsStream("/druid.properties");
Properties pp = new Properties();
pp.load(is);
// 创建连接池,使用配置文件中的参数
DataSource ds = DruidDataSourceFactory.createDataSource(pp);
备注:连接池超标报异常
4)自定义线程池
package cn.test.javamail.massage;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import sun.applet.Main;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Logger;
public class MyDataSourcePool implements DataSource {
private int initCount ;
private int maxCount ;
private int curCount ;
private List<Connection> list= new LinkedList();
public MyDataSourcePool(int initCount, int maxCount) throws SQLException, IOException, ClassNotFoundException {
this.initCount = initCount;
this.maxCount = maxCount;
for (int i = 0; i < initCount; i++) {
Connection connect = getConnect();
list.add(connect);
curCount++;
}
}
@Override
public Connection getConnection() throws SQLException {
Connection connection=null;
if(list.size()>0){
connection = list.get(0);
list.remove(0);
}else if(curCount<maxCount){
try {
Connection connect = getConnect();//不足的时候每次创建一个
list.add(connect);
curCount++;
connection = list.get(0);
list.remove(0);
} catch (Exception e) {
e.printStackTrace();
}
}else{
new RuntimeException("已经满了");
}
return connection;
}
public void close(Connection connect){//c3p0的close重写内部的方法
list.add(connect);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
public Connection getConnect() throws IOException, ClassNotFoundException, SQLException {
Properties ps = new Properties();
InputStream is = this.getClass().getClassLoader().getResourceAsStream("config.properties");
ps.load(is);
Class.forName(ps.getProperty("driverClass"));
Connection connection = DriverManager.getConnection(ps.getProperty("url"), ps);
return connection;
}
}