如何设计缓存及其应用

    缓存的设计通常要用到单例设计模式和资源设计模式,还须要注意多线程同步的问题,如下主要讨论如何设计缓存,什么是数据库链接池,以及Hibernate中的缓存机制。java

如何设计缓存

缓存原理

    在Java中常常用到缓存,在SSh框架中也会用到一级缓存和二级缓存,到底缓存是怎么实现的呢?数据库

    缓存就是利用本地参考原则:当CPU要读取一个数据时,首先从缓存中查找,找到就当即读取并送给CPU处理;没有找到,就用相对慢的速率从内存中读取并送给CPU处理,同时把这个数据所在的数据块调入缓存中,可使得之后对整块数据的读取都从缓存中进行,没必要再调用内存。缓存是一种典型的空间换时间的方案。设计模式

    缓存就至关因而一个临时内存:它有一个有限的空间量,但访问它比访问原始数据速度要快。缓存

 

    在分布式系统设计中,若是在请求层节点上放置一个缓存,便可响应本地的存储数据。当对服务器发送一个请求时,若是本地存在所请求数据,那么该节点即会快速返回本地缓存数据。若是本地不存在,那么请求节点将会查询磁盘上的数据。请求层节点缓存便可以存在于内存中(这个很是快速)也能够位于该节点的本地磁盘上(比访问网络存储要快)。全局缓存是指全部节点都使用同一个缓存空间;分布式缓存即缓存在分布式系统各节点内存中的缓存数据。安全

开源缓存产品 

    一个很是流行的开源缓存产品:Memcached(便可以在本地缓存上工做也能够在分布式缓存上工做)。Memcached用于许多大型Web站点,其很是强大。Memcached基于一个存储键/值对的hashmap,优化数据存储和实现快速搜索(O(1))。服务器

如何设计缓存

在Java中最多见的一种实现缓存的方式就是使用Map,基本的步骤是:网络

1)先到缓存里面查找,看看是否存在须要使用的数据多线程

2)若是没有找到,那么就建立一个知足要求的数据,而后把这个数据设置回到缓存中,以备下次使用框架

3)若是找到了相应的数据,或者是建立了相应的数据,那就直接使用这个数据。分布式

下面只是缓存的基本实现,还有不少功能都没有考虑,好比缓存的清除,缓存的同步等等。如今有不少专业的缓存框架。

缓存接口设计
public Interface<E,V> ICashe(){

   public void size(int max); //设置缓存池大小
   
   public void add(E e); //往缓存中添加数据
   
   public void remove(E e); //从缓存中移除数据
   
   public void update(E e); //更新缓存中的数据
   
   public E get(V v);//从缓存中获取符合条件的值
   
   public void clear(); //清除缓存中数据
   
   public boolean empty(); //判断缓存是否为空
   
   public boolean full(); //判断缓存是否已满
}//end Interface ICashe
缓存实现类举例(由于多个对象要共有一个缓存,因此缓存常实现为单例模式)
public class Cashe Implement ICashe{

   private volatile static Singleton uniqueInstance=null;
    private Map<String,Object> map = new HashMap<String,Object>(); //缓存数据的容器
   

   private Singleton(){
   }
   
   public static Singleton getInstance() {
        if(uniqueInstance == null){
		   synchronized (Singleton.class){ //note we only synchronize the first time through!
		      if(uniqueInstance == null)   //once in the block,check again and if still null, create an instance
			     uniqueInstance=new Singleton();
		   }//end synchronized	   
		}//end if
			
	    return uniqueInstance;
   }//end getInstance()
   
   //other useful methods here
   @override
   public E get(V v){
      //先从缓存里面取值
      E e = map.get(v);
	  
     //判断缓存里面是否有值
     if(e == null){
     //若是没有,那么就去获取相应的数据,好比读取数据库或者文件
     //这里只是演示,因此直接写个假的值
     e = v+",value";
     //把获取的值设置回到缓存里面
     map.put(v, e);
    } //end if
  
    //若是有值了,就直接返回使用
    return e;
   }//end get()
   
   @override
   public void add(E e){
   //TODO
   }
   
   @override
   public void remove(E e){
   //TODO
   }
   
   @override
   public void update(E e){
   //TODO
   }
   
   @override
   public void clear() {
   //TODO
   }
   
   @override
   public boolean empty(){
   //TODO
   } 
   
   @override
   public boolean full(){
     //TODO
   } 
   
}//end class Singleton


数据库链接池

 

为何使用数据库链接池

 

    在传统的两层结构中,客户端程序在启动时打开数据库链接,在退出程序时关闭数据库链接。这样,在整个程序运行中,每一个客户端始终占用一个数据库链接,即便在大量没有数据库操做的空闲时间,如用户输入数据时,从而形成数据库链接的使用效率低下。

    对于Connection这样的资源,初始化的开销是很大的,由于创建链接必须进行Socket链接,验证以及受权等繁杂的操做,代价是昂贵的,所以及早初始化必定量打开的链接,而且缓存起来是一个至关不错的策略。

    那么怎么作呢?对于共享资源,有一个很著名的设计模式:资源池 (Resource Pool)。该模式正是为了解决资源的频繁分配?释放所形成的问题。为解决上述问题,能够采用数据库链接池技术。数据库链接池的基本思想就是为数据库链接创建一个“缓冲池”。预先在缓冲池中放入必定数量的链接,当须要创建数据库链接时,只需从“缓冲池”中取出一个,使用完毕以后再放回去。咱们能够经过设定链接池最大链接数来防止系统无尽的与数据库链接。更为重要的是咱们能够经过链接池的管理机制监视数据库的链接的数量?使用状况,为系统开发?测试及性能调整提供依据。

    所以,在前面的两层结构中,加入一层-数据库链接池。在三层结构模式中,数据库链接经过中间层的链接池管理。只有当用户真正须要进行数据库操做时,中间层才从链接池申请一个链接,数据库操做完毕,链接当即释放到链接池中,以供其余用户使用。这样,不只大大提升了数据库链接的使用效率,使得大量用户能够共享较少的数据库链接,并且省去了创建链接的时间。

如何设计一个数据库链接池

    一般用链接池管理类(DBConnectionManager)来使用数据库链接池( DBConnectionPool)。由于系统中只能有一个链接池管理类的实例,因此链接池管理类的实现是单例模式。

    链接池管理类主要用于对多个链接池对象的管理,具备如下功能:①装载并注册特定数据库的JDBC驱动程序;②根据属性文件给定的信息,建立链接池对象;③为方便管理多个链接池对象,为每个链接池对象取一个名字,实现链接池名字与其实例之间的映射;④跟踪客户使用链接状况,以便须要是关闭链接释放资源。链接池管理类的引入主要是为了方便对多个链接池的使用和管理,如系统须要链接不一样的数据库,或链接相同的数据库但因为安全性问题,须要不一样的用户使用不一样的名称和密码。

数据库链接池接口设计

 

//用数据库链接池接口设计
public interface DBConnectionPool<E> {
	//最大最小链接数
	public synchronized void size(int min,int max);
    //新建一个数据库链接
  public synchronized E newConnection(String name,String URL,String user,String password); 
    //获得一个链接,timeout是等待时间
  public synchronized E getConnection(long timeout);  
    //断开全部链接,释放占用的系统资源
  public synchronized void release();     
    //使用完毕以后,把链接返还给空闲池
  public synchronized void freeConnection(Connection con);  
} //end interface DBConnectionPool

链接池管理类

public class DBConnectionManager {
  static private DBConnectionManager instance;
  //链接池管理类的惟一实例
  static private int clients;//客户数量
  private ArrayList drivers=new ArrayList();
  //容器,存放数据库驱动程序
  private HashMap pools = new HashMap();
  //以name/value的形式存取链接池对象的名字及链接池对象
  static synchronized public DBConnectionManager getInstance()
  /**若是惟一的实例instance已经建立,直接返回这个实例;不然,调用私有构造函数,
  建立链接池管理类的惟一实例*/
  private DBConnectionManager()
  //私有构造函数,在其中调用初始化函数init()
  public void freeConnection(String name,Connection con)
  //释放一个链接,name是一个链接池对象的名字
  public Connection getConnection(String name)
  //从名字为name的链接池对象中获得一个链接
  public Connection getConnection(String name,long time)
  //从名字为name的链接池对象中取得一个链接,time是等待时间
  public synchronized void release()//释放全部资源
  private void createPools(Properties props)
  //根据属性文件提供的信息,建立一个或多个链接池
  private void init()//初始化链接池管理类的惟一实例,由私有构造函数调用
  private void loadDrivers(Properties props)//装载数据库驱动程序
} //end DBConnectionManager

 

Hibernate缓存TODO

一级缓存

二级缓存

Hibernate优化

相关文章
相关标签/搜索