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


一、JDBC常用的API深入詳解及存儲過程的調用

相關鏈接:Jdbc調用存儲過程

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

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

  一個存儲過程是一個可編程的函數,它在數據庫中創建並保存。它可以有SQL語句和一些特殊的控制結構組成。當希望在不同的應用程序或平台上執行相同的函數,或者封裝特定功能時,存儲過程是非常有用的。數據庫中的存儲過程可以看做是對編程中面向對象方法的模擬。它允許控制數據的訪問方式。

存儲過程通常有以下優點:

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

(2).存儲過程允許標准組件是編程。存儲過程被創建后,可以在程序中被多次調用,而不必重新編寫該存儲過程的SQL語句。而且數據庫專業人員可以隨時對存儲過程進行修改,對應用程序源代碼毫無影響。

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

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

(5).存儲過程可被作為一種安全機制來充分利用。系統管理員通過執行某一存儲過程的權限進行限制,能夠實現對相應的數據的訪問權限的限制,避免了非授權用戶對數據的訪問,保證了數據的安全。

簡單來說它的好處主要是:

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

2、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 }

運行結果:

3、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 }

4、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 }

二、JDBC的事務管理

事務的概念

事務(transaction)是作為單個邏輯工作單元執行的一系列操作。這些操作作為一個整體一起向系統提交,要么都執行、要么都不執行

事務的特點

  1、原子性(Atomicity)

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

  2、一致性(Consistency)

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

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

  3、隔離性(Isolation)

    對數據進行修改的所有並發事務是彼此隔離的。

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

  4、永久性(Durability)

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

1、JDBC實現事務管理

①我們通過提交commit()或是回退rollback()來管理事務的操作。

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

  如果采用rollback的話,事務回滾,比如說我們插入的數據、更新的數據都會變成原來沒有更新、沒有插入時的樣子。

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

  當我們調用完insert語句,不用調用commit語句,自己就提交了。

③可以調用setAutoCommit(false) 來禁止自動提交。

2、通過代碼實現事物的管理

  首先我們要注意,在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提供的對數據庫事務操作的支持是比較完整的,通過事務操作可以提高程序的運行效率,保持數據的一致性。

三、數據庫連接池(dbcp、c3p0)

連接池產生的背景

  數據庫連接是一種重要資源。大部分很重要的數據都存在數據庫里,那么在產生連接池之前,我們連接數據庫的方式:直連。(獲取連接->使用->關閉連接)程序小的話可以采用這種方式,但是如果程序很大,比如大型網站,它可能每分鍾或者每秒變化量在100萬次,就是說同時訪問數據庫有100萬個用戶,這時候如果我們不用連接池的話,我們就需要創建100萬個連接這樣的話就會對數據庫造成很大的壓力,如果數據庫承受不了的話就崩潰了,服務器也崩潰了,網站就癱瘓了。

即:

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

②頻繁的連接數據庫會增加數據庫的壓力;

③為解決以上問題出現連接池技術。

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

常用的開源數據庫連接池:

  1. dbcp
  2. c3p0

1、dbcp使用步驟

  1、首先,導入相關jar包

  2、在項目根目錄增加配置文件:dbcp.properties

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

   3、配置並測試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 }

2、c3p0使用步驟

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

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

  1、導入相關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。

  2、在項目根目錄增加配置文件: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

  3、編寫類文件,創建連接池

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連接池。

3、連接池總結

DBCP和C3P0的相同點:

DBCP和C3P0的不同點:

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

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

替代工具:

  • Commons-dbutils;
  • Hibernate;
  • Mybatis;

1、Commons-dbutils 

從字面意思可以理解為:通用的數據庫工具類。

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

特點:

 

核心接口:

示例

2、Hibernate簡介

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

優點

缺點

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

核心接口

示例:

*.hbm.xml

插入:

3、Mybatis簡介

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

特點

示例

userMapper.xml示例


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM