连接池
概念
频繁的打开和关闭连接对数据库服务器有很大的压力, 而且也没有必要
我们可以使用容器来管理数据库连接对象
在服务器启动时可以先准备好一定数量的连接对象并放入连接池中
当用户需要使用连接对象的时候,先从池里拿,如果池里不够再做相应处理
当连接对象使用完毕, 用户可以把它归还到连接池中, 别的用户还可以继续使用
自定义连接池
在java app建立连接池,用户一访问从池子里拿一个连接对象使用
jdbc中有统一规范
通过实现datasource接口
实现其中的get connection方法
使用完要归还,建立归还连接对象方法
成员属性linkedlist作为容器存放connection,方便频繁的增删(用完connection再放入池子)
在这里加入构造静态块用于配置数据库参数
构造块和静态构造块的概念:
静态块:static声明,jvm加载类时执行,仅执行一次
构造块:类中直接用{}定义,每次创建对象执行
归还连接对象
自定义连接池出现的问题
1. 归还连接对象必须调用 backToSource 方法
2. 一旦不小心调用了close 连接对象就不能再使用了, 被人再次拿出可能会导致代码报错
增强close方法的设计
改进方案
通过连接池拿出的连接对象
调用close方法,并不会真的关闭连接对象, 而是归还到连接池
相当于我们要对close方法进行一个方法增强
1. 继承
必须要有父类
2. 装饰模式
必须要实现所有方法
3. 动态代理
必须要有接口
connection是接口,所以可以使用装饰模式进行方法增强
写一个装饰模式
建立一个实现connection接口的类,它是jdbc api类的兄弟类,在里面持有connection的引用,用构造传递连接池对象和连接对象
连接池里的connection对象和池内对象不足,需要额外新建的对象都是被强化过close,createstatement,preparedstatenment方法的对象
装饰模式的弊端
理论上需要重写connection的所有方法,但是按需重写即可,其余方法调用connection的原方法即可
Close方法重写,把用完的connection对象返回到连接池,而不是关闭
@Override
public void close() throws SQLException {
ds.baceToSource(conn);
}
使用connection的原方法
@Override
public Statement createStatement() throws SQLException {
return conn.createStatement();
}
改造数据库连接池
改写连接工厂, 使得连接工厂产生的连接对象也是由连接池里产生的
把连接工厂的加载xml配置文件代码块和生成connection方法移到连接池内
使用C3P0连接池
C3p0连接池
C3p0是一个开源的JDBC连接池
使用方法
导包
c3p0-0.9.1.2.jar
初始化C3P0连接池(不使用配置文件)
ComboPooledDataSource cpds = new ComboPooledDataSource("oracle");
//loads the jdbc driver 加载jdbc驱动
try {
cpds.setDriverClass( "com.mysql.jdbc.Driver" );
cpds.setJdbcUrl( "jdbc:mysql://localhost:3306/jdbc1" );
cpds.setUser("root");
cpds.setPassword("root");
使用配置文件配置数据库和连接池参数
设置配置文件
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 默认配置文件,无参构造ComboPooledDataSource() -->
<default-config>
<!-- 需要注册的驱动类名 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<!-- 数据库路径,///表示省略了localhost.3306,已经知道是mysql数据库了其主机号,端口号直接可以拿到吧 -->
<property name="jdbcUrl">jdbc:mysql:///jdbc1</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池初始化连接数为20 -->
<property name="initialPoolSize">5</property>
<!-- 连接池容量最大为20 -->
<property name="maxPoolSize">20</property>
</default-config>
<!-- 若要有多份配置文件连接不同数据库,可以设置命名配置文件 -->
<named-config name="oracle">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///jdbc1</property>
<property name="user">root</property>
<property name="password">root</property>
</named-config>
</c3p0-config>
ComboPooledDataSource连接池初始化猜想:
首先根据传入参数,确定构造方法,读取相应的xml文件c3p0-config.xml
没有该文件,则新建一个默认的c3p0-config.xml,可以额外调用相关方法给c3p0连接池对象设置数据库配置参数
ComboPooledDataSource cpds = new ComboPooledDataSource()
无参则遍历<default-config>标签下的标签属性
ComboPooledDataSource cpds = new ComboPooledDataSource(“oracle”)
有参数根据参数名遍历该参数名对应的标签属性
<named-config name="oracle">
同时使用dbconfig和c3p0.xml
连接数据库配置使用dbconfig.properties
连接池配置使用c3p0-config.xml
把dbconfig中的driver,url,user,password读出赋值给c3p0对象
package com.bwf.database;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class ConnectionFactory {
private static ComboPooledDataSource cpds = new ComboPooledDataSource();
private static String driver;
private static String url;
private static String uname;
private static String upwd;
static {
Properties properties = new Properties();
// 用 ClassLoader 读取src下的资源
InputStream is = ConnectionFactory.class.getClassLoader().getSystemResourceAsStream("dbconfig.properties");
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
driver = properties.getProperty("driver");
url = properties.getProperty("url");
uname = properties.getProperty("uname");
upwd = properties.getProperty("upwd");
// TODO Auto-generated method stub
// loads the jdbc driver
try {
cpds.setDriverClass(driver);
cpds.setJdbcUrl(url);
cpds.setUser(uname);
cpds.setPassword(upwd);
} catch (PropertyVetoException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Connection getConnection() {
try {
return cpds.getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}