`
z75148885
  • 浏览: 191601 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

持久层设计与资源管理模式

阅读更多

无论是怎样的应用系统,都无法脱离对资源的管理和使用。而对于持久层而言,资源的合理管理和调度则显得尤为重要。

在大多数应用系统中,80%以上的应用逻辑并不需要特别复杂的数据库访问逻辑(可能只是几条简单的Select或作者Insert/Update语句)。对于这些占到多数的简单逻辑而言,如果SQL语句和数据库本身的设计不是太糟糕(合适的关联,字段索引以及数据库分区策略),在特定的硬件环境下,我们认为数据库的性能基本稳定。
此时,导致持久层性能地下的罪魁祸首可能并不是数据库本身,而是在于失败的资源管理调度机制。

Connection Pool
即使对于我们而言,通过JDBC获取数据库连接实在是件再简单不过的事情,但对于JDBC Driver来说,连接数据库却并非一件轻松差事。数据库连接不仅仅是在应用服务器与数据库服务器之间建立一个Socket Connection(对于Type4 的JDBC Driver而言),连接建立之后,应用服务器和数据库服务器之间还需要交换若干次数据(验证用户密码,权限等),然后,数据库开始初始化连接会话句柄,记录联机日志,为此连接分配相应得处理进程和系统资源。

系统如此忙碌,如果我们只是简单地仍过去两个SQL语句,然后就将此连接抛弃,实在可惜,而数据库连接池技术正是为了解决这个问题。
数据库连接池的基本原理是在内部对象池中维护一定数量的数据库连接,并对外暴露数据库连接获取或返回方法。如图

数据库连接池基本原理示意
外部使用者可以通过getConnection方法获取连接,使用完毕后再通过releaseConnection方法将连接返回,注意此时连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。
数据连接池技术带来下面的优势:
1. 资源重用
由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。
2. 更快的系统响应速度
数据库连接池仔初始化过程中,往往已经创建了若干数据库连接池置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
3. 新的资源分配手段
对于应用共享同一个数据库的系统而言,可在应用曾通过数据库连接池的配置,实现某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。
4. 统一的连接管理,避免数据库连接泄露
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄露。
一个最小化的数据库连接池实现:


代码
package net.wanjin.lab.utils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Vector;

public class ConnectionPool {

private static Vector pool;
private final int POOL_MAX_SIZE =20;
/**
* 获取数据库连接
* 如果当前池中有可用连接,则将池中最后一个返回,如果没有,则新建一个返回
* @return
* @throws DBException
*/
public synchronized Connection getConnection() throws DBException{

if(pool ==null){
pool = new Vector();
}
Connection conn;
if(pool.isEmpty()){
conn = createConnection();
}else{
int last_idx = pool.size() -1;
conn =(Connection)pool.get(last_idx);
pool.remove(pool.get(last_idx));

}
return conn;
}
/**
* 将使用完毕的数据库连接放回备用池
*
* 判断当前池中连接数是否已经超过阀值
* 如果超过,则关闭该连接
* 否则放回池中以备下次重用
* @param conn
*/
public synchronized void releaseConnection(Connection conn){

if(pool.size()>POOL_MAX_SIZE){
try{
conn.close();
}catch(SQLException e){
e.printStackTrace();
}
}else{
pool.add(conn);
}
}
/**
* 读取数据库配置信息,并从数据库连接池中获得数据库连接
* @return
* @throws DBException
*/
private static Connection createConnection() throws DBException{
Connection conn;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@1521:oracle","personal","personal");
return conn;
}catch(ClassNotFoundException e){
throw new DBException("ClassNotFoundException when loading JDBC Driver");
}catch(SQLException e){
throw new DBexception("SQLException when loading JDBC Driver");
}
}

}


完备的连接池实现固然错综复杂,但就其根本而言,还是源自同样的思想。

先脱离连接池本身的具体实现,我们看看这段代码在实际应用中可能产生的问题,注意到,由于getConnection方法返回的是一个标准的JDBC Connection,程序员由于编成习惯,可能会习惯性的调用其close方法关闭连接。如此一来,连接无法得到重用,数据库连接池机制形同虚设。为了解决这个问题,比较好的途径有:
1. Decorator 模式
2. Dynamic Proxy 模式
下面我们就这两种模式进行一些探讨:
“Decorator模式的主要目的是利用一个对象,透明地为另一个对象添加新的功能”。
这句话是从GOF关于设计模式的经典著作《设计模式-可复用面向对象软件的基础》一书中关于Decorator模式的描述直译而来,可能比较难以理解。简单来讲,就是通过一个Decorator对原有对象进行封装,同时实现与原有对象相同的接口,从而得到一个基于原有对象的,对既有接口的增强性实现。


对于前面所讨论的Connection释放的问题,理所当然,我们首先想到的是,如果能让JDBC Connection在执行close操作时自动返回到数据库连接池中,那么所有问题都将迎刃而解,但是,JDBC Connection自己显然无法根据实际情况判断何去何从。此时,引入Decorator模式来解决我们所面对的问题就非常合适。

首先,我们引入一个ConnectionDecorator类:


代码
import java.sql.Connection;
import java.sql.SQLException;

public class ConnectionDecorator implements Connection {
Connection dbconn;

public ConnectionDecorator(Connection conn){
this.dbconn = conn; //实际从数据库获得的Connection引用
}

/**
* 此方法将被子类覆盖,以实现数据库连接池的连接返回操作
* @see java.sql.Connection#close()
*/
public void close() throws SQLException{
this.dbconn.close();
}
/**
* (non-Javadoc)
* @see java.sql.Connectionn#commit()
*/
public void commit() throws SQLException{
this.dbconn.commit(); //调用实际连接的commit方法
}
//以下各个方法类似,均调用dbconn.xxx方法作为Connection接口中方法的简单实现.

}


可以看到,ConnectionDecorator类实际上的对传入的数据库连接加上一个外壳,他实现了java.slq.Connection接口,不过本身并没有实现任何实际内容,只是简单的把方法的实现委托给运行期实际获得的Connection实例,,而从外部来看,ConnctionDecorator与普通Connection实例并没有什么区别,因为他们实现了同样的接口,对外提供了同样的功能调用。

目标很清楚,通过这样的封装,我们的ConnectionDecorator对于外部的程序员而言,调用方法与普通的JDBC Connection完全相同,而在内部通过对ConnectionDecorator的修改,我们就可以透明地改变现有实现,为了增加新的特性:


代码
package net.wanjin.lab.persistence.Decorator;

import java.sql.Connection;

import net.wanjin.lab.utils.ConnectionPool;

public class PooledConnection extends ConnectionDecorator implements Connection{

private ConnectionPool connPool;

public PooledConnection(ConnectionPool pool,Connection conn){
super(conn);
connPool = pool;
}
/**
* 覆盖Close方法,将数据库连接返回连接池,而不是直接关闭连接
*/
public void close() throws SQLException{
connPool.releaseConnection(this.dbconn);
}
}
为了应用新的PooledConnection ,我们需要对原本的DBConnectionPool.getConnection和releaseConnection方法稍做改造:

/**
* 获取数据库连接
* 如果当前池中有可用连接,则将池中最后一个返回,如果没有,则新建一个返回
* @return
* @throws DBException
*/
public synchronized Connection getConnection() throws DBException{

if(pool ==null){
pool = new Vector();
}
Connection conn;
if(pool.isEmpty()){
conn = createConnection();
}else{
int last_idx = pool.size() -1;
conn =(Connection)pool.get(last_idx);
pool.remove(pool.get(last_idx));

}
//return conn;
return new PooledConnection(this,conn);
}
/*
* 将使用完毕的数据库连接放回备用池
*
* 判断当前池中连接数是否已经超过阀值
* 如果超过,则关闭该连接
* 否则放回池中以备下次重用
* @param conn
*/
public synchronized void releaseConnection(Connection conn){

if(conn instanceof PooledConnection||pool.size()>POOL_MAX_SIZE){
try{
conn.close();
}catch(SQLException e){
e.printStackTrace();
}
}else{
pool.add(conn);
}
}

此时获取数据库连接后,调用这只需要按照JDBC Connection的标准用法进行调用即可,从而实现了数据库连接的透明化。同样的道理,我们甚至可以利用Decorator模式对DriverManager类进行同样的改造,从而最小化数据库连接池实现对传统JDBC编码方式的影响。

Dynamic Proxy 模式
DynamicProxy是JDK1.3版本中新引入的一种代理机制。严格来讲,DynamicProxy本身并非一种模式,只能算是Proxy模式的一种动态实现方式,不过为了与传统Proxy模式相区分,这里暂且将其称为“Dynamic Proxy模式”,来泛指通过Dynamic Proxy机制实现的Proxy模式。
回到上面的问题,我们的目标是在引入数据库连接池机制的同时,保持JDBCConnection对外接口不变。前面通过Decorator接口中定义的方法众多,我们也只是能照单全收,在ConnecionDecorator中逐一实现这些方法,虽然只是简单的委托实现,也实在是件恼人的工作。
Dynamic Proxy模式则良好地解决了这一问题。通过实现一个邦定到Connection对象的InvocationHandler接口实现,我们可以在Connection.close方法被调用时将其截获,并以我们自己实现的Close方法将其代替,使连接返回到数据库连接池等待下次重用,而不是直接关闭。

下面是ConnectionHandler类,它实现了InvocationHandler接口,按照DynamicProxy机制的定义,Invoke方法将截获所有代理对象的方法调用操作,这里我们通过invoke方法截获close方法进行处理。


代码
package net.wanjin.lab.utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;

public class ConnectionHandler implements InvocationHandler {

Connection dbconn;
ConnectionPool pool;

public ConnectionHandler(ConnectionPool connPool){
this.pool = connPool;
}
/**
*
*/
public Connection bind(Connection conn){
this.dbconn = conn;

Connection proxyConn =(Connection)Proxy.newProxyInstance(
conn.getClass().getClassLoader(),conn.getClass().getInterfaces(),this);

return proxyConn;
}

public Object invoke(Object proxy,Method method,Object[] args)
throws Throwable{
Object obj =null;
//如果调用的是close方法,则用pool.releaseConnection方法将其替换
if("close".equals(method.getName())){
pool.releaseConnection(dbconn);
}else{
obj = method.invoke(dbconn, args);
}
return obj;

}

}


配合Dynamic Proxy模式,我们的DBConnectionPool.getConnection方法也做了一点小的修改:

代码
/**
* 获取数据库连接
* 如果当前池中有可用连接,则将池中最后一个返回,如果没有,则新建一个返回
* @return
* @throws DBException
*/
public synchronized Connection getConnection() throws DBException{

if(pool ==null){
pool = new Vector();
}
Connection conn;
if(pool.isEmpty()){
conn = createConnection();
}else{
int last_idx = pool.size() -1;
conn =(Connection)pool.get(last_idx);
pool.remove(pool.get(last_idx));

}
//return conn;
//return new PooledConnection(this,conn);
ConnectionHandler connHandler = new ConnectionHandler(this);
return connHandler.bind(conn);
}


可以看到,基于Dynamic Proxy 模式的实现相对Decorator更加简洁明了。

分享到:
评论

相关推荐

    持久层设计

    CLASS-TYPE体系结构是一种常见的持久层设计模式,它的核心思想是将实体类与数据访问逻辑分离。在这种体系结构下,实体类代表了业务领域模型,而数据访问逻辑则封装在专门的类中。这种方式的优点包括: - **解耦**:...

    鲁棒的数据库持久层设计.pdf

    在IT领域,尤其是软件开发与数据库管理中,鲁棒的数据库持久层设计是确保应用程序稳定、高效运行的重要环节。本解析将围绕给定文件“鲁棒的数据库持久层设计.pdf”的标题、描述、标签以及部分内容,深入挖掘其中的...

    基于SpringBoot的旅游资源管理网站的设计与实现

    本文的设计与实现在于通过后端框架SpringBoot、持久层框架MyBatis和模板引擎Thymeleaf来共同打造这样一个旅游资源管理网站。 SpringBoot是一个流行的Java框架,它简化了Spring应用的配置和部署流程。SpringBoot提供...

    鲁棒的数据库持久层设计

    持久层设计主要关注的是如何高效地在内存中的对象模型与数据库中的记录之间进行转换。根据不同的设计模式和架构风格,持久层可以分为多种类型: - **ORM(对象关系映射)**:将对象模型直接映射到数据库表上,简化...

    设计健壮的关系数据库持久层

    #### 五、持久层设计概述 文档中的设计部分详细讨论了持久层的设计要素: 1. **总体设计**:从高层次上概述了持久层的组成部分及其相互作用。 2. **具体类的设计**:每个类的作用和其实现细节,如持久对象类如何...

    多层J2EE系统的架构与模式设计

    单例模式保证了类只有一个实例,常用于资源管理。DAO模式结合工厂模式,可以创建灵活且易于测试的数据访问组件。 总结,J2EE通过其多层架构和设计模式,为构建复杂的企业级应用提供了强大支持。理解并熟练运用这些...

    基于SSH的人力资源管理系统的开发和设计开题报告.docx

    【基于SSH的人力资源管理系统开发】\n\nSSH(Struts2+Hibernate+Spring)框架是一种广泛应用于Web应用开发的技术组合,尤其在企业级人力资源管理系统的设计中,SSH框架展现出其强大的优势。本开题报告主要探讨如何...

    文件系统持久层 sst256401 stm25p64

    在嵌入式系统中,文件系统的持久层设计至关重要,因为它直接影响到数据的可靠性和效率。针对大容量、大擦除块的SPI接口Flash设备,如SST256401和STM25P64,其特有的硬件特性为文件系统设计带来了一定挑战。 SST...

    基于J2EE的企业人力资源管理系统的设计与实现

    《基于J2EE的企业人力资源管理系统的设计与实现》 在当今数字化时代,企业对高效、智能的人力资源管理需求日益增长。基于J2EE技术构建的企业人力资源管理系统(HRMS)能够提供这样的解决方案,它集成了员工信息管理、...

    MVC模式下多层分布式软件系统架构设计.pdf

    Struts负责MVC中的控制层(Controller),Spring则提供了中间层框架支持,包括业务对象(Bean)管理和依赖注入,Hibernate作为对象关系映射(ORM)工具,负责持久层(Model)。这种整合不仅实现了MVC模式在Java Web...

    java_ssm人力资源管理系统的设计与实现vue毕业论文.doc

    Java_SSM人力资源管理系统的设计与实现 本文主要介绍了基于Java_SSM架构的人力资源管理系统的设计和实现。该系统旨在提高企业人力资源管理效率,以应对不断增长的人力资源管理需求。 SSM架构 SSM架构是指Spring、...

    Spring的MVC Web应用中的持久层技术

    JdbcTemplate是Spring框架对Java数据库连接(JDBC)的一个封装,旨在简化数据库操作,减少手动处理SQL和资源管理的繁琐工作。通过使用模板方法设计模式,它将常见的错误处理和资源关闭等任务自动化,使开发者能够...

    基于SpringBoot+MyBatis框架的高校人事信息发布系统设计与实现

    而MyBatis在Java EE的数据持久层框架中有着广泛的应用,能够将对象映射成数据库中的数据,实现复杂查询和事务管理。 系统的实现过程中还涉及到信息的安全性问题,因为人事信息往往涉及隐私和机密信息,因此系统需要...

    Spring框架的设计理念与设计模式分析

    ### Spring框架的设计理念与设计模式分析 #### 一、Spring框架概述 Spring作为一个现代软件开发领域内备受推崇的框架,其设计理念与设计模式一直是开发者关注的焦点。Spring框架以其轻量级、模块化和可扩展性著称...

    人力资源管理系统设计与实现开题报告.pdf

    传统的人力资源管理模式往往侧重于事务性操作,忽视了员工的积极性和工作效率的提升,同时手工操作效率低下,难以应对大规模企业的人员管理需求。 因此,设计并实现一个人力资源管理系统显得尤为重要。这个系统旨在...

    ssm人力资源管理系统

    SSM人力资源管理系统是一款基于Java开发的Web应用,其核心框架采用了Spring、SpringMVC和MyBatis这三大流行技术...对于学习和理解SSM开发模式,以及深入了解人力资源管理流程的开发者来说,这是一个有价值的实践案例。

    人力资源管理系统源代码

    4. **MyBatis框架**:MyBatis是一个轻量级的持久层框架,它将SQL与Java代码分离,使得SQL的编写更加灵活。在HRSystem中,MyBatis可以用来映射Java对象与数据库表,实现高效的CRUD操作。 5. **前端技术**:前端部分...

    基于JavaEE的人力资源管理系统设计与实现.pdf

    不过,仍可根据给定的文件标题和描述部分提供一个关于“基于JavaEE的人力资源管理系统设计与实现”的知识点概述。 JavaEE是一种企业级应用程序架构,其全称为Java Platform, Enterprise Edition。它是Sun ...

    基于SSM的人力资源管理系统(含数据库文件).zip

    3. MyBatis:MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。它将SQL语句直接写在XML配置文件或注解中,使得SQL与Java代码...

Global site tag (gtag.js) - Google Analytics