異常的分類:
① 異常的繼承結構:基類為Throwable,Error和Exception繼承Throwable,RuntimeException和IOException等繼承Exception,具體的RuntimeException繼承RuntimeException。
② Error和RuntimeException及其子類成為未檢查異常(unchecked),其它異常成為已檢查異常(checked)。
runtimeException就是運行時異常,它是Java編譯器事先不可預見的異常。
而其他的Exception異常大致的說是檢查時異常,就是說幫你檢查出來了可能出現的異常。此時你程序未執行,但是有可能拋出這個異常,所以提醒你記得捕獲。
Exception體系包括RuntimeException體系和其他非RuntimeException的體系 :
① RuntimeException:RuntimeException體系包括錯誤的類型轉換、數組越界訪問和試圖訪問空指針等等。處理RuntimeException的原則是:如果出現RuntimeException,那么一定是程序員的錯誤。例如,可以通過檢查數組下標和數組邊界來避免數組越界訪問異常。
②其他非RuntimeException(IOException等等):這類異常一般是外部錯誤,例如試圖從文件尾后讀取數據等,這並不是程序本身的錯誤,而是在應用環境中出現的外部錯誤。
1、為什么要聲明方法拋出異常?
方法是否拋出異常與方法返回值的類型一樣重要。假設方法拋出異常卻沒有聲明該方法將拋出異常,那么客戶程序員可以調用這個方法而且不用編寫處理異常的代碼。那么,一旦出現異常,那么這個異常就沒有合適的異常控制器來解決。
2、為什么拋出的異常一定是已檢查異常?
RuntimeException與Error可以在任何代碼中產生,它們不需要由程序員顯示的拋出,一旦出現錯誤,那么相應的異常會被自動拋出。而已檢查異常是由程序員拋出的,這分為兩種情況:客戶程序員調用會拋出異常的庫函數(庫函數的異常由庫程序員拋出);客戶程序員自己使用throw語句拋出異常。遇到Error,程序員一般是無能為力的;遇到RuntimeException,那么一定是程序存在邏輯錯誤,要對程序進行修改(相當於調試的一種方法);只有已檢查異常才是程序員所關心的,程序應該且僅應該拋出或處理已檢查異常。
注意:覆蓋父類某方法的子類方法不能拋出比父類方法更多的異常,所以,有時設計父類的方法時會聲明拋出異常,但實際的實現方法的代碼卻並不拋出異常,這樣做的目的就是為了方便子類方法覆蓋父類方法時可以拋出異常。
使用spring難免要用到spring的事務管理,要用事務管理又會很自然的選擇聲明式的事務管理,在spring的文檔中說道,spring聲明式事務管理默認對非檢查型異常和運行時異常進行事務回滾,而對檢查型異常則不進行回滾操作。
那么什么是檢查型異常什么又是非檢查型異常呢?
最簡單的判斷點有兩個:
1.繼承自runtimeexception或error的是非檢查型異常,而繼承自exception的則是檢查型異常(當然,runtimeexception本身也是exception的子類)。
2.對非檢查型類異常可以不用捕獲,而檢查型異常則必須用try語句塊進行處理或者把異常交給上級方法處理總之就是必須寫代碼處理它。所以必須在service捕獲異常,然后再次拋出,這樣事務方才起效。
- import javax.annotation.Resource;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Propagation;
- import org.springframework.transaction.annotation.Transactional;
- import com.dao.CompanyDao;
- import com.entry.TCompanyInfo;
- @Service("companyService")
- @Transactional
- public class CompanyService {
- @Resource(name="companyDao")
- private CompanyDao companyDao;
- public void setCompanyDao(CompanyDao companyDao) {
- this.companyDao = companyDao;
- }
- public CompanyDao getCompanyDao() {
- return companyDao;
- }
- @Transactional(readOnly=false,propagation=Propagation.REQUIRED,rollbackFor={Exception.class})//readOnly=true慎用(不可寫事務)
- public void test(TCompanyInfo tc){
- try{
- companyDao.createObj(tc);
- String s=null;
- s.length(); //假設會拋出NullPointerException,就會執行catch里的,如果不在catch里throw一個
- RuntimeException子類,依然不會rollback
- }
- catch(Exception e){
- //throw new Exception("runtimeException");
- System.out.println("exception");
- throw new NumberFormatException("format exception"); //重拋一個Exception,才能rollback
- }
- }
- }
在Spring里,同樣只會rollback unchecked exception(RuntimeExcption及子類),而checked exception(Exception及子類)是不會rollback的,除非你特別聲明。
- @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW,rollbackFor = {MyException1.class,MyException2.class})
因此所有在service層方法中用throws定義的Exception,都必須在事務定義中進行rollback設定。(請勿善忘)
所有在service層方法中被catch處理了的異常,又希望容器輔助rollback的話,必須重拋一個預定義的RuntimeException的子類。(請勿回望)
參考文章:http://zw7534313.iteye.com/blog/691398