Java數據庫鏈接——JDBC調用存儲過程,事務管理和高級應用

1、JDBC經常使用的API深刻詳解及存儲過程的調用

相關連接:Jdbc調用存儲過程java

一、存儲過程(Stored Procedure)的介紹

  咱們經常使用的操做數據庫語言SQL語句在執行的時候須要先編譯,而後執行,而存儲過程(Stored Procedure)是在大型數據庫系統中,一組爲了完成特定功能的SQL 語句集,存儲在數據庫中,通過第一次編譯後再次調用不須要再次編譯,用戶經過指定存儲過程的名字並給出參數(若是該存儲過程帶有參數)來執行它。存儲過程是數據庫中的一個重要對象,任何一個設計良好的數據庫應用程序都應該用到存儲過程。mysql

  一個存儲過程是一個可編程的函數,它在數據庫中建立並保存。它能夠有SQL語句和一些特殊的控制結構組成。當但願在不一樣的應用程序或平臺上執行相同的函數,或者封裝特定功能時,存儲過程是很是有用的。數據庫中的存儲過程能夠看作是對編程中面向對象方法的模擬。它容許控制數據的訪問方式。sql

存儲過程一般有如下優勢:數據庫

(1).存儲過程加強了SQL語言的功能和靈活性。存儲過程能夠用流控制語句編寫,有很強的靈活性,能夠完成複雜的判斷和較複雜的運算。apache

(2).存儲過程容許標準組件是編程。存儲過程被建立後,能夠在程序中被屢次調用,而沒必要從新編寫該存儲過程的SQL語句。並且數據庫專業人員能夠隨時對存儲過程進行修改,對應用程序源代碼毫無影響。編程

(3).存儲過程能實現較快的執行速度。若是某一操做包含大量的Transaction-SQL代碼或分別被屢次執行,那麼存儲過程要比批處理的執行速度快不少。由於存儲過程是預編譯的。在首次運行一個存儲過程時查詢,優化器對其進行分析優化,而且給出最終被存儲在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。tomcat

(4).存儲過程能過減小網絡流量。針對同一個數據庫對象的操做(如查詢、修改),若是這一操做所涉及的Transaction-SQL語句被組織程存儲過程,那麼當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,從而大大增長了網絡流量並下降了網絡負載。安全

(5).存儲過程可被做爲一種安全機制來充分利用。系統管理員經過執行某一存儲過程的權限進行限制,可以實現對相應的數據的訪問權限的限制,避免了非受權用戶對數據的訪問,保證了數據的安全。服務器

簡單來講它的好處主要是:網絡

1.因爲數據庫執行動做時,是先編譯後執行的。然而存儲過程是一個編譯過的代碼塊,因此執行效率要比T-SQL語句高。
2.一個存儲過程在程序在網絡中交互時能夠替代大堆的T-SQL語句,因此也能下降網絡的通訊量,提升通訊速率。
3.經過存儲過程可以使沒有權限的用戶在控制之下間接地存取數據庫,從而確保數據的安全。

二、JDBC調用無參存儲過程

 在數據庫新建存儲過程:

注意:建立的存儲過程名稱不要加「()」,否則在調用存儲過程時會提示以下錯誤:

代碼示例:ProduceDao.java

 1 package com.study.dao;
 2 
 3 import java.sql.CallableStatement;
 4 import java.sql.Connection;
 5 import java.sql.ResultSet;
 6 import java.sql.SQLException;
 7 
 8 import com.study.db.DBUtil;
 9 
10 /**
11  * @Description: 存儲過程
12  * @author: Qian
13  * @date: 2016-4-3 下午4:15:24
14  */
15 public class ProduceDao {
16     public static void select_nofilter() throws SQLException{
17         //1.得到鏈接
18         Connection conn = DBUtil.getConnection();
19         //2.得到CallableStatement
20         CallableStatement cs = conn.prepareCall("call sp_select_nofilter()");
21         //3.執行存儲過程
22         cs.execute();
23         //4.處理返回的結果:結果集,出參
24         ResultSet rs = cs.getResultSet();
25         /*遍歷結果集*/
26         while(rs.next()){
27             System.out.println(rs.getString("user_name")+":"+rs.getString("email"));
28         }
29     }
30 }

JDBCTestProduce.java

 1 package com.study.test;
 2 
 3 import java.sql.SQLException;
 4 
 5 import com.study.dao.ProduceDao;
 6 
 7 /**
 8  * @Description: 測試存儲過程
 9  * @author: Qian
10  * @date: 2016-4-3 下午4:24:10
11  */
12 public class JDBCTestProduce {
13     public static void main(String[] args) throws SQLException {
14         ProduceDao dao=new ProduceDao();
15         dao.select_nofilter();
16     }
17 }

運行結果:

三、JDBC調用含輸入參數存儲過程

調用存儲過程:傳個空字符

傳個「小」

 1 //JDBC 調用帶輸入參數的存儲過程
 2     public static List<Goddess> select_filter(String sp_name) throws SQLException{
 3         List<Goddess> result=new ArrayList<Goddess>();
 4         //1.得到鏈接
 5         Connection conn = DBUtil.getConnection();
 6         //2.得到CallableStatement
 7         CallableStatement cs = conn.prepareCall("call sp_select_filter(?)");
 8         cs.setString(1, sp_name);
 9         //3.執行存儲過程
10         cs.execute();
11         //4.處理返回的結果:結果集,出參
12         ResultSet rs = cs.getResultSet();
13         Goddess g=null;
14         while(rs.next()){//若是對象中有數據,就會循環打印出來
15             g=new Goddess();
16             g.setId(rs.getInt("id"));
17             g.setUserName(rs.getString("user_name"));
18             g.setAge(rs.getInt("age"));
19             result.add(g);
20         }
21         return result;
22     }

測試:

 1 public class JDBCTestProduce {
 2     public static void main(String[] args) throws SQLException {
 3         ProduceDao dao=new ProduceDao();
 4 //        dao.select_nofilter();
 5         String sp_name="";
 6         List<Goddess> res=null;
 7         res=dao.select_filter(sp_name);
 8         for (int i = 0; i < res.size(); i++) {
 9             System.out.println(res.get(i).getId()+":"+res.get(i).getUserName()+":"+res.get(i).getAge());
10             
11         }
12     }
13 }

四、JDBC調用含輸出參數存儲過程

 

調用存儲過程:

 1 //JDBC 調用含輸出參數存儲過程
 2         public static Integer select_count() throws SQLException{
 3             Integer count=0;
 4             //1.得到鏈接
 5             Connection conn = DBUtil.getConnection();
 6             //2.得到CallableStatement,prepareStatement,statement
 7             CallableStatement cs = conn.prepareCall("call sp_select_count(?)");
 8             cs.registerOutParameter(1, Types.INTEGER);//註冊輸出參數,第二個參數是告訴JDBC,輸出參數的類型
 9             //3.執行存儲過程
10             cs.execute();
11             //4.處理返回的結果:這個不是結果集,是出參
12             count=cs.getInt(1);
13             return count;
14         }

測試:

 1 package com.study.test;
 2 
 3 import java.sql.SQLException;
 4 import java.util.List;
 5 
 6 import com.study.dao.ProduceDao;
 7 import com.study.model.Goddess;
 8 
 9 /**
10  * @Description: 測試存儲過程
11  * @author: Qian
12  * @date: 2016-4-3 下午4:24:10
13  */
14 public class JDBCTestProduce {
15     public static void main(String[] args) throws SQLException {
16 //        ProduceDao dao=new ProduceDao();
17 //        dao.select_nofilter();
18         /*String sp_name="";
19         List<Goddess> res=null;
20         res=dao.select_filter(sp_name);
21         for (int i = 0; i < res.size(); i++) {
22             System.out.println(res.get(i).getId()+":"+res.get(i).getUserName()+":"+res.get(i).getAge());
23             
24         }*/
25         String sp_name="小";
26         List<Goddess> res=null;
27         Integer count=0;
28         //帶輸入參數的存儲過程
29         /*res=select_filter(sp_name);
30         showResult(res);*/
31         count=select_count();
32         System.out.println(count);
33     }
34     
35     public static List<Goddess> select_filter(String sp_name) throws SQLException{
36         ProduceDao dao=new ProduceDao();
37         return dao.select_filter(sp_name);
38     }
39     public static Integer select_count() throws SQLException{
40         ProduceDao dao=new ProduceDao();
41         return dao.select_count();
42     }
43     
44     public static void showResult(List<Goddess> result){
45         for (int i = 0; i < result.size(); i++) {
46             System.out.println(result.get(i).getId()+":"+result.get(i).getUserName()+":"+result.get(i).getAge());
47             
48         }
49     }
50 }

2、JDBC的事務管理

事務的概念

事務(transaction)是做爲單個邏輯工做單元執行的一系列操做。這些操做做爲一個總體一塊兒向系統提交,要麼都執行、要麼都不執行

事務的特色

  一、原子性(Atomicity)

    事務是一個完整的操做。不能對它進行再分割,是最小的一個單元。

  二、一致性(Consistency)

    當事務完成時,數據必須處於一致狀態。

(例如銀行轉帳,張三要給李四轉100元。則第一步張三的帳戶須要減去100元,第二步李四的帳戶須要加上100元。這是兩個操做,可是應該在一個事務裏面。若是沒有在一個事務裏面,張三減去100,李四並無增長100,那這樣數據就出現了不一致性,張三的錢跑哪去了呢 )

  三、隔離性(Isolation)

    對數據進行修改的全部併發事務是彼此隔離的。

(好比業務A:張三減100,李四加100;同時業務B也是張三減100,李四加100進行操做。業務A和B是同時的,這時候就出現了併發,這個時候是怎麼變化的呢?當業務員A進行操做的時候,業務員B就要等待……就是同一時間對數據庫的操做要保持一個事務的鎖定。也就是說我在作的時候,別人是不能作的。我作完了以後別人才能作,彼此之間是隔離的)

  四、永久性(Durability)

    事務完成後,它對數據庫的修改被永久保持。

一、JDBC實現事務管理

①咱們經過提交commit()或是回退rollback()來管理事務的操做。

  當事務完成的時候,咱們經過commit將事務提交到數據庫之中,而後數據庫會變成持久化的,咱們的數據就會永久保存了。

  若是採用rollback的話,事務回滾,好比說咱們插入的數據、更新的數據都會變成原來沒有更新、沒有插入時的樣子。

②事務操做默認是自動提交

  當咱們調用完insert語句,不用調用commit語句,本身就提交了。

③能夠調用setAutoCommit(false) 來禁止自動提交。

二、經過代碼實現事物的管理

  首先咱們要注意,在JDBC中,事務操做默認是自動提交。也就是說,一條對數據庫的更新表達式表明一項事務操做。操做成功後,系統將自動調用commit()來提交,不然將調用rollback()來回退。

  其次,在JDBC中,能夠經過調用setAutoCommit(false)來禁止自動提交。以後就能夠把多個數據庫操做的表達式做爲一個事務,在操做完成 後調用commit()來進行總體提交。假若其中一個表達式操做失敗,都不會執行到commit(),而且將產生響應的異常。此時就能夠在異常捕獲時調用 rollback()進行回退。這樣作能夠保持屢次更新操做後,相關數據的一致性。

try {  
        conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://localhost:1433;User=JavaDB;Password=javadb;DatabaseName=northwind);  
        //點禁止自動提交,設置回退  
        conn.setAutoCommit(false);   
        stmt = conn.createStatement();  
        //數據庫更新操做1  
        stmt.executeUpdate(「update firsttable Set Name='testTransaction' Where ID = 1」);   
        //數據庫更新操做2  
        stmt.executeUpdate(「insert into firsttable ID = 12,Name = 'testTransaction2'」);   
        //事務提交  
        conn.commit();  
    }catch(Exception ex) {   
        ex.printStackTrace();  
        try {  
            //操做不成功則回退  
            conn.rollback();  
        }catch(Exception e){  
            e.printStackTrace();  
        }  
    }

 

 這樣上面這段程序的執行,或者兩個操做都成功,或者兩個都不成功,讀者能夠本身修改第二個操做,使其失敗,以此來檢查事務處理的效果。

咱們在前面還提到了JDBC對事務所支持的隔離級別,下面將更詳細進行討論。

JDBC API支持事務對數據庫的加鎖,而且提供了5種操做支持,2種加鎖密度。

5種加鎖支持爲:

static int TRANSACTION_NONE = 0;

static int TRANSACTION_READ_UNCOMMITTED = 1;

static int TRANSACTION_READ_COMMITTED = 2;

static int TRANSACTION_REPEATABLE_READ = 4;

