数据库连接池

一、数据库连接池

1.数据库的连接对象创建工作,比较消耗性能。

2.一开始现在内存中开辟一块空间(集合) , 一开先往池子里面放置 多个连接对象。 后面需要连接的话,直接从池子里面去。不要去自己创建连接了。 使用完毕,要记得归还连接。确保连接对象能循环利用。


二、自定义数据库连接池

步骤分析:

使用单元Junit测试

  1. 首先导入之前写好的JDBCUtil类和外部文件jdbc.properties还有jar文件。

  2. 新建一个MyDataSource类:
    需要继承DataSource类–实现所有方法(我们只需要完成getConnection()方法)–只需要管连接池对外公布的获取连接的方法getConnection()。
    2.1 建立MyDataSource方法:先往池子里面放10个连接(建立list集合存放),使用JDBCUtil.getConn()去获取连接,通过循环和add方法连续添加10个连接。
    2.2 在连接池对外公布的获取连接的方法中去通过remove移除(取连接)
    2.3 最后写一个方法addBack():用完之后归还。

  3. 如果现在链接不够的话,就要在取之前判断是否为0,如果不够就要for循环继续add()。

  4. 在项目处右键–构建路径–右边选Add Library–添加Junit4选项

  5. 新建测试的TestPool类:
    5.1 需要建立MyDataSource对象然后调用getConnection()连接
    5.2 写sql语句 –MyDataSource对象调用prepareStatement去检测SQL语句
    5.3 检测sql语句之后调用对应的executeUpdate()语句
    5.4 finally里面要写关于sql操作之后关闭对象–还需要通过对象调用addBack()方法

具体代码:

