程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Java——JDBC小結(5),javajdbc小結

Java——JDBC小結(5),javajdbc小結

編輯:JAVA綜合教程

Java——JDBC小結(5),javajdbc小結


1.事物

關於事物的概念及原理有好多好多,但我的理解就是一句話,要保持一個整體性,就是一個事,要分成幾個步驟去完成,但是只有這幾個步驟都做完了才是一個完整的事。這裡面最簡單的示例就是模擬銀行的取款與存款了,我直接給出這個示例代碼然後加以分析

 1     @Test
 2     public void test2(){
 3         String payId="00001";
 4         String recId="00002";
 5         double mny=1000;
 6         Connection conn=null;
 7         try {
 8             conn=DBUtil.getConnection();
 9             String sql="select *from accounts_jiawen "
10                     + "where id=?";
11             PreparedStatement ps=conn.prepareStatement(sql);
12             ps.setString(1, recId);
13             ResultSet rs=ps.executeQuery();
14             if(!rs.next()){
15                 System.out.println("收款帳號不存在");
16                 throw new SQLException("收款帳號不存在");
17             }            
18             //記錄收款方的余額
19             double recMoney=rs.getDouble("money");
20             
21             //設置手動管理事務
22             conn.setAutoCommit(false);
23             
24             //2.驗證付款方余額夠不夠
25             sql="select * from accounts_jiawen "
26                     + "where id=?";
27             ps=conn.prepareStatement(sql);
28             ps.setString(1, payId);
29             rs=ps.executeQuery();
30             rs.next();
31             double payMoney=rs.getDouble("money");
32             if(payMoney<mny){
33                 System.out.println("余額不足");
34                 throw new SQLException("余額不足");
35             }
36             
37         
38             
39             //3.付款方余額減少n元
40             sql="update accounts_jiawen set "
41                     + "money=? where id=?";
42             ps=conn.prepareStatement(sql);
43             ps.setDouble(1, payMoney-mny);
44             ps.setString(2, payId);
45             ps.executeQuery();
46             
47             //假設此處有一個錯誤
48 //            Integer.valueOf("abc");
49             //4.收款方加n元
50             sql="update accounts_jiawen set "
51                     + "money=? where id=?";
52             ps=conn.prepareStatement(sql);
53             ps.setDouble(1, recMoney+mny);
54             ps.setString(2, recId);
55             ps.executeQuery();
56             //當轉賬流程正常結束時統一提交事物
57             conn.commit();
58         } catch (Exception e) {
59             //當轉賬過程發生異常時回滾事務
60             try {
61                 conn.rollback();
62             } catch (SQLException e1) {
63                 // TODO Auto-generated catch block
64                 e1.printStackTrace();
65                 throw new RuntimeException("回滾");
66             }
67             e.printStackTrace();
68             throw new RuntimeException("wrong",e);
69         }finally{
70             DBUtil.close(conn);
71         }
72     }

 

首先,我們模擬兩個銀行的賬號,一個給另一個匯款,首先我們要先查詢一下收款人的信息,這和符合世紀邏輯,因為我們要知道收款人是否存在,同樣是做一個select查詢語句,方法依然使用的是前述的ParperdStatement,設置占位符的方法,判斷收款人是否存在,並記錄下收款方的現在余額,以便在收到錢後做一個累加。

然後重點來了,在第22行,這就是手動管理一個事物,將自動管理事物關閉,這樣以上的代碼就不是意見完整的事,否則他就是完整的一件事,而不會等待下面的過程,但實際上收款與匯款整體才能算上一件事,因為這涉及到兩個人的賬戶金額變動問題,你不能只考慮其中一個人的金額變化,而將它設置為false以後上面的過程就會一起等待下面的過程。第二部是驗證付款方的余額,判斷是否夠轉。後面的過程就是收付雙方金額的變動,如果你不把事物設置為手動的話,在第四步上面模擬一個代碼打斷一下下面代碼的執行,那麼後面的金額將發生錯誤。這裡面還要說明的是conn.commit()是統一提交事務,而conn.rollback()為回滾

2.批處理

見名知意,就是集中到一起發送一組SQL,好處也就是效率更高,降低了數據庫和程序之間的網絡調用,直接給出示例代碼:

    @Test
    public void test3(){
        Connection conn=null;
        try {
            conn=DBUtil.getConnection();
            conn.setAutoCommit(false);
            
            //批量發送數據的前提是他們的SQL一樣
            String sql="insert into emp_jiawenzhe values("
                    + " emp_jiawenzhe_w.nextval,?,?,?,?,?,?,?)";
            PreparedStatement ps =conn.prepareStatement(sql);
            for(int i=1;i<=108;i++){
                ps.setString(1, "好漢"+i);
                ps.setString(2, "打劫");
                ps.setInt(3, 0);
                ps.setDate(4, null);
                ps.setDouble(5, 1000.0);
                ps.setDouble(6, 8000.0);
                ps.setInt(7, 3);
                //將本條數據存到ps內
                ps.addBatch();
                //每30次批量發送一次數據
                if(i%30==0){
                    ps.executeBatch();
                    //清除緩存的數據
                    ps.clearBatch();
                }
            }
            //余下的數據單獨發送一次
            ps.executeBatch();
            
            conn.commit();
        } catch (SQLException e) {
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
            throw new RuntimeException("批量添加員工失敗",e);
        }finally{
            DBUtil.close(conn);
        }
        
        
    }

這是一個批量插入員工的示例,首先要說明的是,批量發送SQL,前提是他們的SQL要一致,就是干的都是同樣的一種事,在開始進行批處理之前,先要把事物的設置設置為手動提交,下一步就是建立SQL的變參數模型,比如說這裡面我建立的是一個插入的模型,下面的for循環完全是為了省事,做出了插入108條數據的寫法,當然你也可以逐一寫

