一、什么是数据库连接池的核心思想
数据库连接池的基本思想就是为数据库连接
建立一个
“缓冲池”。预先在缓冲池中放入一定数量的连接
对象,当需要建立数据库连接时,只需从
“缓冲池”中取出一个,使用完毕之后再放回去。 以确保连接被后续的请求服务
,
提高连接的复用
,
从而避免了不断的去创建
,
不断的去销毁
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_UNCOMMITTED2.导入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); } } }