static int TRANSACTION_SERIALIZABLE = 8;

具體的說明見表4-2。

2種加鎖密度:

最後一項爲表加鎖,其他3~4項爲行加鎖。

「髒」數據讀寫(Dirty Reads):當一個事務修改了某一數據行的值而未提交時,另外一事務讀取了此行值。假若前一事務發生了回退,則後一事務將獲得一個無效的值(「髒」數據)。

重複讀寫(Repeatable Reads):當一個事務在讀取某一數據行時,另外一事務同時在修改此數據行。則前一事務在重複讀取此行時將獲得一個不一致的值。

錯 誤(映像)讀寫(Phantom Reads):當一個事務在某一表中進行數據查詢時,另外一事務剛好插入了知足了查詢條件的數據行。則前一事務在重複讀取知足條件的值時,將獲得一個額外的 「影像」值。JDBC根據數據庫提供的默認值來設置事務支持及其加鎖,固然,也能夠手工設置:

setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED);

能夠查看數據庫的當前設置:

getTransactionIsolation ()

須要注意的是,在進行手動設置時,數據庫及其驅動程序必須得支持相應的事務操做操做才行。

上 述設置隨着值的增長,其事務的獨立性增長,更能有效地防止事務操做之間的衝突,同時也增長了加鎖的開銷,下降了用戶之間訪問數據庫的併發性,程序的運行效 率也會隨之下降。所以得平衡程序運行效率和數據一致性之間的衝突。通常來講,對於只涉及到數據庫的查詢操做時,能夠採用 TRANSACTION_READ_UNCOMMITTED方式;對於數據查詢遠多於更新的操做,能夠採用 TRANSACTION_READ_COMMITTED方式;對於更新操做較多的,能夠採用TRANSACTION_REPEATABLE_READ;在 數據一致性要求更高的場合再考慮最後一項,因爲涉及到表加鎖,所以會對程序運行效率產生較大的影響。

另外,在Oracle中數據庫驅動對事務處理的默認值是TRANSACTION_NONE,即不支持事務操做,因此須要在程序中手動進行設置。總之,JDBC提供的對數據庫事務操做的支持是比較完整的,經過事務操做能夠提升程序的運行效率,保持數據的一致性。

3、數據庫鏈接池(dbcp、c3p0)

鏈接池產生的背景

  數據庫鏈接是一種重要資源。大部分很重要的數據都存在數據庫裏,那麼在產生鏈接池以前,咱們鏈接數據庫的方式:直連。(獲取鏈接->使用->關閉鏈接)程序小的話能夠採用這種方式,可是若是程序很大,好比大型網站,它可能每分鐘或者每秒變化量在100萬次,就是說同時訪問數據庫有100萬個用戶,這時候若是咱們不用鏈接池的話,咱們就須要建立100萬個鏈接這樣的話就會對數據庫形成很大的壓力,若是數據庫承受不了的話就崩潰了,服務器也崩潰了,網站就癱瘓了。

即:

①數據庫鏈接是一種重要資源;

②頻繁的鏈接數據庫會增長數據庫的壓力;

③爲解決以上問題出現鏈接池技術。

(池子裏保持必定數量的鏈接,當使用時就從池子中拿一個鏈接出來,當使用完鏈接後就把它釋放到池子裏。當你同時訪問數據庫人不少的時候,這個時候鏈接不夠用,就須要等待,減小數據庫的壓力)

經常使用的開源數據庫鏈接池:

  1. dbcp
  2. c3p0

一、dbcp使用步驟

  一、首先,導入相關jar包

  二、在項目根目錄增長配置文件:dbcp.properties

這個屬性文件的內容以下:

   三、配置並測試dbcp鏈接

