JDBC原生寫法+原生連接池

(Notice:以下所有經(jīng)驗(yàn)也是我根據(jù)網(wǎng)上的經(jīng)驗(yàn)整理的爷恳,如有侵權(quán)可以聯(lián)系我刪除尔邓,Wx:IT_Ezra,QQ 654303408兰珍。 有問題討論也可聯(lián)系我侍郭,QQ同上。)

(PS:為什么要用到JDBC原生態(tài)寫法掠河。首先亮元,對(duì)于大多數(shù)項(xiàng)目來說,現(xiàn)在基本上都是用市面上封裝好的開源框架唠摹,但是我們?nèi)匀恍枰私釰DBC爆捞,因?yàn)镴DBC是基礎(chǔ),所有的開源框架都是基于最原始的JDBC封裝加強(qiáng)的勾拉,而對(duì)于JDBC的使用場(chǎng)景煮甥,還是有一席之地的,因?yàn)榫€程池的存在藕赞。首先我們知道成肘,事務(wù)是具有離子型,所以要保持線程安全斧蜕,而通過線程池加上原生態(tài)的JDBC可以保證一定程度上的并發(fā)以及線程安全双霍。)

項(xiàng)目結(jié)構(gòu)圖

  • 項(xiàng)目結(jié)構(gòu)可多可少,有的人高耦合批销,但是就項(xiàng)目來說洒闸,低耦合才是一個(gè)好的項(xiàng)目的標(biāo)準(zhǔn)。
項(xiàng)目結(jié)構(gòu)圖

新建一個(gè)properites文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbctest
username=root
password=root
jdbcPoolInitSize=10

  • 以. properites結(jié)尾的均芽,通常是配置文件顷蟀,然后在系統(tǒng)中,通過加載讀取數(shù)據(jù)骡技。這里是jdbc.properites鸣个,以后還會(huì)有其他的配置文件羞反。

新建jdbc連接池工具類JdbcPool

>package com.test.util;
import java.io.InputStream;
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.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.Properties;
import java.util.logging.Logger;
import javax.sql.DataSource;
//原生的jdbc連接池,加載jdbc.properties文件
public class JdbcPool implements DataSource {
    /**
     *  * @Field: listConnections 使用LinkedList集合來存放數(shù)據(jù)庫鏈接囤萤,
     * 由于要頻繁讀寫List集合昼窗,所以這里使用LinkedList存儲(chǔ)數(shù)據(jù)庫連接比較合適  
     */
    private static LinkedList<Connection> listConnections = new LinkedList<Connection>();
    private static Connection conn;
 // 在靜態(tài)代碼塊中加載src/jdbc.properties數(shù)據(jù)庫配置文件
    static {
        InputStream in = JdbcPool.class.getResourceAsStream("/jdbc.properties");
        Properties prop = new Properties();
        try {
            prop.load(in);
            String driver = prop.getProperty("driver");
            String url = prop.getProperty("url");
            String username = prop.getProperty("username");
            String password = prop.getProperty("password");
// 數(shù)據(jù)庫連接池的初始化連接數(shù)大小
            int jdbcPoolInitSize = Integer.parseInt(prop.getProperty("jdbcPoolInitSize"));
// 加載數(shù)據(jù)庫驅(qū)動(dòng)
            Class.forName(driver);
            for (int i = 0; i < jdbcPoolInitSize; i++) {
                conn = DriverManager.getConnection(url, username, password);
//                 System.out.println("獲取到了連接" + conn);
// 將獲取到的數(shù)據(jù)庫連接加入到listConnections集合中,listConnections集合此時(shí)就是一個(gè)存放了數(shù)據(jù)庫連接的連接池
                listConnections.add(conn);
            }
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }
    /*
     *  * 獲取數(shù)據(jù)庫連接
     */
    @Override
    public Connection getConnection() throws SQLException {
//如果集合中沒有數(shù)據(jù)庫連接對(duì)象了涛舍,且創(chuàng)建的數(shù)據(jù)庫連接對(duì)象沒有達(dá)到最大連接數(shù)量澄惊,可以再創(chuàng)建一組數(shù)據(jù)庫連接對(duì)象以備使用
         if(linkedlist1.size()==0&&max<=5){
             try {
               Class.forName("com.mysql.jdbc.Driver");
            } catch (ClassNotFoundException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
             for(int i=0;i<jdbcConnectionInitSize;i++){
                Connection conn=DriverManager.getConnection(url, username, password);
                System.out.println("獲取到了鏈接" + conn);
                //將創(chuàng)建好的數(shù)據(jù)庫連接對(duì)象添加到Linkedlist集合中
                linkedlist1.add(conn);
                 }
              max++;
             }
         if(linkedlist1.size()>0){
             //從linkedlist集合中取出一個(gè)數(shù)據(jù)庫鏈接對(duì)象Connection使用
             Connection conn1=linkedlist1.removeFirst();
             System.out.println("linkedlist1數(shù)據(jù)庫連接池大小是" + linkedlist1.size());
             /*返回一個(gè)Connection對(duì)象,并且設(shè)置Connection對(duì)象方法調(diào)用的限制富雅,
            *當(dāng)調(diào)用connection類對(duì)象的close()方法時(shí)會(huì)將Connection對(duì)象重新收集放入linkedlist集合中掸驱。
            */
           return (Connection) Proxy.newProxyInstance(conn1.getClass().getClassLoader(),//這里換成JdbcConnectionsPool.class.getClassLoader();也行
                 conn1.getClass().getInterfaces(), new InvocationHandler() {
                                     
                   @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                       if(!method.getName().equalsIgnoreCase("close")){
                           return method.invoke(conn1, args);
                       }else{
                        linkedlist1.add(conn1);
                          System.out.println(conn1+"對(duì)象被釋放,重新放回linkedlist集合中没佑!");
                        System.out.println("此時(shí)Linkedlist集合中有"+linkedlist1.size()+"個(gè)數(shù)據(jù)庫連接對(duì)象毕贼!");
                             return null;
                           }                    
                         }
                   });
       }else{
          System.out.println("連接數(shù)據(jù)庫失敗蛤奢!");
         }
        return null;
    }
    //省略@Override方法
    @Override
    public PrintWriter getLogWriter() throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {
        // TODO Auto-generated method stub
    }
    @Override
    public void setLoginTimeout(int seconds) throws SQLException {
        // TODO Auto-generated method stub
    }
    @Override
    public int getLoginTimeout() throws SQLException {
        // TODO Auto-generated method stub
        return 0;
    }
    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        // TODO Auto-generated method stub
        return false;
    }
    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }
}

新建JDBCUtil工具類

