JAVA : 实现自定义—数据库连接池(装饰者设计模式)
首先说一下什么是数据库连接池:
在传统是开发模式下,Servlet处理用户的请求时,调用Dao和数据库建立连接,完成相应的操作后,关闭数据库的连接,那么问题来了,成千上万的用户请求和数据库建立连接就会让数据库服务器吃不消,甚至导致内存的溢出,数据库连接池就应运而生;用户再次请求连接的时候,不再是直接去找数据库,而是来找连接池,极大的减轻数据库服务器的负担—–
下面言归正传:
这是 MyDataSource.java
/*01:第一步需要实现javax.activation下的DataSource接口;
添加接口的方法后,映入眼帘的一堆未实现的方法,这里只做一个简单
连接池,仅重写getConnection()*/
public class MyDataSource implements DataSource{
//存放创建出来的连接对象
List<Connection> list = new ArrayList<>();
//一次性创建多个数据库连接对象(放在构造函数中,旨在一旦使用这
类,自动创建10个连接对象)
MyDataSource(){
for(int i=0 ; i<=10 ;i++){
Connection conn = JDBCUtil.getConn();
list.add(conn);
}
}
//提供公共的访问方法提供连接对象
@Override
public Connection getConnection() throwsException{
//判断是否需要扩容;
if(list.size<=0){
for(int i=0;i<5;i++){
Connection conn = JDBCUtils.getConn();
list.add(conn);
}
}
Connection conn = list.remove(0);
/*
写到这里,可以发现,在测试类中这样写使用连接池:
MyDataSource datasource = new MyDataSource();
注意,这里返回的不是DataSource;
所以,当我想把使用完的连接对象放回去的时候,我只能手动
写-->dataSource.addback();
为了增情用户的体验感,包装-原来的工具类中的释放资源函数,
让这函数去回收连接对象; JDBCUtil里面的close();
解决方案--装饰者设计模式;
*/
Connection connection =ConnectionWrap(conn,list);
//这里返回的就是经过包装后连接对象;
return connection;
}
//收回使用完的连接对象
public addBack(Conncetion conn){
list.add(conn);
}
//此处省去了一大堆DataSource的方法;
......
}
这是是ConnectionWrap
/*装饰者设计模式--目的是对我MyDataSource进行包装,增强现
JDBCUtil类中release()方法;*/
/*使用装饰者设计模式的前提,被包装的类实现了某个接口,
然后,我的包装类首先实现那个接口;
*/
//这个包装类返回的连接对象仅仅是实现简单连接功能;
public class ConnectionWrap implements Connection(){ /*
//在把需要包装的类的实例当作参数传进ConnectionWrap的构造函数中
//这样做的目的是有了需要包装类的实例,就有了无限可能-调用它的方法;
Connection conn = null;
List<Connection> list =null;
public ConnectionWrap(Connection conn ,List<Connection>list){
super();
this.conn=conn;
this.list=list;
}
//根据需求(用户在使用JDBCUtil里面的relase()方法时,达到收回连接
//连接对象的目的,而release()里面又是close方法)
@Override
public close(){
list.add(conn);
}
//这里重写Preparement的功能(和数据库打交道,一定少不了它)
@Override
public PrepareStatement prepareStatement(String sql){
return conn.prepareStatement(sql);
}
//这里面是一堆Datasource未实现的方法
......
}
这里是测试类:
public class text{
puclic text(){
//从连接池中获取连接对象;
MyDataSource dataSource = new MyDataSource();
Connection conn = null;
PrepareStatement ps = null;
try{
conn = dataSource.getConnection();
String sql = "insert into 表名 values(null,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1,"pool");
ps.setString(2,"123434");
//执行sql语句
int a = ps.executeUpdata();
if(a>0){
System.out.println("插入成功");
}else{
System.out.println("插入失败");
}
}catch (SQLException e) {
e.printStackTrace();
}finally{
//此时,不必再写add back方法 归还连接对象,release()函数里会去调用我们自己wrap的close方法
JDBCUtil.release(ps, conn);
}
}
这个是JDBCUtils 工具类
public class JDBCUtil {
public static void release(ResultSet rs , Statement cs , Connection conn){
closeRS(rs);
closeCs(cs);
closeConn(conn);
}
public static void release(Statement cs , Connection conn){
closeCs(cs);
closeConn(conn);
}
//下面这三个方法都的pervate,受受保护,体更公共的访问接口
private static void closeRS (ResultSet rs ){
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
rs = null;
}
}
private static void closeCs (Statement cs ){
try {
cs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
cs = null;
}
}
private static void closeConn (Connection Conn ){
try {
Conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
Conn = null;
}
}
/* 1、 一般在公司中会把这三条放置在配置文件中(properties)配置文件放在了src文件中;
* 2、在回过头来,写一个静态代码块,在我的这个工具类中把我配置文件里面的内容读取出来;
* 3、这样 以后再更改的时候,我直接去修改配置文件就行
* static String url = "jdbc:mysql://localhost/student" ;
static String username = "root";
static String password = "root";*
static String driverClass = null;
static String url =null;
static String username = null;
static String password = null;
static{
try {
//创建属性配置对象;
Properties properties = new Properties();
//导入输入流
/*如果配置文件在工程的根文件夹下用这个
InputStream is = new FileInputStream("jdbc.properties ");*/
// 如果是src里面; 加载JDBCutil 字节码,得到类加载器,然后把配置文件转换成流
InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
properties.load(is);
driverClass = (String) properties.get("driverClass");
url = (String) properties.get("url");
username = (String) properties.get("username");
password = (String) properties.get("password");
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConn(){
Connection conn = null;
try {
//创建连接
/*jdbc:mysql://localhost/test?" + "user=monty&password=greatsqldb*/
//注册驱动 ---直接newDriver的话,Driver是个接口,出来一堆代码,故new 继承了Driver的 mysql.Driver
//在Driver中有一块静态代码块帮我们注册了驱动,我们相当于注册了两次驱动
// DriverManager.registerDriver(new org.gjt.mm.mysql.Driver() );
//参照文档---防止二次注册驱动(需要抓异常,在下面的catch的Exception)
//注册驱动可以不写
Class.forName(driverClass);
//获取连接对象;
conn = DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
}