您的位置:首页 > 其它

手动编写JDBC连接池应用适配器和装饰者模式

2016-09-17 22:46 260 查看
背景:

     为了对DBUtil更好的理解,所以决定自己手动编写一个连接池,众所周知,DBUtil是一个操作数据库的工具类,是对jdbc的简单封装,不会损耗数据库的性能,所以有的公司为了追求性能使用DBUtils,现在一个普遍的规律就是封装的越完善,性能就越低,首先说说Hibernate,因为这个纯粹的ORM框架,封装的特别的完善,所以性能便有所降低,如果应用到大型的项目中就会显得很笨重,MyBatis算是现在最流行的框架了,他是介于DBUtils和Hibernate之间的。那么下面就说说是如何手动编写的连接池吧,然后用上适配器和装饰者设计模式。

  1、首先来看看目录结构:

  


  2、然后编写自己的连接池: 

     首先创建一个池子,这个池子采用LinkedList,因为LinkedList插入删除比较方便,效率高,通过MyDataSource的构造方法初始化连接数,然后通过装饰者设计模式对conn对象进行加强(这里我们可以联想BufferedReader是如何创建对象的),然后编写获取池子和移除池子的方法
package com.itheima.datasourse;

import java.sql.Connection;
import java.util.LinkedList;

public class MyDataSource {
//存储Connection资源的容器
private static LinkedList<Connection> pool = new LinkedList<Connection>();

public MyDataSource(int initCount){
try {
for(int i=0;i<initCount;i++){
Connection conn = JDBCUtils.getConnection();

//获得原始的conn对象 对该conn进行增强
EnhanceConnection enhanceConn = new EnhanceConnection (conn);

pool.add(enhanceConn);
}
} catch (Exception e) {
e.printStackTrace();
}
}

//提供一个获得池子中connection资源的方法
public Connection getConnection(){
return pool.removeFirst();
}

//提供一个将资源归还给池子的方法
public static void giveBack(Connection conn){
System.out.println("归还资源前池子中的资源数:"+pool.size());
pool.addLast(conn);
System.out.println("归还资源后池子中的资源数:"+pool.size());
}
}

 3、编写AbstractDatasourse类:

    这个类去实现Connection接口,因为方法比较多,所以就不用代码展示了,里面没有自己敲的代码,括号里面是稍微比较官方的解释(当一个接口有多个抽象方法时,而我们只使用其中的一个或两个方法时,每次使用的时候我们都要重写这些方法,比较麻烦。我们可以定义一个类去实现这个接口,并重写里面的方法,只是方法体为空,并把这个类定义为抽象类,我们使用的时候继承这个类重写需要的方法就就可以了)

4、继承AbstractDatasourse类:

并且从写close方法和prepareStatement方法,因为有的时候我们写工具类的时候可能关闭后,池子里面的连接数就会变少,所以为了避免这种情况我们重写close方法:

package com.itheima.datasourse;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class EnhanceConnection extends AbstractDatasourse {
private Connection conn;

public EnhanceConnection(Connection conn){
this.conn = conn;
}

//需要增强的方法 重写业务逻辑
public void close() throws SQLException {
//将conn返回池子中
MyDataSource.giveBack(conn);
}
public PreparedStatement prepareStatement(String sql) throws SQLException {
return conn.prepareStatement(sql);
}
}

5、为了提高代码的复用性,我们将数据库的连接抽到配置文件中,把共有的功能抽取到JDBCUtil里面

package com.itheima.datasourse;

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 JDBCUtils {
private static String driverClass = null;
private static String url = null;
private static String user = null;
private static String password = null;

static{
try {
//为四个变量参数赋值
//获得配置文件 读取配置文件中的键值对 根据键获得对应值进行赋值
InputStream in = new FileInputStream("D:\\workspace\\jiuyeday09\\LWEB10\\src\\jdbc.properties");
//集合对象
Properties pro = new Properties();
pro.load(in);//将输入流中的键值对转换成Properties对象内部的键值对形式

//通过Properties的getProperty(key)方法 获得对应的值value
driverClass = pro.getProperty("driverClass");
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");

Class.forName(driverClass);//执行一次
} catch (Exception e) {
e.printStackTrace();
}
}

//获得链接对象的方法
public static Connection getConnection() throws Exception{
Connection conn = DriverManager
.getConnection(url,user,password);
return conn;
}

//关闭资源的方法
public static void close(ResultSet rs,Statement stmt,Connection conn){

if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
rs = null;
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
stmt = null;
}
}
if(conn!=null){

}

}
}jdbc.properties配置文件中的内容:
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql:///student
user=root
password=root

6、编写测试类:

package com.itheima.datasourse;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.junit.Test;

public class MyDataSourceTest {
@Test
public void test() throws SQLException{
//0、创建连接池对象
MyDataSource dataSource = new MyDataSource(10);
//1、从池子中获得一个资源对象
Connection conn = dataSource.getConnection();
//2、jdbc的操作
PreparedStatement pstmt = conn.prepareStatement("select * from student");
ResultSet rs = pstmt.executeQuery();
while(rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getString("chinese"));
System.out.println(rs.getString("english"));
System.out.println(rs.getString("math"));
}
rs.close();
pstmt.close();
//3、将资源过还给池子
conn.close();

}
}

7、测试结果:



总结:

    敲完之后对许多东西有了新的认识,包括适配器,装饰者(包装类),而且更加了解了连接池的底层是如何实现的。相信明白了,在听到连接池,什么c3p0,DBUtil就不怕了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: