| [JDBC Advanced Topics]異常處理、元數(shù)據(jù)以及事務(wù)。 1、異常 Exception java.sql.SQLException 對(duì)底層數(shù)據(jù)庫異常的封裝,它是一個(gè)已檢查異常。所以應(yīng)用程序必須對(duì)它做處理。 .getErrorCode(); 獲取特定于數(shù)據(jù)庫供應(yīng)商的錯(cuò)誤代碼。 java.sql.SQLWaring extends SQLExecption 提供關(guān)于數(shù)據(jù)庫訪問警告信息的異常。 例: 1   try  { 2  //此處省略 3   } catch(SQLException e)  { 4   while(e != null)  { 5  e.printStackTrace(); 6  e = e.getNextExecption(); 7  } 8  } 2、元數(shù)據(jù):用來描述其他數(shù)據(jù)的數(shù)據(jù) JDBC中的元數(shù)據(jù): ResultSetMetaDate: 結(jié)果集元數(shù)據(jù),它用來描述結(jié)果集本身。 ResultSet.getMetaDate(); 獲取當(dāng)前結(jié)果集的元數(shù)據(jù)。 DatabaseMetaDate: 數(shù)據(jù)庫元數(shù)據(jù),用來描述數(shù)據(jù)庫本身。 Connection.getMetaDate(); 獲取當(dāng)前數(shù)據(jù)庫的元數(shù)據(jù)。 例:  //利用元數(shù)據(jù)打印出結(jié)果集   public void executeSQL(String sqlcommand)  {  Connection con = null;  Statement stm = null;  ResultSet rs = null;   try  {  //這里的ConnectionFactory是寫的一個(gè)連接工廠,這里就不做介紹了。  con = ConnectionFactory.getConnection();  stm = con.createStatement();  boolean flag = stm.execute(sqlcommand);   if(flag)  {  rs = stm.getResultSet();  ResultSetMetaDate rsmd = rs.getMetaDate();  int columns = rsmd.getColumnCount();   for(int i=1;i<columns;i++)  {  String columnName = rsmd.getColumnLabel(i);  System.out.print(columnName+"\t");  }  System.out.println();   while(rs.next())  {   for(int i=1;i<columns;i++)  {  Object content = rs.getObject(i);  System.out.print(content+"\t");  }  System.out.print();   }else  {  int results = stm.getUpdateCount();  System.out.println(results+" resultes was update  ");  }  }   }catch(SQLExecption e)  {  //此處省略若干  }  } 3、DML的操作 [JDBC的事務(wù)] 以事務(wù)為單位 JDBC事務(wù): 定義:一組相關(guān)的操作,不可分割,一起成功,一起失敗。 相關(guān)操作: Connection: commit(); JDBC事務(wù)提交 rollback(); JDBC事務(wù)回滾 JDBC的事務(wù)默認(rèn)情況下是自動(dòng)提交的,每執(zhí)行一次SQL命令,就提交commit一次。[AutoCommit] 如: 轉(zhuǎn)帳(){ ... update t_account1 set balance = balance-100; update t_account2 set balance = balance+100; ... } 如何讓以上兩句SQL語句,一起執(zhí)行,一起失敗。所以就需要把他們放在一個(gè)事務(wù)中。 如: 轉(zhuǎn)帳(){ ... con.setAutoCommit(false);//關(guān)閉自動(dòng)事務(wù)提交 update t_account1 set balance = balance-100; update t_account2 set balance = balance+100; 如果以上兩句都成功,則: con.commit();//提交事務(wù) 如果以上任意一個(gè)失敗,則: con.rollback();//事務(wù)回滾 } 獲取主鍵方式(主鍵值生成策略) 主鍵值不應(yīng)該由UI界面來收集,而應(yīng)該由應(yīng)用程序自動(dòng)生成,常見的策略如下: a. max(id)方法 select max(id) from table_name; 此方法當(dāng)有多線程并發(fā)時(shí),就會(huì)產(chǎn)生問題。 b. sequence 序列 select sequence.nextval from dual; 此方法只適用支持序列的數(shù)據(jù)庫產(chǎn)品,所以不是很通用。 c. 維護(hù)單行單列得表 1  create table id_table(next_id number not null); 2  insert into id_table next_id values(1); 3  commit; 4  --使用以下SQL自動(dòng)維護(hù) 5  select next_id from id_table for update; 6  update id_table set next_id = next_id+1; 7  commit; 并發(fā)控制:多個(gè)事務(wù)同時(shí)操作同一個(gè)對(duì)象 有三種并發(fā)情況,如下: 1、臟讀 Dirty reads 讀到其他事務(wù)沒有提交的數(shù)據(jù)。注:Oracle不支持 2、不可重復(fù)讀 Repeatable reads 同一個(gè)事務(wù)在兩個(gè)不同的時(shí)刻讀取不同結(jié)果 如: 1解決重復(fù)讀問題:  T1:select score from t_score where id= 48; 2  T2:update t_score set score = score+10 where id = 48; 3  T1:select score from t_score where id= 48; 讓T1在查詢語句中加入for update子句,從而把選定的記錄加上排他鎖;那么T1事務(wù)完成之前,其他事務(wù)是不能來獲取鎖資源的。 3、幻影讀 Phanton reads 記錄數(shù)量變化,而不是行記錄的列值 1解決幻影讀問題:  T1:elcet count(*) from t_class where classname = '******'; 2  T2:nsert into t_class values(   .); 3  commit(); 4  T1:selcet count(*) from t_class where classname = '******'; 5  鎖表:lock table table_name in mode; 事務(wù)隔離級(jí)別:SUN在JDBC規(guī)范中制定了5個(gè)級(jí)別,分別用來滿足不同的并發(fā)性。 Connection: 0 .TRANSACTION_NONE 無 1 .TRANSACTION_READ_UNCOMMITED 可以臟讀 2 .TRANSACTION_READ_COMMITED 不可以臟讀 4 .TRANSACTION_REPEATABLE 不可以重復(fù)讀 8 .TRANSACTION_SERIALIZABLE 為每個(gè)事務(wù)都開辟一個(gè)空間 事務(wù)的隔離界別設(shè)置得越高,則并發(fā)性能越差 注:不同數(shù)據(jù)庫,對(duì)隔離級(jí)別的支持也是不一樣的。 如:oracle就不支持0和1兩種。 如何設(shè)置隔離級(jí)別? 如:con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITED); 這個(gè)也是默認(rèn)事務(wù)隔離級(jí)別。 | 
|  |