下面我將說明一下addBatch()這個方法,我們在寫了108條數據並不是直接就寫到了數據庫中,他同樣是要調用ParperdStatement的發送方法,但這就不是excuteQuery,寫出來的東西要先放到緩存中,然後從緩存中拿到一部分數據發送數據庫,再將發送完了的SQL清除緩存,下面做的是每30條發送一次的代碼,調用excuteBatch發送,然後調用clearBatch清除緩存,當然最後剩下的要再一次調用excuteBatch一次性發送走,最後不要忘記提交,因為之前已經設置成了手動提交。

 3.返回自動主鍵

首先對於這塊我認為不太好理解,用起來似乎也沒有上面那麼簡單,接下來同樣是引用一個示例加以說明:

這個示例是這個樣子的,首先要有兩張表,一張是部門表,一張是員工表,這兩個表是關聯的,即主表部門表的主鍵deptno在從表的列中也有出現,並成為從表的外鍵,當對主表進行插入的時候,能將從表的信息一並插入

 1 @Test
 2     public void test4(){
 3         //假設要添加的部門數據如下
 4         String dname ="財務部";
 5         String loc="北京";
 6         //假設要添加員工的數據如下
 7         String ename="張三";
 8         String job="經理";
 9         int mgr=0;
10         double sal=8000.0;
11         double comm=2000.0;
12         
13         String ename2="李四";
14         String job2="經理";
15         int mgr2=0;
16         double sal2=5000.0;
17         double comm2=500.0;
18         
19         Connection conn=null;
20         try {
21             conn=DBUtil.getConnection();
22             conn.setAutoCommit(false);
23             //先添加部門
24             String sql ="insert into depts_jiawen "
25                     + " values(depts_seq_jiawen.nextval,?,?) " ;
26             //參數二是一個數組存的是希望被ps記住的字段名字
27             PreparedStatement ps=conn.prepareStatement(sql,new String[]{"deptno"});
28             ps.setString(1, dname);
29             ps.setString(2, loc);
30             ps.executeUpdate();
31             
32             //從ps中獲取它之前記錄的字段值
33             //返回的結果集中只有一種數據
34             //存的就是記錄那些字段的值
35             ResultSet rs=ps.getGeneratedKeys();
36             rs.next();
37             int deptno=rs.getInt(1);
38             
39             //再添加員工
40             sql="insert into emp_jiawenzhe values( "
41                     + "depts_seq_jiawen.nextval,?,?,?,?,?,?,?) ";
42             ps=conn.prepareStatement(sql);
43             ps.setString(1, ename);
44             ps.setString(2, job);
45             ps.setInt(3, mgr);
46             ps.setDate(4, null);
47             ps.setDouble(5, sal);
48             ps.setDouble(6, comm);
49             ps.setInt(7, deptno);
50             ps.executeUpdate();
51             
52             ps=conn.prepareStatement(sql);
53             ps.setString(1, ename2);
54             ps.setString(2, job2);
55             ps.setInt(3, mgr2);
56             ps.setDate(4, null);
57             ps.setDouble(5, sal2);
58             ps.setDouble(6, comm2);
59             ps.setInt(7, deptno);
60             ps.executeUpdate();
61             
62             conn.commit();
63             
64         } catch (SQLException e) {
65             try {
66                 conn.rollback();
67             } catch (SQLException e1) {
68                 // TODO Auto-generated catch block
69                 e1.printStackTrace();
70             }
71             e.printStackTrace();
72             throw new RuntimeException("wrong",e);
73         }finally{
74             DBUtil.close(conn);
75         }
76     }

這裡面可以看到ParperdStatement中傳入了兩個參數,第一個和之前一樣,是要執行的SQL,而第二個參數是一個字符串數組,他是希望被記住的字段名字,我的理解就是那個外鍵字段放到裡面,為了後面取到這個外鍵的值傳入到從表中進行更新,然後調用了getGeneratedKeys()獲得了這些主鍵的結果集,再用int deptno=rs.getInt(1);得到對應字段的值,對於這塊我實在不能明朗的解釋清楚,目前我也只能說先這麼記住吧,而後面的插入從表就是一個批處理操作,與前述相同。

4.分頁

分頁就是對於一個更龐大的數據表當我們不希望看到整表時,可以分成幾段呈現,這個內容就是一個固定的模式,有固定的分頁公式,一目了然,用的時候直接拿過來使用就好了

示例代碼:

 1     @Test
 2     public void test5(){
 3         int size=10;
 4         int page=2;
 5         
 6         Connection conn=null;
 7         try {
 8             conn=DBUtil.getConnection();
 9             String sql="select * from( "
10                     + "select e.*,rownum r from ( "
11                     + "select * from emp_jiawenzhe "
12                     + "order by empno "
13                     + ") e "
14                     + ") where r between ? and ?";
15             PreparedStatement ps=conn.prepareStatement(sql);
16             ps.setInt(1, (page-1)*size+1);
17             ps.setInt(2, size*page);
18             ResultSet rs=ps.executeQuery();
19             while (rs.next()) {
20                 System.out.println(rs.getInt("empno")+","+rs.getString("ename"));
21                 
22             }
23         } catch (SQLException e) {
24         
25             e.printStackTrace();
26             throw new RuntimeException("wrong",e);
27         }finally{
28             DBUtil.close(conn);
29         }
30     }

page和size分別是分幾頁,每頁有幾個,分頁的SQL寫法是數據庫內容,我將在數據庫基本SQL使用中提到,這裡面暫時先這麼寫著,後面的內容也就很清楚了!

未完待續!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved