日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

数据库 -- 由数据库连接池引出的三种设计模式

發布時間:2024/9/5 数据库 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据库 -- 由数据库连接池引出的三种设计模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

筆記摘要:

? ? ?這里首先對數據庫連接池的優化進行了說明,同時自己編寫了一個數據庫連接池,在實際開發中,為了獲取標準的數據源,我們需要去實現javax.sal.DataSource接口,

? ? ?在實現過程中對于鏈接對象的close方法進行了不同的實現,以便在關閉close的時候,將連接對象放回連接池,而不是關閉掉,針對這一問題,提供了3種不同的解決

? ? ?方案,涉及了3種設計模式:裝飾,適配器和代理。

?

一、直接獲取連接與使用連接池的比較

應用程序直接獲取連接示意圖

?

?

缺點:

? ? 用戶每次請求都需要向數據庫獲得鏈接,而數據庫創建連接通常需要消耗相對較大的資源,創建時間也較長。假設網站一天10萬訪問量,數據庫服務器就需要創建10萬次連接,極大的浪費數據庫的資源,并且極易造成數據庫服務器內存溢出、拓機。

?

?數據庫連接池示意圖

?

優勢:

連接池中會有指定個數的連接對象,每次連接的時候,只要將請求發給連接池,連接池就會提供連接對象,使用完之后,再將連接對象放回連接池,

這樣不用每次都去連接,大大提高了性能。

?

二、編寫一個基本的連接池實現連接復用

?

原理:

通過一個LinkedList來模擬連接池,每次取Connection的時候,就remove,當釋放的時候就再add進去,這里通過打印remove的前后,來說明每次使用之后會放回“連接池”

dbinfo.properties

className=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mydb user=root password=root

?

自定義連接池