JDBCUtil类代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package util;
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JDBCUtil {

static String driverClass = null;
static String url = null;
static String name = null;
static String password= null;

static{
try {
//1. 创建一个属性配置对象
Properties properties = new Properties();
InputStream is = new FileInputStream("jdbc.properties");

//使用类加载器,去读取src底下的资源文件。 后面在servlet
// InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
//导入输入流。
properties.load(is);

//读取属性
driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
name = properties.getProperty("name");
password = properties.getProperty("password");

} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 获取连接对象
* @return
*/
public static Connection getConn(){
Connection conn = null;
try {
Class.forName(driverClass);
//静态代码块 ---> 类加载了,就执行。 java.sql.DriverManager.registerDriver(new Driver());
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb");
//2. 建立连接 参数一: 协议 + 访问的数据库 , 参数二: 用户名 , 参数三: 密码。
conn = DriverManager.getConnection(url, name, password);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}

/**
* 释放资源
* @param conn
* @param st
* @param rs
*/
public static void release(Connection conn , Statement st , ResultSet rs){
closeRs(rs);
closeSt(st);
closeConn(conn);
}
public static void release(Connection conn , Statement st ){
closeSt(st);
closeConn(conn);
}


private static void closeRs(ResultSet rs){
try {
if(rs != null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
rs = null;
}
}

private static void closeSt(Statement st){
try {
if(st != null){
st.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
st = null;
}
}

private static void closeConn(Connection conn){
try {
if(conn != null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
conn = null;
}
}
}

jdbc.properties代码(只需要更改数据库的名字)

1
2
3
4
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost/bank
name=root
password=njdxrjgc7777777.

MyDataSource(实现DataSource类)代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package util;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.sql.DataSource;
/*
* 这是一个数据库连接池
* 一开始先往池子放10个连接
*
* 1.开始创建10个连接
*
* 2.取出去
*
* 3.拿回来
*
* 4.扩容
*
*/
public class MyDataSource implements DataSource{ //继承之后需要实现下面的方法(点击弹出)

List <Connection> list=new ArrayList<Connection>(); //建立list集合存放连接

public MyDataSource() { //添加10个连接
for(int i=0;i<10;i++)
{
Connection conn=JDBCUtil.getConn(); //提前拷贝JDBCUtil类和jdbc.properties外部文件和外部jar文件
list.add(conn); //add往里添加
}

}

//连接池对外公布的获取连接的方法
@Override
public Connection getConnection() throws SQLException {
//来拿连接的时候,先看看池子里面是否还有
if(list.size()==0) //如果没有了继续添加5个
{
for(int i=0;i<5;i++)
{
Connection conn=JDBCUtil.getConn(); //提前拷贝JDBCUtil类和jdbc.properties外部文件和外部jar文件
list.add(conn); //扩容
}
}

Connection conn = list.remove(0); //移除第一个(自动往前补) 相当于取连接
return conn;
}

public void addBack(Connection conn) { //自己写的在用完之后要归还的方法
list.add(conn); //add在加回去
}

//-------只需要看上面的连接方法----------

@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO 自动生成的方法存根
return null;
}

@Override
public int getLoginTimeout() throws SQLException {
// TODO 自动生成的方法存根
return 0;
}

@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
// TODO 自动生成的方法存根
return null;
}

@Override
public void setLogWriter(PrintWriter arg0) throws SQLException {
// TODO 自动生成的方法存根

}

@Override
public void setLoginTimeout(int arg0) throws SQLException {
// TODO 自动生成的方法存根

}

@Override
public boolean isWrapperFor(Class<?> arg0) throws SQLException {
// TODO 自动生成的方法存根
return false;
}

@Override
public <T> T unwrap(Class<T> arg0) throws SQLException {
// TODO 自动生成的方法存根
return null;
}


@Override
public Connection getConnection(String username, String password) throws SQLException {
// TODO 自动生成的方法存根
return null;
}

}

测试JUnit的TestPool代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.junit.Test;
public class TestPool {
@Test
public void testPool(){
Connection conn=null;
PreparedStatement ps =null;
MyDataSource my=new MyDataSource(); //调用我们写好的MyDataPool类

try {
conn = my.getConnection(); //第一步获取连接
String sql="insert into account values(4,'xilali',10)"; //第二步写sql语句
ps = conn.prepareStatement(sql); //第三步调用方法检测sql语句
ps.executeUpdate(); //调用方法对sql执行

} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}finally {
try {
ps.close(); //关闭对象 替换了之前的JDBCUtil.release(conn,ps,rs);
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
//归还连接
my.addBack(conn); //用完之后一定要记得addBack归还连接
}
}
}

单元测试只是显示绿色/红色不通过—具体结果去看看数据库:


三、自定义数据库连接池存在的问题

  • 因为sun公司针对数据库连接池的定义没有用完返回的解决方案—->需要额外记住写addBack()方法

  • 单例

  • 不能面向接口编程

1
2
3
4
5
6
7
8
9
//面向对象编程
MyDataSource my=new MyDataSource(); //调用我们写好的MyDataSource类

//现在面向接口编程
DataSource dataSource = new MyDataSource(); //改成这样因为接口里面没有定义addBack方法
dataSource.addBack(); //会报错

//而且原来sun公司的Connection对于close()方法直接是关闭 ---我们需要直接改成返回连接
conn.colse();

四、解决存在的问题

  1. 修改接口中的那个close方法

  2. 原来的Connection对象的close方法,是真的关闭连接。

  3. 打算修改这个close方法,以后在调用close,并不是真的关闭,而是归还连接对象。


五、扩展方法

原有的方法逻辑,不是我们想要的。 想修改自己的逻辑

  1. 直接改源码—-无法实现。

  2. 继承—-必须得知道这个接口具体实现是谁。

  3. 使用装饰者模式(扩展一个类去更改方法)

  先是一个接口Waiter里面有service()方法,最后有一个Waitress类实现刚才的接口输出方法内容,但是现在可以通过建立WaitressWrap()方法去用构造方法获取接口对象,this获取对象,然后通过实现接口方法更改以前的操作。


六、装饰者模式–具体操作

我们新建ConnectionWrap类实现Connection接口的方法,但是只需要去更改close()和prepareStatement()方法。

1.只展示实现类ConnectionWrap类部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ConnectionWrap implements Connection{   //继承Connnection方法 修改它的close更改为 返回连接

Connection connection=null; //创建连接
List<java.sql.Connection> list;

public ConnectionWrap(java.sql.Connection conn, List<java.sql.Connection> list) { //构造方法
super();
this.connection =connection;
this.list=list;
}

@Override
public void close() throws SQLException { //更改了close()方法 ---变成了归还连接
list.add(connection);
}

@Override
public PreparedStatement prepareStatement(String sql) throws SQLException { //更改了里面的检验sql语句
return connection.prepareStatement(sql);
}

2.在MyDataSource类里面在取连接之前对connection对象进行调用COnnectionWrap类包装,

1
2
3
//抛出前,对对象进行包装
Connection connection=new ConnectionWrap(conn,list);
return connection;

3.在测试类之中以后就不用写归还的方法,而是直接写JDBCUtil的方法:

1
2
//归还连接
JDBCUtil.release(conn,ps);

七、开源连接池(DBCP/C3PO)

DBCP使用步骤:

###1. 导入对应的dbcp和pool的jar文件:

###2.1 不使用配置文件( BasicDataSource类):

思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1.通过BasicDataSource类构件数据源对象
BasicDataSource dataSource = new BasicDataSource();

2.不使用配置文件---使用set方法添加那四行材料
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost/bank"); //jdbc:mysql://localhost/bank 主协议:子协议 ://本地/数据库
dataSource.setUsername("root");
dataSource.setPassword("njdxrjgc7777777.");

3.通过对象调用连接
conn = dataSource.getConnection(); //使用dataSource调用连接

4.书写SQL语句,然后去检验,添加,方法上传
String sql = "insert into account values(null , ? , ?)"; //sql插入语句
ps = conn.prepareStatement(sql); //检验sql语句

ps.setString(1, "admin"); //给下标1和2的设定具体的值
ps.setInt(2, 1000);

ps.executeUpdate(); //调用插入操作方法

5.finally最后使用JDBCUtil类的方法抓异常
JDBCUtil.release(conn, ps); //调用JDBCUtil类的方法

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package kaiyuan;
import java.sql.SQLException;
import org.apache.commons.dbcp.BasicDataSource;
import org.junit.Test;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;
import util.JDBCUtil;
public class DBCPDemo {
@Test
public void testDBCP01(){
java.sql.Connection conn = null;
java.sql.PreparedStatement ps = null;
try {
//1. BasicDataSource类构建数据源对象
BasicDataSource dataSource = new BasicDataSource();

//连的是什么类型的数据库, 访问的是哪个数据库 , 用户名, 密码。。
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost/bank"); //jdbc:mysql://localhost/bank 主协议:子协议 ://本地/数据库
dataSource.setUsername("root");
dataSource.setPassword("njdxrjgc7777777.");

//2. 得到连接对象
conn = dataSource.getConnection(); //使用dataSource调用连接
String sql = "insert into account values(null , ? , ?)"; //sql插入语句
ps = conn.prepareStatement(sql); //检验sql语句

ps.setString(1, "admin"); //给下标1和2的设定具体的值
ps.setInt(2, 1000);

ps.executeUpdate(); //调用插入操作方法

} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtil.release(conn, ps); //调用JDBCUtil类的方法
}
}
}

###2.2 使用配置文件( BasicDataSourceFactory类):

思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1.通过BasicDataSourceFactory类构件数据源对象
BasicDataSourceDactory dataSource = new BasicDataSourceDactory();

2.使用配置文件-
//构造配置文件对象
Properties properties=new Properties();

//输入流加载文件(找到配置文件)
InputStream is=new FileInputStream("src//dbcpconfig.properties");
properties.load(is); //对象调用load加载文件(加载好)

DataSource dataSource = factory.createDataSource(properties); //输入流加载文件之后要用对象调用方法加载配置文件(加载到对象去)


3.通过对象调用连接(sun公司的DataSource)
conn = dataSource.getConnection(); //使用dataSource调用连接

4.书写SQL语句,然后去检验,添加,方法上传
String sql = "insert into account values(null , ? , ?)"; //sql插入语句
ps = conn.prepareStatement(sql); //检验sql语句

ps.setString(1, "liangchaowei"); //给下标1和2的设定具体的值
ps.setInt(2, 1020);

ps.executeUpdate(); //调用插入操作方法

5.finally最后使用JDBCUtil类的方法抓异常
JDBCUtil.release(conn, ps); //调用JDBCUtil类的方法

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package kaiyuan;
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.junit.Test;
import util.JDBCUtil;
public class DBCPDemo02 {

@Test
public void testDBCP02() throws Exception{

//和之前的代码一样
java.sql.Connection conn = null;
java.sql.PreparedStatement ps = null;
try {
//1. BasicDataSourceFactory类构建数据源对象(因为有可以加载配置文件的方法)
BasicDataSourceFactory factory=new BasicDataSourceFactory();

//构造配置文件对象
Properties properties=new Properties();
//输入流加载文件
InputStream is=new FileInputStream("src//dbcpconfig.properties");
properties.load(is); //输入流加载配置文件

DataSource dataSource = factory.createDataSource(properties); //输入流加载文件之后要用对象调用方法加载配置文件

//2. 得到连接对象
conn = dataSource.getConnection(); //使用dataSource调用连接
String sql = "insert into account values(null , ? , ?)"; //sql插入语句
ps = conn.prepareStatement(sql); //检验sql语句

ps.setString(1, "liangchaowei"); //给下标1和2的设定具体的值
ps.setInt(2, 1020);

ps.executeUpdate(); //调用插入操作方法

} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtil.release(conn, ps); //调用JDBCUtil类的方法
}

}
}

dbcpconfig.properties配置文件(放在src下面设置好连接池的连接初始化/最大数等等):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost/bank
username=root
password=njdxrjgc7777777.

#<!-- 初始化连接 -->
initialSize=10

#最大连接数量
maxActive=50

#<!-- 最大空闲连接 -->
maxIdle=20

#<!-- 最小空闲连接 -->
minIdle=5

#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000


#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=gbk

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

J3P0使用步骤:

###1. 导入对应的c3p0-0.9.1.2.jar文件:

###2.1 不使用配置文件方式(ComboPooledDataSource类)

思路:

1
和DBCP数据池的不实用配置文件方式一样,只不过一个是BasicDataSource类、另外一个是ComboPooledDataSource类

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Connection conn = null;
PreparedStatement ps = null;
try {
//1. 创建datasource
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//2. 设置连接数据的信息

dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost/bank");
dataSource.setUser("root");
dataSource.setPassword("root");

//2. 得到连接对象
conn = dataSource.getConnection();
String sql = "insert into account values(null , ? , ?)";
ps = conn.prepareStatement(sql);
ps.setString(1, "admi234n");
ps.setInt(2, 103200);

ps.executeUpdate();

} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtil.release(conn, ps);
}

###2.2 使用配置文件方式(ComboPooledDataSource)

思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1.需要导入c3p0-config.xml解析文件(名字不能更改!!!!)

2.跟以前的相比只需要第一步new一个ComboPooledDataSource对象
ComboPooledDataSource dataSource=new ComboPooledDataSource();

3.然后通过对象getConnection()获得连接。
conn = dataSource.getConnection();

4.新建sql语句,通过连接检验sql语句,添加下标内容,调用插入语句
String sql = "insert into account values(null , ? , ?)"; //sql插入语句
ps = conn.prepareStatement(sql); //检验sql语句

ps.setString(1, "adminsan"); //给下标1和2的设定具体的值
ps.setInt(2, 1050);

ps.executeUpdate(); //调用插入操作方法

5.finally最后调用JDBCUtil类方法
JDBCUtil.release(conn, ps); //调用JDBCUtil类的方法

c3p0-config.xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>

<!-- default-config 默认的配置, -->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property> <!-- 要和不用配置文件的set方法的后面一样 -->
<property name="jdbcUrl">jdbc:mysql://localhost/bank</property>
<property name="user">root</property>
<property name="password">njdxrjgc7777777.</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>

<!-- This app is massive! -->
<named-config name="oracle"> <!-- 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>

<!-- he's important, but there's only one of him -->
<user-overrides user="master-of-the-universe">
<property name="acquireIncrement">1</property>
<property name="initialPoolSize">1</property>
<property name="minPoolSize">1</property>
<property name="maxPoolSize">5</property>
<property name="maxStatementsPerConnection">50</property>
</user-overrides>
</named-config>

</c3p0-config>

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package kaiyuaner;
import java.sql.SQLException;
import javax.sql.CommonDataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.junit.Test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import util.JDBCUtil;
public class C3P0Demo {

@Test
public void C3P0Demo01(){
java.sql.Connection conn = null;
java.sql.PreparedStatement ps = null;
try {

//1.只需要new一个对象(找路径什么的C3P0帮你完成)
ComboPooledDataSource dataSource=new ComboPooledDataSource(); //xml里面有两种数据库(默认会找default-config分支) 如果需要用oracle数据库就("oracle")

//2. 得到连接对象
conn = dataSource.getConnection(); //使用dataSource调用连接
String sql = "insert into account values(null , ? , ?)"; //sql插入语句
ps = conn.prepareStatement(sql); //检验sql语句

ps.setString(1, "adminsan"); //给下标1和2的设定具体的值
ps.setInt(2, 1050);

ps.executeUpdate(); //调用插入操作方法

} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtil.release(conn, ps); //调用JDBCUtil类的方法
}

}
}

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 一、数据库连接池
  2. 2. 二、自定义数据库连接池
    1. 2.1. 步骤分析:
    2. 2.2. 具体代码:
  3. 3. 三、自定义数据库连接池存在的问题
  4. 4. 四、解决存在的问题
  5. 5. 五、扩展方法
  6. 6. 六、装饰者模式–具体操作
  7. 7. 七、开源连接池(DBCP/C3PO)
    1. 7.1. DBCP使用步骤:
    2. 7.2. J3P0使用步骤:
,