亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

JDBC之 連接池

2019-11-14 22:12:11
字體:
來源:轉載
供稿:網友
JDBC之 連接池JDBC之連接池

有這樣的一種現象:

java代碼操作數據庫,需要數據庫連接對象,一個用戶至少要用到一個連接?,F在假設有成千上百萬個用戶,就要創建十分巨大數量的連接對象,這會使數據庫承受極大的壓力,為了解決這種現象,一種技術出現了,這就是數據庫連接池。

什么是數據庫連接池(原理)

所謂數據庫連接池,可以看作:在用戶和數據庫之間創建一個”池”,這個池中有若干個連接對象,當用戶想要連接數據庫,就要先從連接池中獲取連接對象,然后操作數據庫。一旦連接池中的連接對象被拿光了,下一個想要操作數據庫的用戶必須等待,等待其他用戶釋放連接對象,把它放回連接池中,這時候等待的用戶才能獲取連接對象,從而操作數據庫。

數據庫連接池的屬性

連接對象初始的數量:initSize,一開始就創建若干個,當不夠時再添加

連接對象最大數量:maxSize,添加到最大值則不會再添加

下面我們用代碼下一個自己的連接池吧~

實現自己的連接池

看下面代碼和注釋吧~

public class MyPool {    //設置注冊屬性        PRivate String url = "jdbc:MySQL://localhost:3306/vmaxtam";    private String user = "root";    private String passWord = "root";    private static String driverClass="com.mysql.jdbc.Driver";    //設置連接池屬性    private int initSize = 5;    private int maxSize = 8;        //用LinkedList對象來保存connection對象    private LinkedList<Connection> connList = new LinkedList<Connection>();    //聲明一個臨時變量來計算連接對象的數量    private int currentsize = 0;        //聲明MyPool對象時自動注冊驅動    static{        try {            Class.forName(driverClass);        } catch (ClassNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }        //獲取連接的方法    private Connection getConnection()    {        Connection conn=null;        try {            conn = DriverManager.getConnection(url, user, password);        } catch (SQLException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        return conn;    }        //構造方法,初始化連接池,并往里面添加連接對象    public MyPool() {        for(int i = 0; i < initSize; i++)        {            Connection connection = this.getConnection();            connList.add(connection);            currentsize++;        }    }        //獲取連接池中的一個連接對象    public Connection getConnFromPool()    {        //當連接池還沒空        if(connList.size()>0){            Connection connection = connList.getFirst();            connList.removeFirst();            return connection;                }else if(connList.size()==0&&currentsize<8){            //連接池被拿空,且連接數沒有達到上限,創建新的連接            currentsize++;            connList.addLast(this.getConnection());                        Connection connection = connList.getFirst();            connList.removeFirst();            return connection;                }                throw new RuntimeException("連接數達到上限,請等待");    }        //把用完的連接放回連接池    public void releaseConnection(Connection connection)    {        connList.addLast(connection);    }    }

有了連接池后,我們寫一個測試來調用一下它吧~

    @Test    public void test1()    {                //獲得連接池        MyPool mypool = new MyPool();                /*從連接池中嘗試獲取9個連接        for(int i = 0 ; i<9; i++){            Connection conn = mypool.getConnFromPool();            System.out.println(conn.toString());        }*/                //獲取第五個連接后,釋放一下,然后再獲取        for(int i = 0 ; i<9; i++){            Connection conn = mypool.getConnFromPool();            if(i==5){                mypool.releaseConnection(conn);            }            System.out.println(conn.toString());        }    }

上面這樣就實現了自己的一個連接池,但是這個連接池依然存在著很多問題,一個較為明顯的問題就是:

如果一個用戶獲取了一個連接對象,然后調用了close()方法把它關閉了,沒有放回池中,這樣池中的這個對象就回不來了,造成最大連接上限為8個的連接池實際上只有7個連接在工作。

為了解決這個問題,我們需要對close()方法進行改造,是用戶調用close()方法時,實際上是把連接放回連接池中,而不是關閉它。

下面就為解決這個問題來分析下~

解決用戶調用close()方法關閉連接

方法一:使用靜態代理,寫一個myConnection()類來繼承connection的實現類,然后重寫它的close()方法.

方法二:使用動態代理,使用jdbc動態代理類:java.lang.reflect.Proxy類

動態代理類中有這樣一個方法可以創建它的實例

publicstaticObjectnewProxyInstance(ClassLoaderloader,

Class<?>[]interfaces,

InvocationHandlerh)

參數解析:

ClassLoader:類加載器,只要在同一個JDK中的類即可

Class<?>[]:要代理的接口的集合

InvocationHandler:代理接口的方法處理器

根據需要,我們要給MyPool中的Connection加一個動態代理,所以我們用的前兩個參數是:MyPool.Class.GetClassLoader與newClass<>{Connection}

最后還剩方法處理器,我們要修改Connection中的close方法,所以我們寫出一個這樣做的處理器即可,具體實現看下面代碼與注釋~

//獲取連接的方法    private Connection getConnection()    {                try {            //獲取一個連接            final Connection conn=DriverManager.getConnection(url, user, password);                        //把連接交給動態代理類轉換為代理的連接對象            Connection myconn = (Connection)Proxy.newProxyInstance(                    MyPool.class.getClassLoader(),                     new Class[] {Connection.class},                              //編寫一個方法處理器                    new InvocationHandler() {                                @Override                public Object invoke(Object proxy, Method method, Object[] args)                        throws Throwable {                    Object value = null;                                        //當遇到close方法,就會把對象放回連接池中,而不是關閉連接                    if(method.getName().equals("close"))                    {                        MyPool.connList.addLast(conn);                    }else                    {                        //其它方法不變                        value = method.invoke(conn, args);                    }                    return value;                }}            );                return myconn;        } catch (SQLException e) {            e.printStackTrace();            throw new RuntimeException(e);        }    }

以上就是利用動態代理的方式解決close的問題了~~但是,我們自己寫的連接池還有很多其他問題:

1)當前多個并發用戶同時獲取連接時,可能拿到同一個連接對象

2)當前用戶連接數超過了最大連接數時,不能直接拋出異常,應該有機制,控制用戶等待時間........

所以,這時候已經有人站出來,為我們寫好了一些功能相對完善的連接池,這些第三方的連接池得到了廣泛的用途,下面我們來介紹一下常見的連接池工具吧~

DBCP連接池

簡介:DBCP連接池是開源組織Apache軟件基金組織開發的連接池實現。

事實上,tomcat服務器默認就會使用這個連接池道具。

如何使用DBCP連接池呢,下面我來一一演示。

DBCP的使用步驟

步驟一:導包,使用第三方的道具,必須導入相應的jar包。

需要導入兩個jar包:commons-dbcp-1.4.jar包

commons-pool-1.5.6.jar包

步驟二:使用代碼~看看下面代碼的演示吧

