什么是数据库连接池,为什么用连接池?
数据库连接池就是保存若干个Connection对象一个连接池对象。使用池来管理,可以重复使用Connection。有了池,可以不用自己来创建连接。直接通过池对象获取,用完后,调用Connecition的close()方法,将Connection对象返还给池。
JDBC数据库连接池接口
Java中并没有实现连接池,但是规定了所有三方实现的连接池必须实现java.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:
- Connection getConnection()
- Connection getConnection(String username, String password)
连接池参数
初始大小:初始创建多少个Connection对象
最小空闲连接数:低于这个数量,就新建连接对象
增量:一次创建的最小单位
最大空闲连接数:超过这个数量,就关闭多余的连接对象
最大的连接数:超出数量,就需要进行等待
下面介绍两个连接池
BDCP
DBCP是Apache提供的一款开源免费的数据库连接池。
使用前需要导入连个jar包
- commons-dbcp-xx.jar
- commons-pool-xx.jar
代码
@Test
public void func() throws SQLException {
//建立连接池对象
BasicDataSource bd=new BasicDataSource();
//设置四大参数
bd.setDriverClassName("com.mysql.jdbc.Driver");
bd.setUrl("jdbc:mysql://localhost:3306/sql_test");
bd.setUsername("root");
bd.setPassword("123456");
//设置池参数
bd.setMaxActive(20);//最大连接数
bd.setMinIdle(3);//大小空闲连接
bd.setMaxWait(1000);//最大等待时间
//获得连接
Connection cn=bd.getConnection();
//输出连接名
System.out.println(cn.getClass().getName());
}
附上BDCP配置信息
#基本配置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb1
username=root
password=123
#初始化池大小,即一开始池中就会有10个连接对象
默认值为0
initialSize=0
#最大连接数,如果设置maxActive=50时,池中最多可以有50个连接,当然这50个连接中包含被使用的和没被使用的(空闲)
#你是一个包工头,你一共有50个工人,但这50个工人有的当前正在工作,有的正在空闲
#默认值为8,如果设置为非正数,表示没有限制!即无限大
maxActive=8
#最大空闲连接
#当设置maxIdle=30时,你是包工头,你允许最多有20个工人空闲,如果现在有30个空闲工人,那么要开除10个
#默认值为8,如果设置为负数,表示没有限制!即无限大
maxIdle=8
#最小空闲连接
#如果设置minIdel=5时,如果你的工人只有3个空闲,那么你需要再去招2个回来,保证有5个空闲工人
#默认值为0
minIdle=0
#最大等待时间
#当设置maxWait=5000时,现在你的工作都出去工作了,又来了一个工作,需要一个工人。
#这时就要等待有工人回来,如果等待5000毫秒还没回来,那就抛出异常
#没有工人的原因:最多工人数为50,已经有50个工人了,不能再招了,但50人都出去工作了。
#默认值为-1,表示无限期等待,不会抛出异常。
maxWait=-1
#连接属性
#就是原来放在url后面的参数,可以使用connectionProperties来指定
#如果已经在url后面指定了,那么就不用在这里指定了。
#useServerPrepStmts=true,MySQL开启预编译功能
#cachePrepStmts=true,MySQL开启缓存PreparedStatement功能,
#prepStmtCacheSize=50,缓存PreparedStatement的上限
#prepStmtCacheSqlLimit=300,当SQL模板长度大于300时,就不再缓存它
connectionProperties=useUnicode=true;characterEncoding=UTF8;useServerPrepStmts=true;cachePrepStmts=true;prepStmtCacheSize=50;prepStmtCacheSqlLimit=300
#连接的默认提交方式
#默认值为true
defaultAutoCommit=true
#连接是否为只读连接
#Connection有一对方法:setReadOnly(boolean)和isReadOnly()
#如果是只读连接,那么你只能用这个连接来做查询
#指定连接为只读是为了优化!这个优化与并发事务相关!
#如果两个并发事务,对同一行记录做增、删、改操作,是不是一定要隔离它们啊?
#如果两个并发事务,对同一行记录只做查询操作,那么是不是就不用隔离它们了?
#如果没有指定这个属性值,那么是否为只读连接,这就由驱动自己来决定了。即Connection的实现类自己来决定!
defaultReadOnly=false
#指定事务的事务隔离级别
#可选值:NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
#如果没有指定,那么由驱动中的Connection实现类自己来决定
defaultTransactionIsolation=REPEATABLE_READ
C3P0
C3P0也是开源免费的连接池。
使用代码
@Test
public void func() throws PropertyVetoException, SQLException {
//获得连接池对象
ComboPooledDataSource cpds=new ComboPooledDataSource();
//设置4大参数
cpds.setDriverClass("com.mysql.jdbc.Driver");
cpds.setJdbcUrl("jdbc:mysql://localhost:3306/sql_test");
cpds.setUser("root");
cpds.setPassword("123456");
//设置池参数
cpds.setAcquireIncrement(5);//增量
cpds.setInitialPoolSize(20);//初始池大小
cpds.setMinPoolSize(3);//最小连接数
cpds.setMaxPoolSize(40);//最大连接数
//得到连接对象
Connection cn=cpds.getConnection();
//输出连接名
System.out.println(cn.getClass().getName());
//归还给池
cn.close();
}
配置文件
c3p0使用配置文件有两个要求:
- 文件名:必须叫c3p0-config.xml
- 文件位置:必须在src下
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb1</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">123</property>
<property name="acquireIncrement">3</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">2</property>
<property name="maxPoolSize">10</property>
</default-config>
<named-config name="oracle-config">
<property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb1</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">123</property>
<property name="acquireIncrement">3</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">2</property>
<property name="maxPoolSize">10</property>
</named-config>
</c3p0-config>
配置文件中的属性名和java代码中的一致。还可以配置多个连接信息,给每个连接起一个单独的名字。
ComboPooledDataSource ds = new ComboPooledDataSource("orcale-config");
通过连接池更新JDBCUtils工具类
首先是src目录下的配置文件
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 这是默认配置信息 -->
<default-config>
<!-- 连接四大参数配置 -->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/sql_test</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">123456</property>
<!-- 池参数配置 -->
<property name="acquireIncrement">3</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">2</property>
<property name="maxPoolSize">10</property>
</default-config>
</c3p0-config>
JDBCUtils.java
/**
* 使用c3p0连接池
*/
public class JDBCUtils {
//创建一个连接池对象,这里在配置文件中设置参数 c3p0-config.xml
private static ComboPooledDataSource cpds=new ComboPooledDataSource();
/**
* 返回连接对象
* @return
* @throws SQLException
*/
public static Connection getConnction() throws SQLException {
return cpds.getConnection();
}
/**
* 返回连接池对象
* @return
*/
public static ComboPooledDataSource getDataSource(){
return cpds;
}
}
Tomcat配置连接池
Tomcat配置JNDI资源
JNDI(Java Naming and Directory Interface),Java命名和目录接口。JNDI的作用就是:在服务器上配置资源,然后通过统一的方式来获取配置的资源。
通过在tomcat上配置连接池,在项目中就可以通过统一的方式来获取连接池对象了。
下图是tomcat文档上的:
配置JNDI资源需要到<Context>元素中配置<Resource>子元素:
- name:指定资源的名称,这个名称可以随便给,在获取资源时需要这个名称;
- factory:用来创建资源的工厂,这个值基本上是固定的,不用修改;
- type:资源的类型,我们要给出的类型当然是我们连接池的类型了;
- bar:表示资源的属性,如果资源存在名为bar的属性,那么就配置bar的值。对于DBCP连接池而言,你需要配置的不是bar,因为它没有bar这个属性,而是应该去配置url、username等属性。
配置文件这里选择:tomact安装目录下的D:\Program Files\apache-tomcat-8.5.23\conf下的context.xml文件
<?xml version="1.0" encoding="ISO-8859-1"?>
<Context>
<Resource name="mydbcp"
type="org.apache.tomcat.dbcp.dbcp.BasicDataSource"
factory="org.apache.naming.factory.BeanFactory"
username="root"
password="123456"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/sql_test"
maxIdle="3"
maxWait="5000"
maxActive="5"
initialSize="3"/>
<Resource name="myc3p0"
type="com.mchange.v2.c3p0.ComboPooledDataSource"
factory="org.apache.naming.factory.BeanFactory"
user="root"
password="123"
classDriver="com.mysql.jdbc.Driver"
jdbcUrl="jdbc:mysql://127.0.0.1/mydb1"
maxPoolSize="20"
minPoolSize ="5"
initialPoolSize="10"
acquireIncrement="2"/>
</Context>
获取资源
下图是Tomcat文档提供的,与上面Tomcat文档提供的配置资源是对应的。
- Context:javax.naming.Context;
- InitialContext:javax.naming.InitialContext;
- lookup(String):获取资源的方法,其中”java:comp/env”是资源的入口(这是固定的名称),获取过来的还是一个Context,这说明需要在获取到的Context上进一步进行获取。”bean/MyBeanFactory”对应<Resource>中配置的name值,这回获取的就是资源对象了。
DBCP代码
//获取上下文对象
Context initCtx = new InitialContext();
//通过查询得到数据库池对象
BasicDataSource ds= (BasicDataSource) initCtx.lookup("java:/comp/env/mydbcp");
//获得连接对象
Connection cn=ds.getConnection();
//输出连接名
System.out.println(cn.getClass().getName());
cn.close();
C3P0代码
Context ctx=new InitialContext();
ComboPooledDataSource cpds= (ComboPooledDataSource) ctx.lookup("java:comp/env/myc3p0");
Connection cn=cpds.getConnection();
System.out.println(cn.getClass().getName());
cn.close();