一、事務有四個特性:ACID
- 原子性(Atomicity):事務是一個原子操作,由一系列動作組成翎朱。事務的原子性確保動作要么全部完成, 要么完全不起作用。
- 一致性(Consistency):一旦事務完成(不管成功還是失敗),系統(tǒng)必須確保它所建模的業(yè)務處于一致的狀 態(tài),而不會是部分完成部分失敗尺铣。在現(xiàn)實中的數(shù)據不應該被破壞拴曲。
- 隔離性(Isolation):可能有許多事務會同時處理相同的數(shù)據,因此每個事務都應該與其他事務隔離開來, 防止數(shù)據損壞。
- 持久性(Durability):一旦事務完成,無論發(fā)生什么系統(tǒng)錯誤,它的結果都不應該受到影響,這樣就能從 任何系統(tǒng)崩潰中恢復過來凛忿。通常情況下,事務的結果被寫到持久化存儲器中澈灼。
二、傳播行為
當事務方法被另一個事務方法調用時,必須指定事務應該如何傳播店溢。例如:方法可能繼續(xù)在現(xiàn)有事務中運
行,也可能開啟一個新事務,并在自己的事務中運行叁熔。
Spring 定義了七種傳播行為:
- PROPAGATION_REQUIRED 表示當前方法必須運行在事務中。如果當前事務存在,方法將會在該事務中運 行床牧。否則,會啟動一個新的事務,Spring 默認使用
- PROPAGATION_SUPPORTS 表示當前方法不需要事務上下文,但是如果存在當前事務的話,那么該方法會 在這個事務中運行
- PROPAGATION_MANDATORY 表示該方法必須在事務中運行,如果當前事務不存在,則會拋出一個異常
- PROPAGATION_REQUIRED_NEW 表示當前方法必須運行在它自己的事務中荣回。一個新的事務將被啟動。如果 存在當前事務,在該方法執(zhí)行期間,當前事務會被掛起叠赦。如果使用 JTATransactionManager 的話,則需要 訪問 TransactionManager
- PROPAGATION_NOT_SUPPORTED 表示該方法不應該運行在事務中驹马。如果存在當前事務,在該方法運行期 間,當前事務將被掛起。如果使用 JTATransactionManager 的話,則需要訪問
- TransactionManager PROPAGATION_NEVER 表示當前方法不應該運行在事務上下文中除秀。如果當前正有一個事務在運行,則會拋 出異常
- PROPAGATION_NESTED 表示如果當前已經存在一個事務,那么該方法將會在嵌套事務中運行。嵌套的事務 可以獨立于當前事務進行單獨地提交或回滾算利。如果當前事務不存在,那么其行為與PROPAGATION_REQUIRED 一樣册踩。注意各廠商對這種傳播行為的支持是有所差異的⌒茫可以參考資源管理器的 文檔來確認它們是否支持嵌套事務
三暂吉、隔離級別
隔離級別定義了一個事務可能受其他并發(fā)事務影響的程度胖秒。
ISOLATION_DEFAULT 使用后端數(shù)據庫默認的隔離級別,Spring默認使用,mysql默認的隔離級別為:
- Repeatable Read(可重復讀)
- ISOLATION_READ_UNCOMMITTED 讀未提交,最低的隔離級別,允許讀取尚未提交的數(shù)據變更,可能會導致 臟讀、幻讀或不可重復讀
- ISOLATION_READ_COMMITTED 讀已提交,允許讀取并發(fā)事務已經提交的數(shù)據,可以阻止臟讀,但是幻讀或不可重復讀仍有可能發(fā)生
- ISOLATION_REPEATABLE_READ 可重復讀,對同一字段的多次讀取結果都是一致的,除非數(shù)據是被本身事 務自己所修改,可以阻止臟讀和不可重復讀,但幻讀仍有可能發(fā)生
- ISOLATION_SERIALIZABLE 可串行化,最高的隔離級別,完全服從ACID的隔離級別,確保阻止臟讀慕的、不可 重復讀以及幻讀,也是最慢的事務隔離級別,因為它通常是通過完全鎖定事務相關的數(shù)據庫表來實現(xiàn)的
臟讀(Dirty reads)——臟讀發(fā)生在一個事務讀取了另一個事務改寫但尚未提交的數(shù)據時阎肝。如果改寫再 稍后被回滾了,那么第一個事務獲取的數(shù)據就是無效的。 - 不可重復讀(Nonrepeatable read)——不可重復讀發(fā)生在一個事務執(zhí)行相同的查詢兩次或兩次以上,但 是每次都得到不同的數(shù)據時肮街。這通常是因為另一個并發(fā)事務在兩次查詢期間進行了更新风题。
幻讀(Phantom read)——幻讀與不可重復讀類似。它發(fā)生在一個事務(T1)讀取了幾行數(shù)據,接著另一 個并發(fā)事務(T2)插入了一些數(shù)據時嫉父。在隨后的查詢中,第一個事務(T1)就會發(fā)現(xiàn)多了一些原本不存在 的記錄沛硅。
四、屬性說明 @Transactional
a绕辖、isolation:用于指定事務的隔離級別摇肌。默認為底層事務的隔離級別。
b仪际、noRollbackFor:指定遇到指定異常時強制不回滾事務围小。
c、noRollbackForClassName:指定遇到指定多個異常時強制不回滾事務树碱。該屬性可以指定多個異常類 名肯适。
d、propagation:指定事務的傳播屬性赴恨。
e疹娶、readOnly:指定事務是否只讀。表示這個事務只讀取數(shù)據但不更新數(shù)據,這樣可以幫助數(shù)據庫引擎優(yōu) 化事務伦连。若真的是一個只讀取的數(shù)據庫應設置 readOnly=true
f雨饺、rollbackFor:指定遇到指定異常時強制回滾事務。
g惑淳、rollbackForClassName:指定遇到指定多個異常時強制回滾事務额港。該屬性可以指定多個異常類名。
h歧焦、timeout:指定事務的超時時長移斩。
注意:
1.mysql 為例,存儲引擎不能使用 MyISAM,應該使用 InnoDB
實現(xiàn)代碼
@Service
public class UserService {
@Autowired
private RoncooUserDao roncooUserDao;
@Autowired
private RoncooUserLogDao roncooUserLogDao;
/**
* 用戶注冊 *
* @return
*/
@Transactional
public String register(String name, String ip) {
// 1.添加用戶
RoncooUser roncooUser = new RoncooUser(); roncooUser.setName(name);
roncooUser.setCreateTime(new Date()); roncooUserDao.insert(roncooUser);
// 測試使用
boolean flag = true;
if (flag) {
throw new RuntimeException();
}
// 2.添加注冊日志
RoncooUserLog roncooUserLog = new RoncooUserLog(); roncooUserLog.setUserName(name); roncooUserLog.setUserIp(ip);
roncooUserLog.setCreateTime(new Date()); roncooUserLogDao.save(roncooUserLog);
return "success"; }
}
測試
@Autowired
private UserService userService;
@Test
public void register() {
String result = userService.register("無境", "192.168.1.1");
System.out.println(result);
}