事物管理(黑馬學習筆記)

事物回顧

在數據庫階段我們已學習過事務了,我們講到:

事物是一組操作的集合,它是一個不可分割的工作單位。事務會把所有的操作作為一個整體,一起向數據庫提交或者是撤銷操作請求。所以這組操作要么同時成功,要么同時失敗。

怎么樣來控制這組操作,讓這組操作同時成功或同時失敗呢?此時就要涉及到事務的具體操作了。

事務的操作主要有三步:

開啟事務(一組操作開始前,開啟事務):start transaction / begin ;

提交事務(這組操作全部成功后,提交事務):commit ;

回滾事務(中間任何一個操作出現異常,回滾事務):rollback ;

Spring事務管理

案例

簡單的回顧了事務的概念以及事務的基本操作之后,接下來我們看一個事務管理案例:解散部門 (解散部門就是刪除部門)

需求:當部門解散了不僅需要把部門信息刪除了,還需要把該部門下的員工數據也刪除了。

步驟:

? ? ● 根據ID刪除部門數據

? ? ● 根據部門ID刪除該部門下的員工

代碼實現:

DeptServiceImpl

@Slf4j
@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Autowiredprivate EmpMapper empMapper;//根據部門id,刪除部門信息及部門下的所有員工@Overridepublic void delete(Integer id){//根據部門id刪除部門信息deptMapper.deleteById(id);//刪除部門下的所有員工信息empMapper.deleteByDeptId(id);   }
}

DeptMapper

@Mapper
public interface DeptMapper {/*** 根據id刪除部門信息* @param id   部門id*/@Delete("delete from dept where id = #{id}")void deleteById(Integer id);
}

EmpMapper

@Mapper
public interface EmpMapper {//根據部門id刪除部門下所有員工@Delete("delete from emp where dept_id=#{deptId}")public int deleteByDeptId(Integer deptId);}

重啟SpringBoot服務,使用postman測試部門刪除:

代碼正常情況下,dept表和Emp表中的數據已刪除

修改DeptServiceImpl類中代碼,添加可能出現異常的代碼:

@Slf4j
@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Autowiredprivate EmpMapper empMapper;//根據部門id,刪除部門信息及部門下的所有員工@Overridepublic void delete(Integer id){//根據部門id刪除部門信息deptMapper.deleteById(id);//模擬:異常發生int i = 1/0;//刪除部門下的所有員工信息empMapper.deleteByDeptId(id);   }
}

重啟SpringBoot服務,使用postman測試部門刪除:

查看數據庫表:

● 刪除了2號部門

● 2號部門下的員工數據沒有刪除

以上程序出現的問題:即使程序運行拋出了異常,部門依然刪除了,但是部門下的員工卻沒有刪除,造成了數據的不一致。

原因分析

原因:

● 先執行根據id刪除部門的操作,這步執行完畢,數據庫表 dept 中的數據就已經刪除了。

● 執行 1/0 操作,拋出異常

● 拋出異常之前,下面所有的代碼都不會執行了,根據部門ID刪除該部門下的員工,這個操作也不會執行 。

此時就出現問題了,部門刪除了,部門下的員工還在,業務操作前后數據不一致。

而要想保證操作前后,數據的一致性,就需要讓解散部門中涉及到的兩個業務操作,要么全部成功,要么全部失敗。那我們如何,讓這兩個操作要么全部成功,要么全部失敗呢 ?

那就可以通過事務來實現,因為一個事務中的多個業務操作,要么全部成功,要么全部失敗。

此時,我們就需要在delete刪除業務功能中添加事務。

在方法運行之前,開啟事務,如果方法成功執行,就提交事務,如果方法執行的過程當中出現異常了,就回滾事務。

思考:開發中所有的業務操作,一旦我們要進行控制事務,是不是都是這樣的套路?

答案:是的。

所以在spring框架當中就已經把事務控制的代碼都已經封裝好了,并不需要我們手動實現。我們使用了spring框架,我們只需要通過一個簡單的注解@Transactional就搞定了。

Transactional注解

@Transactional作用:就是在當前這個方法執行開始之前來開啟事務,方法執行完畢之后提交事務。如果在這個方法執行的過程當中出現了異常,就會進行事務的回滾操作。

@Transactional注解:我們一般會在業務層當中來控制事務,因為在業務層當中,一個業務功能可能會包含多個數據訪問的操作。在業務層來控制事務,我們就可以將多個數據訪問操作控制在一個事務范圍內。

@Transactional注解書寫位置:

方法