public class DBCPTest {        private String url = "jdbc:mysql://localhost:3306/vmaxtam";        private String user = "root";        private String password = "root";        private String classDriver = "com.mysql.jdbc.Driver";            @Test        public void Test1()        {            //創建DBCP連接池對象            BasicDataSource ds = new BasicDataSource();                        //設置連接參數來進行連接            ds.setUrl(url);            ds.setUsername(user);            ds.setPassword(password);            ds.setDriverClassName(classDriver);                        //然后可以設置連接池的一些屬性啦~            ds.setInitialSize(5);            ds.setMaxActive(8);            ds.setMaxWait(3000);//設置最大的等待時長,毫秒為單位                        //從連接池中獲取對象            for(int i = 0 ; i<8;i++)            {                Connection conn = null;                try {                    conn = ds.getConnection();                    System.out.println(conn.hashCode());                                    } catch (SQLException e) {                    e.printStackTrace();                }                    }                    }}

為了測試效果,我們可以在循環中設置拿9個連接額,這樣在拿第九個連接時就會出現等待,等待到結束都沒有連接被釋放回連接池,就會出現報錯。

也可以把For循環改成下面那樣,測試close方法:

//從連接池中獲取對象            for(int i = 0 ; i<9;i++)            {                Connection conn = null;                try {                    conn = ds.getConnection();                    System.out.println(conn.hashCode());                    if(i==5)                    {                        conn.close();                    }                                    } catch (SQLException e) {                    e.printStackTrace();                }                    }

上面的代碼還是有點地方可以得到優化,例如可以通過配置文件來配置連接的參數,還有數據庫連接池的屬性參數。

配置文件:

url=jdbc:mysql://localhost:3306/vmaxtamusername=rootpassword=rootclassDriver=com.mysql.jdbc.Driver        initialSize=5maxActive=8maxWait=3000

用對象讀取配置文件:

@Test        public void Test2()        {                        try {                //創建配置對象                Properties properties = new Properties();                properties.load(DBCPTest.class.getResourceAsStream("/dbcp.properties"));                            //創建連接池對象,并且用連接池工廠來加載配置對象的信息                BasicDataSource ds = (BasicDataSource)BasicDataSourceFactory.createDataSource(properties);                //從連接池中獲取對象            for(int i = 0 ; i<8;i++)            {                Connection conn = null;                conn = ds.getConnection();                System.out.println(conn.hashCode());            }        }catch (Exception e2) {                e2.printStackTrace();            }                    }

以上就是DBCP連接池的基本用法了~下面我們來學習另一個連接池~

C3P0連接池

簡介:C3P0是一個開源組織的產品,開源框架的內部的連接池一般都使用C3P0來實現,例如:Hibernate

C3P0的使用步驟

步驟一:導包,使用第三方的工具必須導入jar包

要導入的包:c3p0-0.9.1.2.jar包

步驟二:看下面的代碼顯示怎么使用這個連接池吧~

@Test    public void Test1()    {        try {            //獲取連接池對象            ComboPooledDataSource cp = new ComboPooledDataSource();                        //設置連接參數            cp.setJdbcUrl(url);            cp.setUser(user);            cp.setPassword(password);            cp.setDriverClass(classDriver);                        //設置連接池的參數            cp.setInitialPoolSize(5);//初始數量            cp.setMaxPoolSize(8);//最大數量            cp.setCheckoutTimeout(3000);//最大等待時間                        for(int i = 0 ; i<8 ; i++)            {                Connection conn = cp.getConnection();                System.out.println(conn.hashCode());            }                } catch (Exception e) {            e.printStackTrace();        }        }

可以看出,C3P0的用法和DBCP的用法非常的相似~這里不做累贅。

特別的是C3PO讀取參數文件的方式,C3P0除了能像DBCP那樣讀取配置文件,它還提供了一種特殊的設置參數的方式,就是把參數數據寫在一個名叫c3p0-config.xml的XML文件中,在創建C3P0對象時會自動在classpath去尋找該文件來讀取~

也就是說:c3p0會到classpath下讀取名字為c3p0-config.xml文件

這份XML文件有特殊的要求,下面我們來寫一下這份XML文件:

<c3p0-config>    <!-- 默認配置 -->    <default-config>        <property name="jdbcUrl">jdbc:mysql://localhost:3306/vmaxtam</property>        <property name="user">root</property>        <property name="password">root</property>        <property name="driverClass">com.mysql.jdbc.Driver</property>                <property name="initialPoolSize">5</property>        <property name="maxPoolSize">8</property>        <property name="checkoutTimeout">3000</property>            </default-config>    <!-- mysql的連接配置 -->    <named-config name="mysql">        <property name="jdbcUrl">jdbc:mysql://localhost:3306/vmaxtam</property>        <property name="user">root</property>        <property name="password">root</property>        <property name="driverClass">com.mysql.jdbc.Driver</property>                <property name="initialPoolSize">5</property>        <property name="maxPoolSize">8</property>        <property name="checkoutTimeout">3000</property>        </named-config>        <!-- 使用 oracal就會用這份配置-->    <!-- 也可以寫其他數據庫的配置 --></c3p0-config>

寫完xml文件,現在我們就讀取它吧~

@Test    public void Test2()    {        try {            //獲取連接池對象,寫上參數就會去找xml文件找這個數據庫的配置來讀取,當無參時,就會使用默認設置。            ComboPooledDataSource cp = new ComboPooledDataSource("mysql");                        for(int i = 0 ; i<9 ; i++)            {                Connection conn = cp.getConnection();                System.out.println(conn.hashCode());                if(i==5)                {                    conn.close();                }            }                } catch (Exception e) {            e.printStackTrace();        }        }

使用這種讀取方法,顯得代碼十分簡便。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产一区二区久久精品| yw.139尤物在线精品视频| 久久久亚洲影院你懂的| 亚洲www永久成人夜色| 亚洲一级黄色av| 欧美精品久久久久久久| 日本成人免费在线| 国产性色av一区二区| 国产精品福利在线观看网址| 成人观看高清在线观看免费| 亚洲日本欧美日韩高观看| 69av成年福利视频| 欧美日韩亚洲激情| 国产精品福利网站| 国内揄拍国内精品| 在线播放日韩专区| 国产精品综合网站| 久久亚洲精品网站| 欧美亚洲伦理www| 亚洲欧美在线x视频| 国产一区二区三区毛片| 国产热re99久久6国产精品| 国产91ⅴ在线精品免费观看| 亚洲黄色av女优在线观看| 日韩美女免费线视频| 韩国福利视频一区| 国产精品va在线播放我和闺蜜| 欧美性在线视频| 97视频在线观看播放| 亚洲国产成人久久综合一区| 国产精品美女呻吟| 有码中文亚洲精品| 国产精品一区二区久久久久| 亚洲韩国欧洲国产日产av| 国产精品视频大全| 亚洲福利视频在线| 亚洲第一精品夜夜躁人人躁| 欧美激情在线视频二区| 欧美日韩免费观看中文| 国产视频福利一区| 尤物99国产成人精品视频| 亚洲精品按摩视频| 国产精品久久久久久av下载红粉| 国产精品自产拍高潮在线观看| 最新国产精品拍自在线播放| 欧美视频在线免费| 国产亚洲成av人片在线观看桃| 亚洲欧洲日本专区| 69久久夜色精品国产69乱青草| 亚洲综合av影视| 羞羞色国产精品| 北条麻妃一区二区在线观看| 国产精品久久久久久久久免费看| 日韩一区二区久久久| 亚洲精品成人久久久| 人人爽久久涩噜噜噜网站| 国产午夜精品全部视频在线播放| 97免费视频在线| 亚洲自拍av在线| 久久91精品国产91久久跳| 国产日韩欧美中文| 亚洲综合自拍一区| 欧美一级bbbbb性bbbb喷潮片| 久久躁狠狠躁夜夜爽| 亚洲精品日韩欧美| www.日韩视频| 欧美大片在线影院| 亚洲男人第一av网站| 亚洲精选中文字幕| 国产欧美精品久久久| 日本精品视频网站| 国产精品一香蕉国产线看观看| 91丨九色丨国产在线| 欧美精品999| 久久777国产线看观看精品| 国产精品jvid在线观看蜜臀| 国产精品揄拍一区二区| 日本高清+成人网在线观看| 国产精品久久久久99| 亚洲一区中文字幕| 日韩成人中文电影| 久久久视频在线| 国产精品男人爽免费视频1| 国产精品自产拍在线观看中文| 久久久久久久久久久免费精品| 91av福利视频| 欧美日本亚洲视频| 国产盗摄xxxx视频xxx69| 精品亚洲一区二区三区| 成人免费观看网址| 一夜七次郎国产精品亚洲| 欧美性在线视频| 中文字幕日韩有码| 亚洲直播在线一区| 欧美精品18videos性欧| 97涩涩爰在线观看亚洲| 亚洲天堂第二页| 中文字幕综合一区| 日韩极品精品视频免费观看| 国产一区视频在线播放| 91在线视频免费| 日韩免费在线视频| 亚洲国产精品99| 一区二区中文字幕| 精品偷拍一区二区三区在线看| 亚洲欧美另类在线观看| 538国产精品一区二区在线| 久久免费视频网| 日韩美女在线观看一区| 亚洲欧美成人一区二区在线电影| 视频在线一区二区| 亚洲免费一级电影| 国产精品视频公开费视频| 91精品久久久久| 欧美激情三级免费| 亚洲成人a**站| 成年无码av片在线| 66m—66摸成人免费视频| 亚洲成年人影院在线| 亚洲精品自在久久| 欧美国产日韩视频| 国产性猛交xxxx免费看久久| 欧美性猛交99久久久久99按摩| 亚洲成人黄色网址| 欧美激情va永久在线播放| 91免费国产视频| 亚洲精品欧美一区二区三区| 久久久久久久国产精品| 日韩欧美在线网址| 久久久精品国产| 最新国产成人av网站网址麻豆| 亚洲资源在线看| 亚洲精品欧美一区二区三区| 欧美精品一区二区免费| 日韩欧美有码在线| 国产精品久久久久久久天堂| 亚洲品质视频自拍网| 久久精品最新地址| 国内精品免费午夜毛片| 91久久精品日日躁夜夜躁国产| 欧美在线视频在线播放完整版免费观看| 日韩网站免费观看| 欧美日韩国产成人在线观看| 精品国偷自产在线视频| 国产精品自产拍在线观| 午夜精品久久久久久99热软件| 欧美日韩国产二区| 欧洲精品毛片网站| 日韩成人在线视频| 国产精品美女免费视频| 亚洲女人被黑人巨大进入al| 精品福利免费观看| 国产精品国内视频| 国产精品成人免费视频| 亚洲午夜国产成人av电影男同| 91极品女神在线| 亚洲人成网7777777国产| 精品无人区太爽高潮在线播放| 欧美成人免费小视频| 国产成人精品久久二区二区| 欧美另类精品xxxx孕妇| 日韩性生活视频| 久久久中文字幕| 国产福利视频一区二区|