緩存的設計通常要用到單例設計模式和資源設計模式,還須要注意多線程同步的問題,如下主要討論如何設計緩存,什麼是數據庫鏈接池,以及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優化