? ? ○ 當前方法交給spring進行事務管理

? ? ○ 當前類中所有的方法都交由spring進行事務管理

接口

? ? ○ 接口下所有的實現類當中所有的方法都交給spring 進行事務管理

接下來,我們就可以在業務方法delete上加上 @Transactional 來控制事務 。

@Slf4j
@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Autowiredprivate EmpMapper empMapper;@Override@Transactional  //當前方法添加了事務管理public void delete(Integer id){//根據部門id刪除部門信息deptMapper.deleteById(id);//模擬:異常發生int i = 1/0;//刪除部門下的所有員工信息empMapper.deleteByDeptId(id);   }
}

在業務功能上添加@Transactional注解進行事務管理后,我們重啟SpringBoot服務,使用postman測試:

添加Spring事務管理后,由于服務端程序引發了異常,所以事務進行回滾。

說明:可以在application.yml配置文件中開啟事務管理日志,這樣就可以在控制看到和事務相關的日志信息了

#spring事務管理日志
logging:level:org.springframework.jdbc.support.JdbcTransactionManager: debug

事務進階

前面我們通過spring事務管理注解@Transactional已經控制了業務層方法的事務。接下來我們要來詳細的介紹一下@Transactional事務管理注解的使用細節。我們這里主要介紹@Transactional注解當中的兩個常見的屬性:

? ? 1.異常回滾的屬性:rollbackFor

? ? 2.事務傳播行為:propagation

我們先來學習下rollbackFor屬性。

rollbackFor

我們在之前編寫的業務方法上添加了@Transactional注解,來實現事務管理。

@Transactional
public void delete(Integer id){//根據部門id刪除部門信息deptMapper.deleteById(id);//模擬:異常發生int i = 1/0;//刪除部門下的所有員工信息empMapper.deleteByDeptId(id);   
}

以上業務功能delete()方法在運行時,會引發除0的算數運算異常(運行時異常),出現異常之后,由于我們在方法上加了@Transactional注解進行事務管理,所以發生異常會執行rollback回滾操作,從而保證事務操作前后數據是一致的。

下面我們在做一個測試,我們修改業務功能代碼,在模擬異常的位置上直接拋出Exception異常(編譯時異常)

@Transactional
public void delete(Integer id) throws Exception {//根據部門id刪除部門信息deptMapper.deleteById(id);//模擬:異常發生if(true){throw new Exception("出現異常了~~~");}//刪除部門下的所有員工信息empMapper.deleteByDeptId(id);   
}

說明:在service中向上拋出一個Exception編譯時異常之后,由于是controller調用service,所以在controller中要有異常處理代碼,此時我們選擇在controller中繼續把異常向上拋。

@DeleteMapping("/depts/{id}")
public Result delete(@PathVariable Integer id) throws Exception {//日志記錄log.info("根據id刪除部門");//調用service層功能deptService.delete(id);//響應return Result.success();
}

重新啟動服務后測試:

拋出異常之后事務會不會回滾

使用postman測試,刪除5號部門

發生了Exception異常,但事務依然提交了

通過以上測試可以得出一個結論:默認情況下,只有出現RuntimeException(運行時異常)才會回滾事務。

假如我們想讓所有的異常都回滾,需要來配置@Transactional注解當中的rollbackFor屬性,通過rollbackFor這個屬性可以指定出現何種異常類型回滾事務

@Slf4j
@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Autowiredprivate EmpMapper empMapper;@Override@Transactional(rollbackFor=Exception.class)public void delete(Integer id){//根據部門id刪除部門信息deptMapper.deleteById(id);//模擬:異常發生int num = id/0;//刪除部門下的所有員工信息empMapper.deleteByDeptId(id);   }
}

接下來我們重新啟動服務,測試刪除部門的操作:

控制臺日志:執行了刪除3號部門的操作, 因為異常又進行了事務回滾

數據表:3號部門沒有刪除

結論:

? ? ● 在Spring的事務管理中,默認只有運行時異常 RuntimeException才會回滾。

? ? ● 如果還需要回滾指定類型的異常,可以通過rollbackFor屬性來指定。

propagation

介紹

我們接著繼續學習@Transactional注解當中的第二個屬性propagation,這個屬性是用來配置事務的傳播行為的。

什么是事務的傳播行為呢?

? ? ● 就是當一個事務方法被另一個事務方法調用時,這個事務方法應該如何進行事務控制。

例如:兩個事務方法,一個A方法,一個B方法。在這兩個方法上都添加了@Transactional注解,就代表這兩個方法都具有事務,而在A方法當中又去調用了B方法。