DBCPUtil.java

  1 package com.study.db;
  2 
  3 import java.sql.Connection;
  4 import java.sql.SQLException;
  5 import java.util.Properties;
  6 
  7 import javax.sql.DataSource;
  8 
  9 import org.apache.commons.dbcp2.BasicDataSource;
 10 import org.apache.commons.dbcp2.BasicDataSourceFactory;
 11 /**
 12  * @Description: DBCP配置類
 13  * @author: Qian
 14  * @date: 2016-4-4 上午8:57:49
 15  */
 16 public class DBCPUtil {
 17     /**數據源,static*/
 18     private static DataSource DS;
 19     private static final String configFile="/dbcp.properties";//配置文件
 20     
 21     /**從數據源得到一個鏈接*/
 22     /**
 23      * @Description: TODO
 24      * @param @return 設定文件
 25      * @return Connection 返回類型
 26      * @author Qian
 27      * @date 2016-4-4 上午9:11:07
 28      */
 29     public Connection getConn(){
 30         Connection conn=null;
 31         if(DS !=null){
 32             try {
 33                 conn=DS.getConnection();//從數據源裏面拿到鏈接
 34             } catch (Exception e) {
 35                 e.printStackTrace(System.err);
 36             }
 37             try {
 38                 conn.setAutoCommit(false);//關閉鏈接的自動提交
 39             } catch (SQLException e) {
 40                 e.printStackTrace();
 41             }
 42             return conn;
 43         }
 44         return conn;
 45     }
 46     
 47     /**默認的構造函數*/
 48     /**
 49      * @Description: TODO
 50      * @param 
 51      * @return 
 52      * @author Qian
 53      * @date 2016-4-4 上午9:17:02
 54      */
 55     public DBCPUtil(){
 56         initDbcp();
 57     }
 58     
 59     private static void initDbcp(){
 60         Properties pops=new Properties();
 61         try {
 62             pops.load(Object.class.getResourceAsStream(configFile));//讀取配置文件
 63             DS=BasicDataSourceFactory.createDataSource(pops);//經過BasicDataSourceFactory提供的工廠類,拿到DataSource數據源
 64         } catch (Exception e) {
 65             e.printStackTrace();
 66         }
 67     }
 68     /*構造函數,初始化了DS,指定數據庫*/
 69     public DBCPUtil(String connectURI){
 70         initDS(connectURI);
 71     }
 72     
 73     /*構造函數,初始化了DS,指定全部參數*/
 74     public DBCPUtil(String connectURI,String userName,String passWord,String driverClass,int initialSize,int maxIdle,int minIdle,int maxWait){
 75         initDS(connectURI,userName,passWord,driverClass,initialSize,maxIdle,minIdle,maxWait);
 76     }
 77     
 78     /**
 79      * @Description: 建立數據源,除了數據外,都是用硬編碼默認參數
 80      * @param @param connectURI 數據庫
 81      * @return
 82      * @author Qian
 83      * @date 2016-4-4 上午9:47:18
 84      */
 85     public static void initDS(String connectURI){
 86         initDS(connectURI, "root", "root",     "com.mysql.jdbc.Driver", 10, 20, 5, 1000);
 87     }
 88     
 89     /**
 90      * @Description: 
 91      * @param @param connectURI 數據庫
 92      * @param @param userName 用戶名
 93      * @param @param passWord 密碼
 94      * @param @param driverClass 驅動
 95      * @param @param initialSize 初始化鏈接數
 96      * @param @param maxIdle 最大鏈接數
 97      * @param @param minIdle 最小鏈接數
 98      * @param @param maxWait 超時等待時間(得到鏈接的最大等待毫秒數)
 99      * @return
100      * @author Qian
101      * @date 2016-4-4 上午9:45:18
102      */
103     public static void initDS(String connectURI,String userName,String passWord,String driverClass,
104             int initialSize,int maxIdle,int minIdle,int maxWait){
105         BasicDataSource ds=new BasicDataSource();//new 一個數據源
106         ds.setDriverClassName(driverClass);
107         ds.setUsername(userName);
108         ds.setPassword(passWord);
109         ds.setUrl(connectURI);
110         ds.setInitialSize(initialSize);//初始的鏈接數
111         ds.setMaxIdle(maxIdle);
112         ds.setMaxWaitMillis(maxWait);
113         ds.setMinIdle(minIdle);
114         DS = ds;
115     }
116 }

