Spring事務管理零基礎入門
一、簡介
概念:事務是數(shù)據(jù)庫操作的最小工作單元,是作為單個邏輯工作單元執(zhí)行的一系列操作,這些操作一起提交,要么都執(zhí)行,要么都不執(zhí)行。事務時一組不可分割的操作集合(工作邏輯單元)。
簡而言之,就是一系列操作要么都執(zhí)行成功(事務提交),要么都執(zhí)行失敗(事務回滾)
二、特性(一原持久隔離)
2.1 原子性
事務中所有操作是不可再分割的原子單位。事務中所有操作要么都執(zhí)行成功,要么都執(zhí)行失敗
2.2 一致性(類似能量守恒)
事務執(zhí)行后,數(shù)據(jù)庫狀態(tài)與其他業(yè)務規(guī)則保持一致,保證數(shù)據(jù)的一致性
2.3 隔離性
在并發(fā)操作中,不同事務之間應該隔離開,使每個并發(fā)的事務不會相互干擾
2.4 持久性
一旦事務提交成功,事務中所有的數(shù)據(jù)操作都必須持久化到數(shù)據(jù)庫中,即使提交事務后,數(shù)據(jù)庫立馬崩潰,在數(shù)據(jù)庫重啟時,也必須能通過某種機制恢復數(shù)據(jù)
三、隔離級別
3.1 事務級別(從低到高)
Read uncommitted:
讀未提交,一個事務可以讀取另一個未提交事務的數(shù)據(jù)。會產(chǎn)生臟讀。
Read committed:
讀提交,一個事務要等另一個事務提交后才能讀取數(shù)據(jù),會產(chǎn)生不可重復讀。
Repeatable read:
重復讀,開始讀取數(shù)據(jù)(事務開啟)時,不再允許修改操作,可能出現(xiàn)幻讀。
Seriazable:
最高的事務隔離級別,該級別下事務串行化順序執(zhí)行,可避免臟讀、不可重復讀、幻讀,但是該事務級別效率低下,比較耗數(shù)據(jù)庫性能,一般不使用。
3.2 常用數(shù)據(jù)庫默認級別:
Sql Server、Oracle 默認事務隔離級別: Read committed
Mysql 默認隔離級別是:Repeatable read
3.3 事務中可能出現(xiàn)的問題:
臟讀(讀取了未提交的新事物,然后回滾了)
A 事務讀取了 B 事務中未提交的數(shù)據(jù), 如果事務 B 回滾,則 A 讀取使用了錯誤的數(shù)據(jù)。

不可重復讀(讀取了提交的新事物,指更新操作)
在對于數(shù)據(jù)庫中某個數(shù)據(jù),一個事務范圍內多次查詢卻返回了不同的數(shù)據(jù)值,這是由于在查詢間隔,被另一個事務修改了。

幻讀(讀取了新提交的事務,指增加刪除操作)
在事務 A 多次讀取構成中,事務 B 對數(shù)據(jù)進行了新增/刪除操作,導致 事務 A 多次讀取的數(shù)據(jù)不一致。

第一類事務丟失(回滾丟失)
事務 A、B 同時執(zhí)行一個數(shù)據(jù),事務 B 已經(jīng)提交,事務 A 回滾了,B 的事務操作就因為事務 A 回滾而丟失了
第二類事務丟失(提交覆蓋丟失)
事務 A、B 同時執(zhí)行一個數(shù)據(jù),兩個同時獲取到一個數(shù)據(jù),事務 B 先提交, 事務 A 后提交,則事務 A 覆蓋了事務 B
四、傳播特性
事務的傳播性分為以下三類,所有的都是給內部方法配置
4.1 死活都不要事務
Never:外部方法沒有事務就非事務執(zhí)行,有就拋出異常
Not_Supported:外部方法沒有事務就非事務執(zhí)行,有就直接掛起,然后非事務執(zhí)行
4.2 可有可無的
Supported:外部方法有事務就用,沒有就算了
4.3 必須要有事務
Requires_new:不管外部方法有沒有事務都新建事務,如果外部有,就將外部事務掛起
Nested:如果外部方法沒有事務,就新建一個事務,如果外部有事務,就在外部事務中嵌套事務
Required:如果外部方法沒有事務就新建一個事務,如果有,就加入外部方法的事務,這個是最常用的,也是默認的
Mandatory:如果外部方法沒有事務就拋出異常,如果有,就使用外部方法的事務
五、應用
5.1 數(shù)據(jù)表

5.2 實體類
import lombok.Data;
import javax.persistence.*;
@Data
@Entity
public class User {
@Id
@GeneratedValue
private Integer id;
private String name;
private double money;
}5.3 Service
package com.dily.study.work.service;
import com.dily.study.work.entity.User;
import com.dily.study.work.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired // 使用jpa
private UserRepository userRepository;
/**
* 轉出
*
* @param fromName 從誰轉出
* @param money 轉出金額
*/
public void out(String fromName, int money) {
User user = userRepository.findByName(fromName);
user.setMoney(user.getMoney() - money);
userRepository.save(user);
}
/**
* 轉入
*
* @param toName 轉到哪里
* @param money 轉入金額
*/
public void in(String toName, int money) {
User user = userRepository.findByName(toName);
user.setMoney(user.getMoney() + money);
userRepository.save(user);
}
/**
* 帶事務
* 要么都成功,要么都失敗
*
* @param fromName 從哪里轉出
* @param toName 轉入到哪里
* @param money 金額
*/
@Transactional
public void transfer(String fromName, String toName, int money) {
out(fromName, money);
if (true) throw new RuntimeException("出錯了");
in(toName, money);
}
/**
* 不帶事務
* 只有轉出成功,轉入失敗
*
* @param fromName 從哪里轉出
* @param toName 轉入到哪里
* @param money 金額
*/
public void transfer(String fromName, String toName, int money) {
out(fromName, money);
if (true) throw new RuntimeException("出錯了");
in(toName, money);
}
}事務的嵌套
// 在 UserService 中注入自己,因為如果內部調用自己的方法,事務注解不生效。
@Autowired
private UserService userService;
/**
* 外層事務,外層只轉出
*
* @param fromName 從哪里轉出
* @param toName 轉入到哪里
* @param money 金額
*/
@Transactional
public void laoda(String fromName, String toName, int money) {
userService.out(fromName, money);
if (true) throw new RuntimeException("出錯了");
userService.xiaodi(toName,money);
}
/**
* 內層事務,內層只轉入
* 可以修改 propagation 的值來查看不同傳播類型的效果
*
* @param toName 轉入到哪里
* @param money 金額
*/
@Transactional(propagation = Propagation.MANDATORY)
public void xiaodi(String toName, int money) {
if (true) throw new RuntimeException("出錯了");
userService.in(toName, money);
}內外部方法盡量避免操作同一張表,當外部方法事務掛起時,則外部操作的表會被加鎖,內部方法事務則無法操作同一張表
到此這篇關于Spring事務管理零基礎入門的文章就介紹到這了,更多相關Spring事務管理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java 8 Function函數(shù)式接口及函數(shù)式接口實例
函數(shù)式接口(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。接下來通過本文給大家介紹Java 8 Function函數(shù)式接口及函數(shù)式接口實例代碼,需要的朋友可以參考下2018-05-05
SpringBoot和Vue.js實現(xiàn)的前后端分離的用戶權限管理系統(tǒng)
本文主要介紹了SpringBoot和Vue.js實現(xiàn)的前后端分離的用戶權限管理系統(tǒng),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-04-04
spring中FactoryBean中的getObject()方法實例解析
這篇文章主要介紹了spring中FactoryBean中的getObject()方法實例解析,分享了相關代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下2018-02-02
Java并發(fā)系列之AbstractQueuedSynchronizer源碼分析(共享模式)
這篇文章主要為大家詳細介紹了Java并發(fā)系列之AbstractQueuedSynchronizer源碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-02-02
PostMan post請求發(fā)送Json數(shù)據(jù)的方法
下面小編就為大家分享一篇PostMan post請求發(fā)送Json數(shù)據(jù)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03
java中int轉string與string轉int的效率對比
這篇文章主要介紹了java中int轉string與string轉int的效率對比,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringBoot修改子模塊Module的jdk版本的方法 附修改原因
這篇文章主要介紹了SpringBoot修改子模塊Module的jdk版本的方法 附修改原因,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-04-04