所謂事務的傳播行為,指的就是在A方法運行的時候,首先會開啟一個事務,在A方法當中又調用了B方法, B方法自身也具有事務,那么B方法在運行的時候,到底是加入到A方法的事務當中來,還是B方法在運行的時候新建一個事務?這個就涉及到了事務的傳播行為。

我們要想控制事務的傳播行為,在@Transactional注解的后面指定一個屬性propagation,通過 propagation 屬性來指定傳播行為。接下來我們就來介紹一下常見的事務傳播行為。

屬性值含義
REQUIRED【默認值】需要事務,有則加入,無則創建新事務
REQUIRES_NEW需要新事務,無論有無,總是創建新事務
SUPPORTS支持事務,有則加入,無則在無事務狀態中運行
NOT_SUPPORTED不支持事務,在無事務狀態下運行,如果當前存在已有事務,則掛起當前事務
MANDATORY必須有事務,否則拋異常
NEVER

必須沒事務,否則拋異常

對于這些事務傳播行為,我們只需要關注以下兩個就可以了:

? ? 1.REQUIRED(默認值)

? ? 2.REQUIRES_NEW

案例

接下來我們就通過一個案例來演示下事務傳播行為propagation屬性的使用。

需求:解散部門時需要記錄操作日志

由于解散部門是一個非常重要而且非常危險的操作,所以在業務當中要求每一次執行解散部門的操作都需要留下痕跡,就是要記錄操作日志。而且還要求無論是執行成功了還是執行失敗了,都需要留下痕跡。

步驟:

? ? 1.執行解散部門的業務:先刪除部門,再刪除部門下的員工(前面已實現)

? ? 2.記錄解散部門的日志,到日志表(未實現)

準備工作:

創建數據庫表 dept_log 日志表:

create table dept_log(id int auto_increment comment '主鍵ID' primary key,create_time datetime null comment '操作時間',description varchar(300) null comment '操作描述'
)comment '部門操作日志表';

實體類:DeptLog

@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeptLog {private Integer id;private LocalDateTime createTime;private String description;
}

Mapper接口:DeptLogMapper

@Mapper
public interface DeptLogMapper {@Insert("insert into dept_log(create_time,description) values(#{createTime},#{description})")void insert(DeptLog log);}

業務接口:DeptLogService

public interface DeptLogService {void insert(DeptLog deptLog);
}

業務實現類:DeptLogServiceImpl

@Service
public class DeptLogServiceImpl implements DeptLogService {@Autowiredprivate DeptLogMapper deptLogMapper;@Transactional //事務傳播行為:有事務就加入、沒有事務就新建事務@Overridepublic void insert(DeptLog deptLog) {deptLogMapper.insert(deptLog);}
}

代碼實現:

業務實現類:DeptServiceImpl

@Slf4j
@Service
//@Transactional //當前業務實現類中的所有的方法,都添加了spring事務管理機制
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Autowiredprivate EmpMapper empMapper;@Autowiredprivate DeptLogService deptLogService;//根據部門id,刪除部門信息及部門下的所有員工@Override@Log@Transactional(rollbackFor = Exception.class) public void delete(Integer id) throws Exception {try {//根據部門id刪除部門信息deptMapper.deleteById(id);//模擬:異常if(true){throw new Exception("出現異常了~~~");}//刪除部門下的所有員工信息empMapper.deleteByDeptId(id);}finally {//不論是否有異常,最終都要執行的代碼:記錄日志DeptLog deptLog = new DeptLog();deptLog.setCreateTime(LocalDateTime.now());deptLog.setDescription("執行了解散部門的操作,此時解散的是"+id+"號部門");//調用其他業務類中的方法deptLogService.insert(deptLog);}}//省略其他代碼...
}

測試:

重新啟動SpringBoot服務,測試刪除3號部門后會發生什么?

? ? ● 執行了刪除3號部門操作

? ? ● 執行了插入部門日志操作

? ? ● 程序發生Exception異常

? ? ● 執行事務回滾(刪除、插入操作因為在一個事務范圍內,兩個操作都會被回滾)

然后在dept_log表中沒有記錄日志數據

原因分析:

接下來我們就需要來分析一下具體是什么原因導致的日志沒有成功的記錄。

在執行delete操作時開啟了一個事務

當執行insert操作時,insert設置的事務傳播行是默認值REQUIRED,表示有事務就加入,沒有則新建事務

此時:delete和insert操作使用了同一個事務,同一個事務中的多個操作,要么同時成功,要么同時失敗,所以當異常發生時進行事務回滾,就會回滾delete和insert操作

解決方案:

在DeptLogServiceImpl類中insert方法上,添加@Transactional(propagation = Propagation.REQUIRES_NEW)

Propagation.REQUIRES_NEW :不論是否有事務,都創建新事務 ,運行在一個獨立的事務中。

@Service
public class DeptLogServiceImpl implements DeptLogService {@Autowiredprivate DeptLogMapper deptLogMapper;@Transactional(propagation = Propagation.REQUIRES_NEW)//事務傳播行為:不論是否有事務,都新建事務@Overridepublic void insert(DeptLog deptLog) {deptLogMapper.insert(deptLog);}
}

重啟SpringBoot服務,再次測試刪除3號部門:

那此時,DeptServiceImpl中的delete方法運行時,會開啟一個事務。 當調用 deptLogService.insert(deptLog) 時,也會創建一個新的事務,那此時,當insert方法運行完畢之后,事務就已經提交了。 即使外部的事務出現異常,內部已經提交的事務,也不會回滾了,因為是兩個獨立的事務。

到此事務傳播行為已演示完成,事務的傳播行為我們只需要掌握兩個:REQUIRED、REQUIRES_NEW。

REQUIRED :大部分情況下都是用該傳播行為即可。

REQUIRES_NEW :當我們不希望事務之間相互影響時,可以使用該傳播行為。比如:下訂單前需要記錄日志,不論訂單保存成功與否,都需要保證日志記錄能夠記錄成功。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/710877.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/710877.shtml
英文地址,請注明出處:http://en.pswp.cn/news/710877.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java實現根據 表索引 批量新增或更新數據信息

目的 通過數據庫名、表名實現動態添加活更新數據。添加或更新由唯一索引判斷。 實現 思路 查詢數據庫表的唯一索引-CSDN博客 根據數據庫表名動態查詢表字段-CSDN博客 達夢數據庫根據唯一索引批量新增或更新數據-CSDN博客 將數據轉換為sql語句需要的格式 完善代碼,實…

maven常用打包命令

1.背景 2.代碼 1 mvn常用命令 一般情況下對于一個maven項目,cd切換到當前項目路徑下,執行如下示例命令即可對項目進行打包。 mvn clean install mvn -U clean package -Dmaven.test.skiptrue mvn clean package -Dmaven.test.skiptrue -P prod mvn cle…

JavaScript數組操作指南:20個精通操作技巧指南

splice、 slice、 pop 和 shift。數組的排序方法是穩定且非原地算法的嗎?要記住所有 JavaScript 數組方法以及它們之間的區別并不容易。它們的名稱相似,就好像直接從同義詞詞典中提取一樣。 這個數組速查表列出了 JavaScript 中通常需要的所有數組方法&…

Gson使用Object接收長數字問題

近期發現公司同事在使用Gson對數字進行反序列列化時出現丟失精度的問題,在這里搬運一下,做個記錄~ 現象 使用Gson反序列化長Long數字(大于16位),如果用Object類型來接收則會丟失精度。 Gson會將數字反序列化為double類型,double類型本身就容易丟精度。…

小程序基礎

小程序基礎 1. 認識什么是小程序 什么是微信小程序 微信小程序是一種運行在微信內部的 輕量級 應用程序。 在使用小程序時 不需要下載安裝,用戶 掃一掃 或 搜一下 即可打開應用。它也體現了 “用完即走” 的理念,用戶不用關心安裝太多應用的問題。它…

weak的實現原理