GoddessDao.java

 1 //查詢單個女神(根據id去查詢)
 2     public Goddess get(Integer id) throws SQLException{
 3         Goddess g=null;
 4         Connection con=DBUtil.getConnection();//首先拿到數據庫的鏈接
 5         String sql="" + 
 6                 "select * from imooc_goddess "+
 7                 "where id=?";//參數用?表示,至關於佔位符;用mysql的日期函數current_date()來獲取當前日期
 8         //預編譯sql語句
 9         PreparedStatement psmt = con.prepareStatement(sql);
10         //先對應SQL語句,給SQL語句傳遞參數
11         psmt.setInt(1, id);
12         //執行SQL語句
13         /*psmt.execute();*///execute()方法是執行更改數據庫操做(包括新增、修改、刪除);executeQuery()是執行查詢操做
14         ResultSet rs = psmt.executeQuery();//返回一個結果集
15         //遍歷結果集
16         while(rs.next()){
17             g=new Goddess();
18             g.setId(rs.getInt("id"));
19             g.setUserName(rs.getString("user_name"));
20             g.setAge(rs.getInt("age"));
21             g.setSex(rs.getInt("sex"));
22             //rs.getDate("birthday")得到的是java.sql.Date類型。注意:java.sql.Date類型是java.util.Date類型的子集,因此這裏不須要進行轉換了。
23             g.setBirthday(rs.getDate("birthday"));
24             g.setEmail(rs.getString("email"));
25             g.setMobile(rs.getString("mobile"));
26             g.setCreateUser(rs.getString("create_user"));
27             g.setCreateDate(rs.getDate("create_date"));
28             g.setUpdateUser(rs.getString("update_user"));
29             g.setUpdateDate(rs.getDate("update_date"));
30             g.setIsDel(rs.getInt("isdel"));
31         }
32         return g;
33     }
34     
35        //查詢單個女神(根據id去查詢)
36         public Goddess getByDbcp(Integer id) throws SQLException{
37             DBCPUtil db=new DBCPUtil();
38             Goddess g=null;
39             Connection con=db.getConn();//首先拿到數據庫的鏈接
40             String sql="" + 
41                     "select * from imooc_goddess "+
42                     "where id=?";//參數用?表示,至關於佔位符;用mysql的日期函數current_date()來獲取當前日期
43             //預編譯sql語句
44             PreparedStatement psmt = con.prepareStatement(sql);
45             //先對應SQL語句,給SQL語句傳遞參數
46             psmt.setInt(1, id);
47             //執行SQL語句
48             /*psmt.execute();*///execute()方法是執行更改數據庫操做(包括新增、修改、刪除);executeQuery()是執行查詢操做
49             ResultSet rs = psmt.executeQuery();//返回一個結果集
50             //遍歷結果集
51             while(rs.next()){
52                 g=new Goddess();
53                 g.setId(rs.getInt("id"));
54                 g.setUserName(rs.getString("user_name"));
55                 g.setAge(rs.getInt("age"));
56                 g.setSex(rs.getInt("sex"));
57                 //rs.getDate("birthday")得到的是java.sql.Date類型。注意:java.sql.Date類型是java.util.Date類型的子集,因此這裏不須要進行轉換了。
58                 g.setBirthday(rs.getDate("birthday"));
59                 g.setEmail(rs.getString("email"));
60                 g.setMobile(rs.getString("mobile"));
61                 g.setCreateUser(rs.getString("create_user"));
62                 g.setCreateDate(rs.getDate("create_date"));
63                 g.setUpdateUser(rs.getString("update_user"));
64                 g.setUpdateDate(rs.getDate("update_date"));
65                 g.setIsDel(rs.getInt("isdel"));
66             }
67             return g;
68         }

測試:

 1 package com.study.test;
 2 
 3 import java.util.Date;
 4 
 5 import com.study.dao.GoddessDao;
 6 import com.study.model.Goddess;
 7 
 8 /**@Description: 測試用DBCP鏈接數據庫
 9  * @author: Qian
10  * @date: 2016-4-4 上午9:53:53
11  */
12 public class TestDbcp {
13 
14     /**@Description: TODO
15      * @param @param args
16      * @return
17      * @author Qian
18      * @throws Exception 
19      * @date 2016-4-4 上午9:53:53
20      */
21     public static void main(String[] args) throws Exception {
22         //1.經過普通方式操做數據庫
23         Date a=new Date();
24         get();
25         Date b=new Date();
26         System.out.println(b.getTime()-a.getTime());
27         
28         //2.經過DBCP鏈接池的方式操做數據庫
29         Date c=new Date();
30         get();
31         Date d=new Date();
32         System.out.println(d.getTime()-c.getTime());
33         
34         /**
35          * 經過運行,發現第二種方式明顯要比第一種用時少
36          */
37     }
38     
39     public static void get() throws Exception{
40         GoddessDao dao=new GoddessDao();
41         Goddess g=dao.get(1);
42         System.out.println(g.toString());
43     }
44     
45     public static void getByDbcp() throws Exception{
46         GoddessDao dao=new GoddessDao();
47         Goddess g=dao.getByDbcp(1);
48         System.out.println(g.toString());
49     }
50 }