package com.test.util;
 
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCUtil {
    private static JdbcPool pool = new JdbcPool();
    /**
     *  * 獲取資源
     */
    public static Connection getConnection() throws SQLException {
        return pool.getConnection();
    }
    /**
     *  * 關(guān)閉資源
     *  * @param resultSet 查詢返回的結(jié)果集鬼癣,沒有為空
     *  * @param statement   
     *  * @param connection
     */
    public static void close(ResultSet resultSet, Statement statement,
            Connection connection) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
            resultSet = null;
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
#數(shù)據(jù)庫操作
package com.test.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.test.util.JDBCUtil;

public class JDBCDao {
    /**
     *  * 增加,刪除啤贩,修改  
     */
    public static void insertOrDeleteOrUpdate(String sql) {
        try {
            Connection connection = JDBCUtil.getConnection();
            PreparedStatement pst = connection.prepareStatement(sql);
            int execute = pst.executeUpdate();
            System.out.println("執(zhí)行語句:" + sql + "," + execute + "行數(shù)據(jù)受影響");
            JDBCUtil.close(null, pst, connection);
        } catch (SQLException e) {
            System.out.println("異常提醒:" + e);
        }
    }
    /**
     *  * 查詢待秃,返回結(jié)果集  
     */
    public static List<Map<String, Object>> select(String sql) {
        List<Map<String, Object>> returnResultToList = null;
        try {
            Connection connection = JDBCUtil.getConnection();
            PreparedStatement pst = connection.prepareStatement(sql);
            ResultSet resultSet = pst.executeQuery();
//  returnResultToList = returnResultToList(resultSet);
            JDBCUtil.close(resultSet, pst, connection);
        } catch (SQLException e) {
            System.out.println("異常提醒:" + e);
        }
        return returnResultToList;
    }
    /**
     *  * 數(shù)據(jù)返回集合  * @param resultSet  * @return  * @throws SQLException  
     */
    public static List<Map<String, Object>> returnResultToList(ResultSet resultSet) {
        List<Map<String, Object>> values = null;
        try {
            // 鍵: 存放列的別名, 值: 存放列的值.
            values = new ArrayList<>();
            // 存放字段名
            List<String> columnName = new ArrayList<>();
            ResultSetMetaData rsmd = resultSet.getMetaData();
            for (int i = 0; i < rsmd.getColumnCount(); i++) {
                // 字段名
                columnName.add(rsmd.getColumnLabel(i + 1));
            }
            System.out.println("表字段為:");
            System.out.println(columnName);
            System.out.println("表數(shù)據(jù)為:");
            Map<String, Object> map = null;
            // 處理 ResultSet, 使用 while 循環(huán)
            while (resultSet.next()) {
                map = new HashMap<>();
                for (String column : columnName) {
                    Object value = resultSet.getObject(column);
                    map.put(column, value);
                    System.out.print(value + "\t");
                }
                // 把一條記錄的 Map 對(duì)象放入準(zhǔn)備的 List 中
                values.add(map);
                System.out.println();
            }
        } catch (SQLException e) {
            System.out.println("異常提醒:" + e);
        }
        return values;
    }
}
  • tips:使用連接池的時(shí)候,痹屹,使用代理章郁,代理Connection的close()方法可能會(huì)出現(xiàn)如下錯(cuò)誤

java.lang.ClassCastException: com.sun.proxy.$Proxy4 cannot be cast to java.sql.Connection

  • 解決方法:Connection.getInterfaces() 與數(shù)據(jù)庫驅(qū)動(dòng)有關(guān),數(shù)據(jù)庫驅(qū)動(dòng)不同 Connection.getInterfaces() 的結(jié)果也就不同志衍,Connection.getInterfaces() 返回的是 Class[ ] 數(shù)組驱犹,此數(shù)組的第一個(gè)元素必須是Connection才能把創(chuàng)建的代理類轉(zhuǎn)為Connection對(duì)象,否則就會(huì)報(bào):Java.lang.ClassCastException足画。因?yàn)镃onnection本身就是一個(gè)接口雄驹,它的字節(jié)碼符合第二個(gè)參數(shù)要求,把conn.getClass().getInterfaces();改成new Class[]{Connection.class}就可以了淹辞。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末医舆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子象缀,更是在濱河造成了極大的恐慌蔬将,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件央星,死亡現(xiàn)場(chǎng)離奇詭異霞怀,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)莉给,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門毙石,熙熙樓的掌柜王于貴愁眉苦臉地迎上來廉沮,“玉大人,你說我怎么就攤上這事徐矩≈褪保” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵滤灯,是天一觀的道長(zhǎng)坪稽。 經(jīng)常有香客問我,道長(zhǎng)鳞骤,這世上最難降的妖魔是什么窒百? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮豫尽,結(jié)果婚禮上篙梢,老公的妹妹穿的比我還像新娘。我一直安慰自己拂募,他們只是感情好庭猩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布窟她。 她就那樣靜靜地躺著陈症,像睡著了一般。 火紅的嫁衣襯著肌膚如雪震糖。 梳的紋絲不亂的頭發(fā)上录肯,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音吊说,去河邊找鬼论咏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛颁井,可吹牛的內(nèi)容都是我干的厅贪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼雅宾,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼养涮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起眉抬,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤贯吓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蜀变,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悄谐,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年库北,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了爬舰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片们陆。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖洼专,靈堂內(nèi)的尸體忽然破棺而出棒掠,到底是詐尸還是另有隱情,我是刑警寧澤屁商,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布烟很,位于F島的核電站,受9級(jí)特大地震影響蜡镶,放射性物質(zhì)發(fā)生泄漏雾袱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一官还、第九天 我趴在偏房一處隱蔽的房頂上張望芹橡。 院中可真熱鬧,春花似錦望伦、人聲如沸林说。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腿箩。三九已至,卻和暖如春劣摇,著一層夾襖步出監(jiān)牢的瞬間珠移,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工末融, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钧惧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓勾习,卻偏偏與公主長(zhǎng)得像浓瞪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子巧婶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容