@Transactional只能被應用到public方法上, 對於其它非public的方法,如果標記了@Transactional也不會報錯,但方法沒有事務功能.
Spring使用聲明式交易處理,預設情況下,如果被註解的資料庫操作方法中發生了unchecked異常,所有的資料庫操作將rollback;如果發生的異常是checked異常,預設情況下資料庫操作還是會提交的。
這種預設的行為是可以改變的。
使用@Transactional註解的noRollbackFor和rollbackFor屬性
如:@Transactional(rollbackFor=Exception.class)可以使checked異常發生時,資料庫操作也rollback、@Transactional(noRollbackFor=RuntimeException.class)可以使unchecked異常發生時也提交資料庫操作。
也可以使用noRollbackForClassName、rollbackForClassName屬性來指定一個異常類名的String數組來改變預設的行為。
讀取資料庫中的資料時是不需要交易管理的,這種情況下可以使用事務的傳播行為來告訴Spring不需要開啟事務,
如:@Transactional(propagation = Propagation.NOT_SUPPORTED)。
事務的傳播行為有:
1. REQUIRED:表示業務方法需要在一個事務中處理,如果業務方法執行時已經在一個事務中,則加入該事務,否則重新開啟一個事務。這也是預設的事務傳播行為;
2. NOT_SUPPORTED:聲明業務方法不需要事務,如果業務方法執行時已經在一個事務中,則事務被掛起,等方法執行完畢後,事務恢複進行;
3. REQUIRES_NEW:表明業務方法需要在一個單獨的事務中進行,如果業務方法進行時已經在一個事務中,則這個事務被掛起,並重新開啟一個事務來執行這個業務方法,業務方法執行完畢後,原來的事務恢複進行;
4. MANDATORY:該屬性指定業務方法只能在一個已經存在的事務中進行,業務方法不能發起自己的事務;如果業務方法沒有在一個既有的事務中進行,容器將拋出異常;
5. SUPPORTS:該屬性指定,如果業務方法在一個既有的事務中進行,則加入該事務;否則,業務方法將在一個沒有事務的環境下進行;
6. NEVER:指定業務方法不可以在事務中進行,如果業務方法執行時已經在一個事務中,容器將拋出異常;
7. NESTED:該屬性指定,如果業務方法在一個既有的事務中執行,則該業務方法將在一個嵌套的事務中進行;否則,按照REQUEIRED來對待。它使用一個單獨的事務,這個事務可以有多個rollback點,內部事務的rollback對外部事務沒有影響,但外部事務的rollback會導致內部事務的rollback。這個行為只對DataSourceTransactionManager有效。
事務的隔離等級
使用@Transactional的Isolation屬性可以指定事務的隔離等級。但事務的隔離等級是由底層的資料庫實現的,並不是由Spring來實現。
1. READ_UNCOMMITTED:會出現髒讀、不可重複讀取和幻讀問題;
2. READ_COMMITTED:會出現不可重複讀取和幻讀問題;
3. REPEATABLE_READ:會出現幻讀問題;
4. SERIALIZABLE:序列化,不會出現上面的問題。
一般的資料庫預設提供的是READ_COMMITTED隔離等級,如sqlserver2000;Mysql預設提供的是REPEATABLE_READ。
@Transactional 的所有可選屬性如下:
屬性 類型 預設值 說明
propagation Propagation枚舉 REQUIRED 事務傳播屬性
isolation isolation枚舉 DEFAULT 交易隔離等級
readOnly boolean false 是否唯讀
timeout int -1 逾時(秒)
rollbackFor Class[] {} 需要復原的異常類
rollbackForClassName String[] {} 需要復原的異常類名
noRollbackFor Class[] {} 不需要復原的異常類
noRollbackForClassName String[] {} 不需要復原的異常類名
//事務傳播屬性
@Transactional(propagation=Propagation.REQUIRED) //如果有事務,那麼加入事務,沒有的話建立一個(不寫的情況下)
@Transactional(propagation=Propagation.NOT_SUPPORTED) //容器不為這個方法開啟事務
@Transactional(propagation=Propagation.REQUIRES_NEW) //不管是否存在事務,都建立一個新的事務,原來的掛起,新的執行完畢,繼續執行老的事務
@Transactional(propagation=Propagation.MANDATORY) //必須在一個已有的事務中執行,否則拋出異常
@Transactional(propagation=Propagation.NEVER) //必須在一個沒有的事務中執行,否則拋出異常(與Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS) //如果其他bean調用這個方法,在其他bean中聲明事務,那就用事務.如果其他bean沒有聲明事務,那就不用事務.
@Transactional(propagation=Propagation.NESTED)
@Transactional (propagation = Propagation.REQUIRED,readOnly=true) //readOnly=true唯讀,不能更新,刪除
@Transactional (propagation = Propagation.REQUIRED,timeout=30)//設定逾時時間
@Transactional (propagation = Propagation.REQUIRED,isolation=Isolation.DEFAULT)//設定資料庫隔離等級
用 spring 交易管理員,由spring來負責資料庫的開啟,提交,復原.
預設遇到運行期例外(throw new RuntimeException("注釋");)會復原,即遇到不受檢查(unchecked)的例外時復原;
而遇到需要捕獲的例外(throw new Exception("注釋");)不會復原,即遇到受檢查的例外(就是非運行時拋出的異常,編譯器會檢查到的異常叫受檢查例外或說受檢查異常)時,需我們指定方式來讓交易回復 ,如下:
@Transactional(rollbackFor=Exception.class) //指定復原,遇到異常Exception時復原
public void methodName() {
throw new Exception("注釋");
}
@Transactional(noRollbackFor=Exception.class)//指定不復原,遇到運行期例外(throw new RuntimeException("注釋");)會復原
public ItimDaoImpl getItemDaoImpl() {
throw new RuntimeException("注釋");
}