一、什么是数据库连接池的核心思想
数据库连接池的基本思想就是为数据库连接
建立一个
“缓冲池”。预先在缓冲池中放入一定数量的连接
对象,当需要建立数据库连接时,只需从
“缓冲池”中取出一个,使用完毕之后再放回去。 以确保连接被后续的请求服务
,
提高连接的复用
,
从而避免了不断的去创建
,
不断的去销毁
Connecion
的事
,
从而提高了性能
.
二、使用连接池的原因
(
1
)节省创建连接与释放连接的性能消耗
(
2
)连接池中的连接起到复用的作用
,提高程序性能,如下图所示:
三、数据库连接池编写原理分析
(
1
)编写连接池需实现
javax.sql.DataSource
接口。
DataSource
接口中定义了两个重载的
getConnection
方法:
Connection getConnection()
Connection getConnection(String username, String password)
(
2
)实现
DataSource
接口,并实现连接池功能的步骤:
在
DataSource
构造函数中批量创建与数据库的连接,并把创建的连接保存到一个集合对象中
实现
getConnection
方法,让
getConnection
方法每次调用时,从集合对象中取一个
Connection
返回给用户。
当用户使用完
Connection
,调用
Connection.close()
方法时,
Collection
对象应保证将自己返回到连接池的集合对象中
,
而不要把
conn
还给数据库。
四、编写数据库连接池核心
扩展
Connection
的
close
方法
在关闭数据库连接时,将
connection
存回连接池中,而并非真正的关闭
扩展类的三种方式
基于继承
---
方法覆盖
使用装饰模式包装类,增强原有行为
使用动态代理
---
基于字节码
Class
在内存中执行过程
五、常用两个开源的数据库连接池
现在很多
WEB
服务器
(Weblogic, WebSphere, Tomcat)
都提供了
DataSoruce
的实现,即连接池的实现。通常我们把
DataSource
的实现,按其英文含义称之为数据源,数据源中都包含了数据库连接池的实现。
也有一些开源组织提供了数据源的独立实现:
1.
DBCP
数据库连接池
(
核心类
BasicDataSource)
2.
C3P0
数据库连接池
(核心类ComboPooledDataSource,主流开源连接池)
3.Apache Tomcat
内置的连接池(
apache dbcp
)这个是
Tomcat
内置的连接池,需要配置
JNDI
技术来使用
实际应用时不需要我们自己去编写连接数据库代码,直接从数据源获得数据库的连接。程序员编程时也应尽量使用这些数据源的实现,以提升程序的数据库访问性能。
c3p0与dbcp的区别:前者有自动回收空闲连接的功能,后者没有,建议优先使用c3p0连接池。
六、DBCP
数据源
(datasource)
DBCP
是
Apache
软件基金组织下的开源连接池实现,使用
DBCP
数据源,应用程序应在系统中增加如下
两个
jar
文件
:
Commons-dbcp.jar
:连接池的实现
Commons-pool.jar
:连接池实现的依赖库
6.1 DBCP连接池的使用步骤
1.创建配置文件properties,保存到src目录中,内容如下:
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb1
username=root
password=root
#初始化连接
initialSize=10
#最大连接数量
maxActive=50
#最大空闲连接
maxIdle=20
#最小空闲连接
minIdle=5
#超时等待时间以毫秒为单位 6000毫秒/1000等于60秒
maxWait=60000
#连接属性
connectionProperties=useUnicode=true;characterEncoding=utf8
#是否自动提交
defaultAutoCommit=true
#事务隔离级别 NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
2.导入jar包,项目结构如下:
package demo1;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.apache.commons.dbcp.BasicDataSource;
/**
* 方式一:手动设置连接参数
*/
public class DbcpTest1 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement stmt = null;
// 1.创建BasicDataSource对象
BasicDataSource ds = new BasicDataSource();
// 2.设置连接数据库的参数(必要)
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql:///mydb1");
ds.setUsername("root");
ds.setPassword("root");
try {
// 3.从dbcp连接池中获得连接对象
conn = ds.getConnection();
// 4.获得preparedstatement对象
stmt = conn.prepareStatement("update account set money = 200 where name = ?");
stmt.setString(1, "chenys");
// 5.执行sql语句
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 6.关闭资源
if (null != stmt)
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (null != conn)
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
package demo2;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
/**
* 方式二:从配置文件properties中获得连接参数 推荐使用,因为扩展性高
*/
public class DbcpTest2 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement stmt = null;
//1.创建配置文件对象
Properties props = new Properties();
//2.把目标配置文件中的数据以一个流的形式读取进流中
InputStream inStream = DbcpTest2.class.getClassLoader().getResourceAsStream("dbcp.properties");
try {
//3.加载配置文件,这时候 props中就会有 dbcp.properties里的配置信息了
props.load(inStream);
//4.创建BasicDataSource对象
DataSource ds = BasicDataSourceFactory.createDataSource(props);
//5.获取dbcp中的连接池
conn = ds.getConnection();
//6.创建stmt对象
stmt = conn.prepareStatement("update account set money = 11001 where name = ?");
stmt.setString(1, "chenys");
//7.执行sql语句
stmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}finally {
//8.关闭资源
if(null !=stmt)
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(null !=conn)
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
七、C3P0
数据源
主流开源连接池,在
Hibernate
和
Spring
都提供对
C3P0
连接池支持
方式一:手动设置连接参数
方式二:在
src
下新建
c3p0-config.xml
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
会自动加载配置文件
常用基本连接池属性
acquireIncrement
如果连接池中连接都被使用了,一次性增长
3
个新的连接
initialPoolSize
连接池中初始化连接数量 默认
:3
maxPoolSize
最大连接池中连接数量 默认:
15
连接
maxIdleTime
如果连接长时间没有时间,将被回收 默认:
0
连接永不过期
minPoolSize
连接池中最小连接数量 默认:
3.
7.1 c3p0连接池的使用步骤
1.导入相关jar包,项目结构如下:
2.编写连接池配置文件
<c3p0-config>
<!-- 默认配置,如果没有指定则使用这个配置 -->
<default-config>
<!-- 基本配置 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/mydb1</property>
<property name="user">root</property>
<property name="password">root</property>
<!--扩展配置-->
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config>
<!-- 命名的配置,加载的时候可以指定名称加载 -->
<named-config name="myc3p0">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/mydb1</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 如果池中数据连接不够时一次增长多少个 -->
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">20</property>
<property name="minPoolSize">10</property>
<property name="maxPoolSize">40</property>
<property name="maxStatements">20</property>
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
package utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
* 定义jdbc的工具类
*
* @author Lucky
*
*/
public class JdbcUtils {
// 1.创建ComboPooledDataSource对象,这里 在 new ComboPooledDataSource 会自动去 classpath 找
// c3p0-config.xml 配置文件, 然后 会自动 解析其中的数据 ,创建一个连接池
// 配置c3p0的xml文件,该文件需要被保存到src目录下,配置文件的名称必须为c3p0-config.xml,否则会解析失败。
// new ComboPooledDataSource(String configName) 使用命名的配置 若配置的名字找不到,使用默认的配置
private static DataSource ds = new ComboPooledDataSource();
// 2.定义获取connection对象的方法
public static Connection getConnection() {
try {
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
// 3.定义释放资源的方法
public static void release(ResultSet rs, PreparedStatement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
4.编写测试类
package demo;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import utils.JdbcUtils;
public class C3p0Test {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement stmt=null;
try {
conn = JdbcUtils.getConnection();
stmt = conn.prepareStatement("insert into account values(null,'ccc',1000)");
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally{
JdbcUtils.release(null, stmt, conn);
}
}
}