自己编写数据库连接池
编写连接池需实现java.sql.DataSource接口。
DataSource接口中定义了两个重载的getConnection方法:
Connection getConnection()
ConnectiongetConnection(String username, String password)
步骤:1、在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。
2、实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。
3、当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。
例:
public class JdbcPool implements DataSource {
private static LinkedList<Connection> list = new LinkedList<Connection>();
private static Properties config = new Properties();
static{
try {
config.load(JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("db.properties"));
Class.forName(config.getProperty("driver"));
for(int i=0;i<10;i++){
Connection conn = DriverManager.getConnection(config.getProperty("url"),config.getProperty("username"), config.getProperty("password"));
list.add(conn);
}
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
在实际开发,发现对象的方法满足不了开发需求时,有三种方式对其进行增强
1、写一个connecton子类,覆盖close方法,增强close方法(要导入原有信息,相当于重写conection 对象,几乎不可能)
2、用包装设计模式(可行,但是要覆盖的方法太多)
步骤:1.定义一个类,实现与被增强相同的接口
2.在类中定义一个变量,记住被增强对象
3.定义一个构造函数,接收被增强对象
4.覆盖想增强的方法
5.对于不想增强的方法,直接调用目标对象(被增强对象)的方法
3、用动态代理(aop面向切面编程)
public Connection getConnection() throws SQLException {
if(list.size()<=0){
throw new RuntimeException("数据库忙,请稍会再来!!");
}
//取出连接不要调用get方法,要用remove方法,取出并删除池中连接
Connection conn = list.removeFirst();
//定义一个自己的连接,然后返回。主要原因为了用户调用close方法的时候不把连接还给数据库,要还给连接池。
MyConnection my = new MyConnection(conn);
return my;
}
//定义一个类,实现与被增强相同的接口
class MyConnection implements Connection{
//在类中定义一个变量,记住被增强对象
private Connection conn;
//定义一个构造函数,接收被增强对象
public MyConnection(Connection conn){
this.conn = conn;
}
//覆盖想增强的方法,将连接加入集合中。
public void close(){
list.add(this.conn);
}
//对于不想增强的方法,直接调用目标对象(被增强对象)的方法
public void clearWarnings() throws SQLException {
this.conn.clearWarnings();
}
public void commit() throws SQLException {
this.conn.commit();
}
public Statement createStatement() throws SQLException {
return this.conn.createStatement();
}
..............很多需要覆盖的方法
}
}
开源数据库连接池
现在很多WEB服务器(Weblogic, WebSphere, Tomcat)都提供了DataSoruce的实现,即连接池的实现。通 常我们把DataSource的实现,按其英文含义称之为数据源,数据源中都包含了数据库连接池的实现。 也有一些开源组织提供了数据源的独立实现:有DBCP 数据库连接池和C3P0 数据库连接池。实际应用 时不需要编写连接数据库代码,直接从数据源获得数据库的连接。程序员编程时也应尽量使用这些数 据源的实现,以提升程序的数据库访问性能。
DBCP数据源
DBCP 是 Apache 软件基金组织下的开源连接池实现,使用DBCP数据源,应用程序应在系统中增加两 个 jar 文件:Commons-dbcp.jar(连接池的实现)与Commons-pool.jar(连接池实现的依赖库)Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程 序独立使用。
例:
public class JdbcUtils {
private static DataSource ds = null;
static{
try{
//用到类装载器读取DBCP的配置文件
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
//用之前除了要导入两个jar包,还有将dbcpconfig.properties考到类目录下,配置文件内部有连接信息
Properties prop = new Properties();
prop.load(in);
//实力化BasicDataSourceFactory工厂,并调用createDataSource方法将配置文件传入后获得连接池
BasicDataSourceFactory factory = new BasicDataSourceFactory();
ds = factory.createDataSource(prop);
}catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
//编写一个方法用于获取连接池中的连接
public static Connection getConnection() throws SQLException{
//内部返回的也不是真正的Connection,原因也是close方法重写,为了将连接直接返回连接池
return ds.getConnection();
}
}
C3P0 数据源
使用C3P0数据源,应用程序应在系统中导入c3p0-0.9.2-pre1.jar、mchange-commons-0.2.jar、 c3p0-oracle-thin-extras-0.9.2-pre1.jar(数据库为oracle才导入)文件
例:
public class JdbcUtils_C3P0 {
private static ComboPooledDataSource ds = null;
static{
try{
//实例化连接池,可以传入参数作为配置,如果不传入就用缺省的配置
ds = new ComboPooledDataSource();
//配置C3P0的配置要在c3p0-config.xml文件中配置,文件名不能变。将配置文件放到类目录 下(src)
}catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
public static Connection getConnection() throws SQLException{
return ds.getConnection();
}
}
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>驱动名称
<property name="jdbcUrl">jdbc:mysql://localhost:3306/day16</property>URL
<property name="user">root</property>用户名
<property name="password">root</property>密码
<property name="maxIdleTime">30</property>最大空闲时间
<property name="initialPoolSize">10</property>池初始化大小
<property name="minPoolSize">5</property>最小的池的数量
<property name="maxPoolSize">20</property>最大的池的数量
</default-config>
<named-config name="flx">名称为实力化池要传入的参数
<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="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</named-config>
</c3p0-config>
配置Tomcat数据源
在C:\apache-tomcat-6.0.36\conf\Catalina\localhost文件夹中新建context.xml文件配置,也可在META-INF 文件夹中新建context.xml文件配置。
<Context>
<Resourcename="jdbc/EmployeeDB"名称
auth="Container"容器创建
type="javax.sql.DataSource"类型
username="root"用户名
password="root"密码
driverClassName="com.mysql.jdbc.Driver"驱动
url="jdbc:mysql://localhost:3306/day16"URL
initialSize="10"初始化池个数
maxActive="30"最大可以池
maxIdle="4"/>最大空闲连接数
</Context>
注:如果要操作mysql,必须将mysql的驱动导入,否则会出现找不到类异常
public class JdbcUtils_Tomcat {
private static DataSource ds;
static {
try {
//初始化JNDI
Context initCtx = new InitialContext();
//找到JNDI容器
Context envCtx = (Context) initCtx.lookup("java:comp/env");
//找到数据源
ds = (DataSource) envCtx.lookup("jdbc/EmployeeDB");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static Connection getConnection() throws SQLException{
return ds.getConnection();
}
}