import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Collections; import java.util.LinkedList; import java.util.ResourceBundle;import javax.management.RuntimeErrorException;public class SimpleConnectionPool {private static String className;private static String url;private static String user;private static String password;//創建一個集合用于模擬連接池private static LinkedList<Connection> pool = new LinkedList<Connection>(); // private static LinkedList<Connection> pool = (LinkedList<Connection>) Collections.synchronizedCollection(new LinkedList<Connection>());//加載配置文件并注冊驅動static{try {ResourceBundle bundle = ResourceBundle.getBundle("cn.itmonkey.util.dbinfo");className = bundle.getString("className");url = bundle.getString("url");user = bundle.getString("user");password = bundle.getString("password");Class.forName(className);//創建10個連接對象for(int i=0;i<10;i++){Connection conn = DriverManager.getConnection(url,user,password);pool.add(conn);}System.out.println("初始化連接");//打印所創建的連接對象int i=0;for(Connection conn: pool){System.out.println(conn+"..."+i++);}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();}}//獲取連接對象,由于可能同時會有多個對象來取,所以使用同步public synchronized static Connection getConnection(){System.out.println("取之前的連接如下");int i=0;for(Connection conn: pool){System.out.println(conn+"..."+i++);}//從隊列中移出一個連接對象,返回給調用者if(pool.size()>0){ //防止為0的時候,導致異常,所以要進行判斷Connection conn = pool.remove();return conn;}else{throw new RuntimeException("對不起,服務器忙!");}}//將連接對象釋放到隊列中public static void release(Connection conn){pool.addLast(conn);} }

二、編寫標準的數據庫連接池

標準的數據源:

需要實現javax.sal.DataSource接口的類,標準的數據源里默認了維護了一個連接池

?

問題:

在直接獲取標準數據源的Connection后,在調用它的close方法時,不是還回連接池中,而是直接關閉,我們希望在調用close方法的時候,是將Connection還回連接池中,而不是關閉

?

解決方案一:裝飾設計模式

通過裝飾,對需要的已有功能進行增強

?

裝飾設計模式編寫步驟

1、編寫一個類,實現與被增強對象相同的接口

2、定義一個引用變量,記住被增強對象

3、定義構造方法,參數為接口后者父類,比便實現多態,傳入被增強對象, 并給第2部的變量賦值

4、對于要增強的方法,自己改寫

5、對于不需要增強的方法,調用原有對象的對應方法。

public class MyConnection implements Connection{private Connection conn;private LinkedList<Connection> pool;//模擬連接池public MyConnection(Connection conn,LinkedList<Connection> pool){this.conn = conn;this.pool = pool;}//釋放連接對象到連接池 @Overridepublic void close() throws SQLException {pool.add(conn);}@Overridepublic void clearWarnings() throws SQLException {conn.clearWarnings();}@Overridepublic void commit() throws SQLException {conn.commit();} //不需要增強的方法,調用原有對象的對應方法即可, @Overridepublic Array createArrayOf(String typeName, Object[] elements)throws SQLException {return conn.createArrayOf(typeName, elements);}//后面有很多方法,因為不需要增強的方法,調用原有對象的對應方法即可,這里略去   ………… }

解決方案二:適配器模式

?通過一個類去繼承一個接口或父類,對需要增強的方法進行改寫即可,適配器模式在監聽機制中出現比較多,由于父類中有很多的抽象方法,如果一一實現,比較麻煩,所以通常在API中會提供一個已經默認實現的類,我們只需去繼承這個類,然后對希望增強的方法進行復寫即可

?

適配器模式編寫步驟

1.編寫一個類,繼承默認適配器

2.定義一個引用變量,記住被增強對象

3.定義構造方法,傳入被增強的對象,并給第2部的變量賦值

4.對于要增強的方法,自己改寫

?

為Connection準備的適配器

?適配器本身也是一個包裝類,實現或者繼承一個類,但是什么都不做,所有的方法都調用原有對象的對應方法

?

public class ConnectionWrapper implements Connection{protected Connection conn;public ConnectionWrapper(Connection conn){this.conn = conn;}@Overridepublic void clearWarnings() throws SQLException {conn.clearWarnings();}@Overridepublic void close() throws SQLException {conn.close();}@Overridepublic void commit() throws SQLException {conn.commit();}@Overridepublic Array createArrayOf(String typeName, Object[] elements)throws SQLException {return null;}………… }

?

繼承適配器,對需要增強的方法復寫即可

public class MyConnection2 extends ConnectionWrapper {private LinkedList<Connection> pool;public MyConnection2(Connection conn, LinkedList<Connection> pool) {super(conn);this.pool = pool;} //將連接對象還回池中public void close() throws SQLException {pool.add(conn);} }

解決方案三:動態代理

使用動態代理,在獲取Connection的方法中使用代理,所以在獲取Connection的時候,就是一個代理的Connection,該代理的Connection對象,會對調用方法進行判斷,如果是close方法,就對返回值進行改寫(這里是將Connection對象放回連接池中),否則就按照原來方法去執行

關于更多動態代理的知識,筆者在Java基礎里面有詳細地提到,其機制,實現等,想深刻了解的親們可以查看:http://www.cnblogs.com/xushuai123/archive/2012/12/02/2978070.html

import java.io.PrintWriter; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.LinkedList; import java.util.ResourceBundle;import javax.sql.DataSource;//標準的數據源 public class ProxyDataSource implements DataSource{private static String className;// 驅動類名private static String url;// 連接串private static String user;private static String password;private static LinkedList<Connection> pool = new LinkedList<Connection>();static {try {ResourceBundle rb = ResourceBundle.getBundle("cn.itxushuai.util.dbinfo");className = rb.getString("className");url = rb.getString("url");user = rb.getString("user");password = rb.getString("password");Class.forName(className);// 初始化10個連接for (int i = 0; i < 10; i++) {Connection conn = DriverManager.getConnection(url, user,password);pool.add(conn);}} catch (Exception e) {throw new ExceptionInInitializerError("驅動加載失敗");}}@Overridepublic synchronized Connection getConnection() throws SQLException {if(pool.size()>0){System.out.println("池中的連接如下");int i=1;for(Connection conn : pool){System.out.println(conn+"----"+i++);}final Connection conn = pool.remove();Connection proxyConn = (Connection)Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method,Object[] args) throws Throwable {if("close".equals(method.getName())){ return pool.add(conn);}else{return method.invoke(conn, args);}}}); return proxyConn;}else{throw new RuntimeException("服務器忙");}}@Overridepublic Connection getConnection(String username, String password)throws SQLException {// TODO Auto-generated method stubreturn null;}@Overridepublic PrintWriter getLogWriter() throws SQLException {// TODO Auto-generated method stubreturn null;}@Overridepublic int getLoginTimeout() throws SQLException {// TODO Auto-generated method stubreturn 0;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {// TODO Auto-generated method stub }@Overridepublic void setLoginTimeout(int seconds) throws SQLException {// TODO Auto-generated method stub }@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {// TODO Auto-generated method stubreturn false;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {// TODO Auto-generated method stubreturn null;}}

?

?

轉載于:https://www.cnblogs.com/xushuai123/archive/2013/03/31/2992385.html

總結

以上是生活随笔為你收集整理的数据库 -- 由数据库连接池引出的三种设计模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。