二、c3p0使用步驟

   c3p0是一個開源的JDBC鏈接池,它實現了數據源和JNDI綁定,支持JDBC3和JDBC2的標準擴展。目前使用它的開源項目有Hibernate,Spring等。

默認狀況下(即沒有配置鏈接池的狀況下),Hibernate會採用內建的鏈接池。但這個鏈接池性能不佳,所以官方也只是建議僅在開發環境下使用。Hibernate支持第三方的鏈接池,官方推薦的鏈接池是C3P0,Proxool。

  一、導入相關jar包

注:在tomcat或者項目中引入最新版的C3P0的JAR包(我是用的是c3p0-0.9.2.1.jar)

若是啓動時報類沒有找到:Caused by: java.lang.NoClassDefFoundError: com/mchange/v2/ser/Indirector,

則須要加入mchange-commons-java-0.2.3.4.jar。

  二、在項目根目錄增長配置文件:c3p0.properties

1 c3p0.driverClass=com.mysql.jdbc.Driver
2 c3p0.jdbcUrl=jdbc:mysql://localhost:3306/demo_jdbc
3 c3p0.user=root
4 c3p0.password=root

  三、編寫類文件,建立鏈接池

C3P0Util.java

 1 package com.study.db;
 2 
 3 import java.sql.Connection;
 4 import java.sql.SQLException;
 5 
 6 import com.mchange.v2.c3p0.ComboPooledDataSource;
 7 
 8 /**@Description: c3p0數據源配置類
 9  * @author: Qian
10  * @date: 2016-4-4 上午10:40:01
11  */
12 public class C3P0Util {
13     //建立一個數據源
14     private static ComboPooledDataSource ds=new ComboPooledDataSource();
15     
16     public static Connection getConn(){
17         try {
18             return ds.getConnection();
19         } catch (SQLException e) {
20             throw new RuntimeException(e);
21         }
22     }
23 }

TestC3p0.java

 1 package com.study.test;
 2 
 3 import java.sql.Connection;
 4 import java.sql.SQLException;
 5 
 6 import com.study.db.C3P0Util;
 7 
 8 /**@Description: 測試C3P0
 9  * @author: Qian
10  * @date: 2016-4-4 上午10:43:11
11  */
12 public class TestC3p0 {
13 
14     /**@Description: TODO
15      * @param @param args
16      * @return
17      * @author Qian
18      * @throws SQLException 
19      * @date 2016-4-4 上午10:43:11
20      */
21     public static void main(String[] args) throws SQLException {
22         Connection con=C3P0Util.getConn();
23         System.out.println(con.getCatalog());
24 
25     }
26 
27 }

能夠仿照上面dbcp來測試c3p0鏈接池。

三、鏈接池總結

DBCP和C3P0的相同點:

DBCP和C3P0的不一樣點:

4、JDBC的替代產品(Hibernate、Mybatis)

上面介紹的都是手工的鏈接數據庫,寫SQL語句。這部分的替代產品會替代咱們的這些工做。

替代工具:

  • Commons-dbutils;
  • Hibernate;
  • Mybatis;

一、Commons-dbutils 

從字面意思能夠理解爲:通用的數據庫工具類。

Apache組織提供的一個開源JDBC工具類庫,對傳統操做數據庫的類進行二次封裝,能夠把結果集轉化成List。

特色:

 

核心接口:

示例

二、Hibernate簡介

  是一種Java語言下的對象關係映射解決方案。它是一種自由、開源的軟件。

優勢

缺點

若是對大量的數據進行頻繁的操做,性能效率比較低,不如直接使用JDBC。(由於Hibernate作了完整的封裝,因此效率可能會低。)

核心接口

示例:

*.hbm.xml

插入:

三、Mybatis簡介

   Mybatis是支持普通SQL查詢,存儲過程和高級映射的優秀持久層框架。

特色

示例

userMapper.xml示例

相關文章
相關標籤/搜索