iOS 在運行時維護著一個全局的弱引用表,該表是一個 hash 表,hash表的 key 是 對象本身,value 是指向該對象的所有 weak 指針的地址數組。 /**全局的弱引用表,本質是一個hash結構,對象本身作為key, 存儲weak修飾的指…

大模型訓練經驗

1.模型訓練好后預測全是起始符號。 解決辦法:訓練數據的輸入輸出去掉起始符號。 2.模型訓練后學不到有效信息。 加大epoch,我加大到了1000。 3.模型訓練后預測沒有結束符,暫時未解,另外,發現當訓練不足時&#xff…

Metasploit安裝及使用教程(非常詳細)從零基礎入門到精通,看完這一篇就夠了。

通過本篇文章,我們將會學習以下內容: 1、在Windows上安裝Metasploit 2、在Linux和MacOS上安裝Metasploit 3、在Kali Linux中使用 Metasploit 4、升級Kali Linux 5、使用虛擬化軟件構建滲透測試實驗環境 6、配置SSH連接 7、使用SSH連接Kali 8、配…

如何學習自然語言處理之語言模型

自然語言處理(NLP)是一種人工智能技術,它使計算機能夠理解和處理人類語言。而語言模型是NLP中的一個重要概念,主要是用來估測一些詞的序列的概率,即預測p(w1, w2, w3 … wn),其中一個應用就是句子的生成。 …

JVM運行流程

? 作者:小胡_不糊涂 🌱 作者主頁:小胡_不糊涂的個人主頁 📀 收錄專欄:JavaEE 💖 持續更文,關注博主少走彎路,謝謝大家支持 💖 JVM 1. 運行流程2. 運行時數據區2.1 堆&am…

ubuntu新建ap熱點并分享

測試環境ubuntu16,只有一臺筆記本電腦,不插網線,無線網卡既連wifi,又作為熱點 1.方法1 直接手動新建ap熱點 參考https://jingyan.baidu.com/article/ea24bc39b03fc6da62b331f0.html https://jingyan.baidu.com/article/363872ecd8f35d6e4ba…

機試指南:Ch5:線性數據結構 Ch6:遞歸與分治

文章目錄 第5章 線性數據結構1.向量 vector2.隊列 queue(1)隊列的特點、應用(2)基本操作(3)例題例題1:約瑟夫問題2 (難度:中等) (4)習題習題1:排隊打飯 (難度:中等) 3.棧 stack(1)棧…

前端 JS 經典:Content-type 詳解

1. 什么是 Content-Type Content-Type 是 HTTP 協議中的一個請求頭或響應頭字段,用于指示發送或接收的實體的媒體類型,告訴服務器或客戶端如何解析和處理請求或響應的主體部分。 2. Content-Type 的構成 Content-Type 由兩部分組成:媒體類型…

視頻在線壓縮

video2edit 一款免費的在線視頻編輯軟件,可以進行視頻合并、視頻剪輯、視頻壓縮以及轉換視頻格式等。 鏈接地址:在線視頻編輯器和轉換器 - 編輯,轉換和壓縮視頻文件 打開視頻壓縮頁面,上傳想要壓縮視頻,支持MP4&…

收入穩步增長 助力持續發展 尼康發布截至2024年3月財年第三季度財報

近日,尼康截至2024年3月財年的第三季度(2023年10月1日-2023年12月31日)財報正式發布。數據顯示,尼康集團第三財季銷售收入共計1977億日元,較去年同期上漲300億日元,漲幅約17.9%。其中影像業務領域&#xff…

Java面試題:解釋Java內存模型中的內存順序規則,Java中的線程組(ThreadGroup)的工作原理,Java中的FutureTask的工作原理

引言 在Java開發領域,內存模型、多線程和并發是三個至關重要的概念,它們直接影響到程序的性能、穩定性和可擴展性。作為面試官,考察候選人對這些概念的理解和應用能力是評估其技術水平的重要手段。本文將提供三道涉及這些核心知識點的面試題…

視頻記錄儀_基于聯發科MT6762的智能4G記錄儀方案

智能記錄儀采用聯發科強勁八核處理器,12nm制程工藝的記錄儀具便是滿足這些需求的理想選擇。搭載4GB32GB內存,并運行Android 11.0操作系統,這款記錄儀具展現出強勁的性能表現。 首先,這款記錄儀具具備優秀的視頻錄制功能。它能完整…

WPS如何共享文件和文件夾

1 WPS共享單個文件 用WPS打開要分享的文件,點擊右上角的“分享”鍵,選擇上傳到云端。 之后點擊“創建并分享”,即可分享該文檔。 2 WPS創建共享文件夾 2.1 如何共享文件夾 首先打開WPS,點擊左上角的首頁。在首頁欄中&#…

Ubuntu系統下DPDK環境搭建

目錄 一.虛擬機配置1.添加一個網卡(橋接模式)2.修改網卡類型3.修改網卡名稱4.重啟虛擬機5.查看網卡信息6.dpdk配置內存巨型頁 三 DPDK源代碼下載和編譯1.下載源代碼2.解壓源代碼3.安裝編譯環境4.編譯5.設置dpdk的環境變量6.禁止多隊列網卡7.加載igb_uio模塊8.網卡綁定9.驗證測試…

Vue3自定義文章列表組件

一、Vue3的代碼展示 <template><div><div v-for"article in articles" :key"article.id" class"article-card"><div class"author-info"><img :src"article.avatar" alt"Author Avatar&qu…