一、什么是数据库连接池
二、数据源
1、实现数据库连接池
编写连接池需实现java.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:
Connection getConnection()
Connection getConnection(String username, String password)
实现DataSource接口,并实现连接池功能的步骤:
在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。
实现getConnection方法,让getConnection方法每次调用时,从Linked中取一个Connection返回给用户。
当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。
1 //实现DataSource接口 2 public class JdbcPool implements DataSource { 3 4 private static LinkedList<Connection> list = new LinkedList<Connection>(); 5 6 //保存配置文件信息 7 private static Properties config = new Properties(); 8 static{ 9 try { 10 //通过类加载器读取配置文件 11 config.load(JdbcPool.class.getClassLoader().getResourceAsStream("db.properites")); 12 //注册驱动 13 Class.forName(config.getProperty("driver")); 14 15 16 //创建10个连接 17 for(int i=0;i<10;i++){ 18 list.add(DriverManager.getConnection(config.getProperty("url"), "username", "password")); 19 } 20 } catch (Exception e) { 21 //抛出初始化异常 22 throw new ExceptionInInitializerError(e); 23 } 24 } 25 26 27 @Override 28 //实现连接池注意的问题: 29 //当调用close()方法的时候不是把连接返回给数据库,而是把连接返回给连接池 30 31 /* 32 * conn.close() 33 /* 在实际开发,发现对象的方法满足不了开发需求时,有三种方式对其进行增强 34 * 1.写一个connecton子类,覆盖close方法,增强close方法 35 * 2.用包装设计模式 36 * 3.用动态代理 aop 面向切面编程 37 */ 38 public Connection getConnection() throws SQLException { 39 //如果连接池中没有连接 40 if(list.size()<0){ 41 throw new RuntimeException("对不起数据库繁忙"); 42 43 } 44 //从数据库中移除第一个 45 Connection con = list.removeFirst(); 46 MyConnection my = new MyConnection(con); 47 return my; 48 } 49 50 51 //1.定义一个类,实现与被增强相同的接口 52 //2.在类中定义一个变量,记住被增强对象 53 //3.定义一个构造函数,接收被增强对象 54 //4.覆盖想增强的方法 55 //5.对于不想增强的方法,直接调用目标对象(被增强对象)的方法 56 //增强con对象 57 class MyConnection implements Connection{ 58 private Connection conn; 59 public MyConnection(Connection conn){ 60 this.conn = conn; 61 } 62 63 //增强close方法 64 public void close(){ 65 list.add(this.conn); 66 }
2、DBCP数据源
应用程序应在系统中增加如下两个 jar 文件:
Commons-dbcp.jar:连接池的实现
Commons-pool.jar:连接池实现的依赖库
配置文件:dbcpconfig.properties
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day16
username=root
password=root
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最大空闲连接 -->
maxIdle=20
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=utf8
#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_COMMITTED
package com.utils;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
//DBCP连接池
public class JdbcUtils_DBCP {
//数据库连接池
private static DataSource ds = null;
static{
try{
//读取配置文件
InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties prop = new Properties();
prop.load(in);
BasicDataSourceFactory factory = new BasicDataSourceFactory();
//创建连接池
ds = factory.createDataSource(prop);
}catch(Exception e){
throw new ExceptionInInitializerError(e);
}
}
//获取连接的方法
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
public static void release(Connection con,Statement st,ResultSet result){
if(result!=null){
try{
result.close();
}catch(Exception e){
e.printStackTrace();
}
result = null;
}
if(st!=null){
try{
st.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
3、C3P0数据源
配置文件:c3p0-config.xml
<c3p0-config>
<!--默认配置-->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/day16</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">20</property>
<property name="minPoolSize">5</property>
<property name="maxStatements">200</property>
</default-config>
<named-config name="mysql">
<property name="acquireIncrement">50</property>
<property name="initialPoolSize">100</property>
<property name="minPoolSize">50</property>
<property name="maxPoolSize">1000</property><!-- intergalactoApp adopts a different approach to configuring statement caching -->
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property>
</named-config>
<named-config name="oracle">
<property name="acquireIncrement">50</property>
<property name="initialPoolSize">100</property>
<property name="minPoolSize">50</property>
<property name="maxPoolSize">1000</property><!-- intergalactoApp adopts a different approach to configuring statement caching -->
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
1 package com.utils;
2
3 import java.sql.Connection;
4 import java.sql.ResultSet;
5 import java.sql.SQLException;
6 import java.sql.Statement;
7
8 import com.mchange.v2.c3p0.ComboPooledDataSource;
9
10 public class JdbcUtils_C3P0 {
11 public static ComboPooledDataSource ds = null;
12
13 static{
14 try{
15 //自动搜索配置文件
16 ds = new ComboPooledDataSource();
17
18 }catch(Exception e){
19 throw new ExceptionInInitializerError();
20 }
21 }
22
23 //获取连接的方法s
24 public static Connection getConnection() throws SQLException {
25 return ds.getConnection();
26 }
27
28 //释放连接
29 public static void release(Connection con,Statement st,ResultSet result){
30 if(result!=null){
31 try{
32 result.close();
33 }catch(Exception e){
34 e.printStackTrace();
35 }
36 result = null;
37 }
38
39 if(st!=null){
40 try{
41 st.close();
42 }catch(Exception e){
43 e.printStackTrace();
44 }
45 }
46
47 if(con!=null){
48 try {
49 con.close();
50 } catch (Exception e) {
51 e.printStackTrace();
52 }
53 }
54 }
55
56
57 }
4、配置tomcat数据源
在web工程WebRoot/META-INF目录下建立context.xml配置文件如下:
1 <Context>
2
3 <!-- jdbc/EmployeeDB 为资源的名称 -->
4 <Resource name="jdbc/EmployeeDB" auth="Container"
5 type="javax.sql.DataSource"
6 username="root"
7 password="root"
8 driverClassName="com.mysql.jdbc.Driver"
9 url="jdbc:mysql://localhost:3306/day16"
10 initialSize="10"
11 maxActive="30"
12 maxIdle="4"/>
13 </Context>
获取连接池
1 public class JdbcUtils {
2 private static DataSource ds;
3 static {
4 try {
5 //初始化JNDI容器
6 Context initCtx = new InitialContext();
7 //根据关键字获取容器
8 Context envCtx = (Context) initCtx.lookup("java:comp/env");
9
10 //根据名称获取数据源
11 ds = (DataSource) envCtx.lookup("jdbc/EmployeeDB");
12 } catch (Exception e) {
13 throw new RuntimeException(e);
14 }
15 }
16
17 //获取连接
18 public static Connection getConnection() throws SQLException{
19 return ds.getConnection();
20 }
21 }
注意:
1、mysql的驱动包一定要导进tomcat的lib目录下
2、服务器会自动把META-INF目录下的context.xml加载到confCatalinalocalhost目录下
实现原理:JNDI
JNDI(Java Naming and Directory Interface),Java命名和目录接口,它对应于J2SE中的javax.naming包,
这套API的主要作用在于:它可以把Java对象放在一个容器中(JNDI容器),并为容器中的java对象取一个名称,以后程序想获得Java对象,只需通过名称检索即可。
其核心API为Context,它代表JNDI容器,其lookup方法为检索容器中对应名称的对象。