Spring Boot業務代碼中使用@Transactional事務失效踩坑點總結

1.概述

接著之前我們對Spring AOP以及基于AOP實現事務控制的上文,今天我們來看看平時在項目業務開發中使用聲明式事務@Transactional的失效場景,并分析其失效原因,從而幫助開發人員盡量避免踩坑。

我們知道 Spring 聲明式事務功能提供了極其方便的事務配置方式,配合 Spring Boot 的自動配置,大多數 Spring Boot 項目只需要在方法上標記 @Transactional 注解,即可一鍵開啟方法的事務性配置。當然后端開發人員對數據庫事務這個概念并不陌生,也知道如果整體考慮多個數據庫操作要么成功要么失敗時,需要通過數據庫事務來實現多個操作的一致性和原子性。如下所示:

    @Override@Transactional(rollbackFor = Exception.class)public void addUser(UserParam param) {User user = PtcBeanUtils.copy(param, User.class);userDAO.insert(user);if (!CollectionUtils.isEmpty(param.getRoleIds())) {userRoleService.addUserRole(user.getId(), param.getRoleIds());}}

新增用戶的同時還添加了用戶角色,這里就是使用@Transactional來控制事務保證一致性的。但大多數開發僅限于為方法標記 @Transactional來開啟聲明式事務,認為就可以高枕無憂了,不會去關注事務是否有效、出錯后事務是否正確回滾,也不會考慮復雜的業務代碼中涉及多個子業務邏輯時,怎么正確處理事務。事務沒有被正確處理,一般來說不會過于影響正常流程,也不容易在測試階段被發現。但當系統越來越復雜、壓力越來越大之后,就會帶來大量的數據不一致問題,隨后就是大量的人工介入查看和修復數據。

正是因為聲明式事務@Transactional使用簡單,所以很多開發人員不注重細節點,但是@Transactional條條框框還蠻多的,可謂是細節點拉滿,如果不注意也不小心就會掉進坑里,今天就讓我們一起來了解使用細節,把坑填平咯。

2.@Transactional

話不多說,先看看該注解定義

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {@AliasFor("transactionManager")String value() default "";@AliasFor("value")String transactionManager() default "";Propagation propagation() default Propagation.REQUIRED;Isolation isolation() default Isolation.DEFAULT;int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;boolean readOnly() default false;Class<? extends Throwable>[] rollbackFor() default {};String[] rollbackForClassName() default {};Class<? extends Throwable>[] noRollbackFor() default {};String[] noRollbackForClassName() default {};}

從上面看出@Transactional既可以作用于類上,也可以作用于方法上,**作用于類:表示所有該類的public**方法都配置相同的事務屬性信息。接下來再看看其屬性:

propagation: 設置事務的傳播行為,主要解決是A方法調用B方法時,事務的傳播方式問題的,默認值為 Propagation.REQUIRED,其他屬性值信息如下:

事務傳播行為解釋
REQUIRED(默認值)A調用B,B需要事務,如果A有事務B就加入A的事務中,如果A沒有事務,B就自己創建一個事務
REQUIRED_NEWA調用B,B需要新事務,如果A有事務就掛起,B自己創建一個新的事務
SUPPORTSA調用B,B有無事務無所謂,A有事務就加入到A事務中,A無事務B就以非事務方式執行
NOT_SUPPORTSA調用B,B以無事務方式執行,A如有事務則掛起
NEVERA調用B,B以無事務方式執行,A如有事務則拋出異常
MANDATORYA調用B,B要加入A的事務中,如果A無事務就拋出異常
NESTEDA調用B,B創建一個新事務,A有事務就作為嵌套事務存在,A沒事務就以創建的新事務執行

**isolation :**事務的隔離級別,默認值為 Isolation.DEFAULT。指定事務的隔離級別,事務并發存在三大問題:臟讀、不可重復讀、幻讀/虛讀。可以通過設置事務的隔離級別來保證并發問題的出現,常用的是READ_COMMITTED 和REPEATABLE_READ

isolation屬性解釋
DEFAULT默認隔離級別,取決于當前數據庫隔離級別,例如MySQL默認隔離級別是REPEATABLE_READ
READ_UNCOMMITTEDA事務可以讀取到B事務尚未提交的事務記錄,不能解決任何并發問題,安全性最低,性能最高
READ_COMMITTEDA事務只能讀取到其他事務已經提交的記錄,不能讀取到未提交的記錄。可以解決臟讀問題,但是不能解決不可重復讀和幻讀
REPEATABLE_READA事務多次從數據庫讀取某條記錄結果一致,可以解決不可重復讀,不可以解決幻讀
SERIALIZABLE串行化,可以解決任何并發問題,安全性最高,但是性能最低

**timeout :**事務的超時時間,默認值為 -1。如果超過該時間限制但事務還沒有完成,則自動回滾事務。

**readOnly:**指定事務是否為只讀事務,默認值為 false;為了忽略那些不需要事務的方法,比如讀取數據,可以設置 read-only 為 true。

**rollbackFor:**用于指定能夠觸發事務回滾的異常類型,可以指定多個異常類型。

**noRollbackFor:**拋出指定的異常類型,不回滾事務,也可以指定多個異常類型。

項目推薦:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企業級系統架構底層框架封裝,解決業務開發時常見的非功能性需求,防止重復造輪子,方便業務快速開發和企業技術棧框架統一管理。引入組件化的思想實現高內聚低耦合并且高度可配置化,做到可插拔。嚴格控制包依賴和統一版本管理,做到最少化依賴。注重代碼規范和注釋,非常適合個人學習和企業使用

Github地址:https://github.com/plasticene/plasticene-boot-starter-parent

Gitee地址:https://gitee.com/plasticene3/plasticene-boot-starter-parent

微信公眾號Shepherd進階筆記

交流探討qun:Shepherd_126

3.@Transactional失效場景、原因及修正方式

3.1 同一個類中的方法通過this調用導致失效

    public void addUser(UserParam param) {User user = PtcBeanUtils.copy(param, User.class);// 新增用戶userDAO.insert(user);// 添加用戶角色this.addUserRole(user.getId(), param.getRoleIds());log.info("執行結束了");}@Transactional(rollbackFor = Exception.class)public void addUserRole(Long userId, List<Long> roleIds) {if (CollectionUtils.isEmpty(roleIds)) {return;}List<UserRole> userRoles = new ArrayList<>();roleIds.forEach(roleId -> {UserRole userRole = new UserRole();userRole.setUserId(userId);userRole.setRoleId(roleId);userRoles.add(userRole);});userRoleDAO.insertBatch(userRoles);throw new RuntimeException("發生異常咯");}

執行#addUser()會發現事務控制失效,發生異常事務并沒有回滾,用戶和角色綁定都插入成功了。

這里,我給出@Transactional 生效原則 1,必須通過代理過的類從外部調用目標方法才能生效.

Spring 是通過 AOP 技術對方法進行增強實現事務控制的,要調用增強過的方法必然是調用代理后的對象,而這里this是原生對象,并不是代理,自然就沒有事務控制了。

修正方式:①:將this換成代理的userService, 可以自己注入自己@Resource private UserService userService,當然也可以不用注入,直接在Spring容器中獲取userService這個bean ②將#addUser()方法開啟事務即加上@Transactional(rollbackFor = Exception.class),這里本就該開啟,只是為了演示失效情況沒加上,因為在#addUser()里面有插入用戶的操作涉及到事務的所以本要開啟。當然如果#addUser()只是做一些判斷、邏輯處理不涉及到數據庫事務操作,那么這樣解決就顯得有點不太合適,而且容易導致另一種事務失效的情況,即因為沒有正確處理異常,導致事務即便生效也不一定能回滾。

3.2 異常被catch“吃掉了”導致@Transactional失效

如下所示:

    @Transactional(rollbackFor = Exception.class)public void addUser(UserParam param) {try {User user = PtcBeanUtils.copy(param, User.class);// 完成一些邏輯處理.......// 添加用戶角色this.addUserRole(user.getId(), param.getRoleIds());log.info("執行結束了");} catch (Exception e) {log.error(e.getMessage());}}@Transactional(rollbackFor = Exception.class)public void addUserRole(Long userId, List<Long> roleIds) {if (CollectionUtils.isEmpty(roleIds)) {return;}List<UserRole> userRoles = new ArrayList<>();roleIds.forEach(roleId -> {UserRole userRole = new UserRole();userRole.setUserId(userId);userRole.setRoleId(roleId);userRoles.add(userRole);});userRoleDAO.insertBatch(userRoles);throw new RuntimeException("發生異常咯");}

@Transactional生效原則2:只有異常傳播出了標記了 @Transactional 注解的方法,事務才能回滾。之前我們總結過 基于AOP事務控制實現原理說過在 Spring的 TransactionAspectSupport 里有個 invokeWithinTransaction 方法,里面就是處理事務的邏輯。可以看到,只有捕獲到異常才能進行后續事務處理:

	protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable {......try {// This is an around advice: Invoke the next interceptor in the chain.// This will normally result in a target object being invoked.retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {// target invocation exception// 捕獲到異常,進行回滾操作,如果我們在業務方法已經捕獲掉異常,這里就捕獲不到了,自然就不會回滾了completeTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}......return result;}}

可以看到,只有捕獲到異常時才進行回滾操作,如果我們在業務方法已經捕獲掉異常,這里就捕獲不到了,自然就不會回滾了。

修正方式:就是對異常捕獲盡量做到局部針對操作,不要籠統把整個方法的代碼邏輯都包括進行,這樣異常就拋出去了。

3.3 @Transactional 屬性 rollbackFor 設置錯誤,導致異常不滿足回滾條件

直接看代碼:

    @Transactionalpublic void addUser(UserParam param) {User user = PtcBeanUtils.copy(param, User.class);.......// 添加用戶角色this.addUserRole(user.getId(), param.getRoleIds());log.info("執行結束了");}public void addUserRole(Long userId, List<Long> roleIds) throws Exception {if (CollectionUtils.isEmpty(roleIds)) {return;}List<UserRole> userRoles = new ArrayList<>();roleIds.forEach(roleId -> {UserRole userRole = new UserRole();userRole.setUserId(userId);userRole.setRoleId(roleId);userRoles.add(userRole);});userRoleDAO.insertBatch(userRoles);throw new Exception("發生異常咯");}

這里#addUser()使用@transactional,但沒有設置rollbackFor屬性,且#addUserRole()拋出的異常是exception,不是RuntimeException,這樣事務也失效了,因為默認情況下,出現 RuntimeException(非受檢異常)或 Error 的時候,Spring才會回滾事務

從上面3.2小節的completeTransactionAfterThrowing(txInfo, ex);進去完成回滾操作會判斷異常類型是否滿足規定,DefaultTransactionAttribute 類能看到如下代碼塊,可以發現相關證據,通過注釋也能看到 Spring 這么做的原因,大概的意思是受檢異常一般是業務異常,或者說是類似另一種方法的返回值,出現這樣的異常可能業務還能完成,所以不會主動回滾;而Error 或 RuntimeException 代表了非預期的結果,應該回滾:

	public boolean rollbackOn(Throwable ex) {return (ex instanceof RuntimeException || ex instanceof Error);}

修正方法:設置rollbackFor@Transactional(rollbackFor = Exception.class)

3.4 @Transactional 應用在非 public 修飾的方法上

    @Transactional(rollbackFor = Exception.class)private void addUserRole(Long userId, List<Long> roleIds) {if (CollectionUtils.isEmpty(roleIds)) {return;}List<UserRole> userRoles = new ArrayList<>();roleIds.forEach(roleId -> {UserRole userRole = new UserRole();userRole.setUserId(userId);userRole.setRoleId(roleId);userRoles.add(userRole);});userRoleDAO.insertBatch(userRoles);throw new RuntimeException("發生異常咯");}

idea也會提示爆紅:

Spring通過CGLIB動態代理來增強生產代理對象,CGLIB 通過繼承方式實現代理類,private 方法在子類不可見,自然也就無法進行事務增強。s在基于AOP事務控制實現原理一文中也分析過,會調用到AbstractFallbackTransactionAttributeSourcecomputeTransactionAttribute()方法

 @Nullableprotected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {// Don't allow no-public methods as required.if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {return null;}......}

修正方式:自然是改成public

3.5 @Transactional 注解傳播屬性 propagation 設置錯誤

如上面我們新增的用戶的同時要添加用戶角色,但是假如我們希望即使添加角色錯誤了,還可以正常新增用戶。

 public void addUser(UserParam param) {String username = param.getUsername();checkUsernameUnique(username);User user = PtcBeanUtils.copy(param, User.class);// 添加用戶userDAO.insert(user);// 添加用戶角色userRoleService.addUserRole(user.getId(), param.getRoleIds());}

#userRoleService.addUserRole()

  @Transactional(rollbackFor = Exception.class)private void addUserRole(Long userId, List<Long> roleIds) {if (CollectionUtils.isEmpty(roleIds)) {return;}List<UserRole> userRoles = new ArrayList<>();roleIds.forEach(roleId -> {UserRole userRole = new UserRole();userRole.setUserId(userId);userRole.setRoleId(roleId);userRoles.add(userRole);});userRoleDAO.insertBatch(userRoles);throw new RuntimeException("發生異常咯");}

你會發現只會同時插入失敗,無法實現上面所說的。這時候你可能會想到,既然addUserRole()拋出了異常不能插入用戶角色,但是addUser()不想受影響,正常添加用戶,那么何不在addUser()里面對userRoleService.addUserRole()進行異常捕獲,不就可以解決問題了嗎?真是如此嗎,就讓我們來驗證一下:

    @Transactional(rollbackFor = Exception.class)public void addUser(UserParam param) {User user = PtcBeanUtils.copy(param, User.class);// 添加用戶userDAO.insert(user);// 添加用戶角色try {userRoleService.addUserRole(user.getId(), param.getRoleIds());} catch (Exception e) {log.error(e.getMessage());}}

執行會發現,用戶同樣沒有添加成功,看日志報錯:

[1689568520410750976] [ERROR] [2023-08-10 17:25:02.023] [http-nio-18888-exec-1@56682]  com.plasticene.fast.service.impl.UserServiceImpl addUser : 發生異常咯
[1689568520410750976] [ERROR] [2023-08-10 17:25:02.097] [http-nio-18888-exec-1@56682]  com.plasticene.boot.web.core.global.GlobalExceptionHandler exceptionHandler : 【系統異常】
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-onlyat org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:870)

可以看到發生異常咯是我們在addUser()中捕獲到輸出的,但是緊接著下一行發現有報出一個異常UnexpectedRollbackException

原因是,主方法添加用戶的邏輯和子方法添加用戶角色的邏輯是同一個事務,子邏輯標記了事務需要回滾,主邏輯自然也不能提交了。

修正方式:其實要想新增用戶角色失敗不影響添加用戶,只需要讓新增用戶角色單獨開啟一個新事務即可。

   @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)public void addUserRole(Long userId, List<Long> roleIds) {List<UserRole> userRoles = new ArrayList<>();roleIds.forEach(roleId -> {UserRole userRole = new UserRole();userRole.setUserId(userId);userRole.setRoleId(roleId);userRoles.add(userRole);});userRoleDAO.insertBatch(userRoles);throw new RuntimeException("發生異常啦!");}

3.6 @Transactional長事務導致生產事故

很多開發都覺得Spring的聲明式事務使用非常簡單,即@Transactional,所以從來不注重細節。當 Spring 遇到該注解時,會自動從數據庫連接池中獲取 connection,并開啟事務然后綁定到 ThreadLocal 上,對于@Transactional注解包裹的整個方法都是使用同一個connection連接。如果我們出現了耗時的操作,比如第三方接口調用、業務邏輯復雜、大批量數據處理等就會導致我們我們占用這個connection的時間會很長,數據庫連接一直被占用不釋放。一旦類似操作過多,就會導致數據庫連接池耗盡。這就是典型的長事務問題

長事務引發的常見危害有:

  1. 數據庫連接池被占滿,應用無法獲取連接資源;
  2. 容易引發數據庫死鎖;
  3. 數據庫回滾時間長;
  4. 在主從架構中會導致主從延時變大。

服務系統開始出現故障:數據庫監控平臺一直收到告警短信,數據庫連接不足,出現大量死鎖;日志顯示調用流程引擎接口出現大量超時;同時一直提示CannotGetJdbcConnectionException,數據庫連接池連接占滿。

要想解決這個問題其實也不難,只需要對方法進行拆分,將不需要事務管理的邏輯與事務操作分開,這樣就可以有效控制事務的時長從而避免長事務。當然對一個方法邏輯拆分成多個子方法很有可能造成上面敘述的事務不生效的情況,不過我相信你看到上面的總結肯定沒問題啦。

4.總結

Spring的聲明式事務使用@Transactional注解在開發時確實很方便,但是稍有不慎使用不當就會導致事務失效數據不一致、甚至是系統數據庫性能問題。所以上面滿滿的干貨總結都是出自日常工作中碰到的,有效幫你避坑。

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

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

相關文章

uniapp條件編譯

uniapp條件編譯 uni-app 將已經將可以跨平臺兼容處理的組件及 API 等進行了封裝&#xff0c;但是部分平臺的特性無法跨平臺。 由此&#xff0c;uni-app 提供了條件編譯的方案&#xff0c;來處理不同平臺的特定或差異。 寫法 #ifdef&#xff1a; 僅在某平臺存在#ifndef&#xf…

Kafka 01——Kafka的安裝及簡單入門使用

Kafka 01——Kafka的安裝及簡單入門使用 1. 下載安裝1.1 JDK的安裝1.2 Zookeeper的安裝1.2.1 關于Zookeeper版本的選擇1.2.2 下載、安裝Zookeeper 1.3 kafka的安裝1.3.1 下載1.3.2 解壓1.3.3 修改配置文件 2. 啟動 kafka2.1 Kafka啟動2.2 啟動 kafka 遇到的問題2.2.1 問題12.2.…

Python愛心光波

文章目錄 前言Turtle入門簡單案例入門函數 愛心光波程序設計程序分析 尾聲 前言 七夕要來啦&#xff0c;博主在閑暇之余創作了一個愛心光波&#xff0c;感興趣的小伙伴們快來看看吧&#xff01; Turtle入門 Turtle 是一個簡單而直觀的繪圖工具&#xff0c;它可以幫助你通過簡…

面試筆記:Android 架構崗,一次4小時4面的體驗

作者&#xff1a;橘子樹 此次面試一共4面4小時&#xff0c;中間只有幾分鐘間隔。對持續的面試狀態考驗還是蠻大的。 關于面試的心態&#xff0c;保持悲觀的樂觀主義心態比較好。面前做面試準備時保持悲觀&#xff0c;盡可能的做足準備。面后積極做復盤&#xff0c;樂觀的接受最…

基于MIV的神經網絡變量篩選

1.案例背景 一般神經網絡中所包含的網絡輸人數據是研究者根據專業知識和經驗預先選擇好的,然而在許多實際應用中,由于沒有清晰的理論依據,神經網絡所包含的自變量即網絡輸入特征難以預先確定,如果將一些不重要的自變量也引入神經網絡,會降低模型的精度,因此選擇有意義的自變量特…

ECS服務器安裝docker

? 為了安裝并配置 Docker &#xff0c;你的系統必須滿足下列最低要求&#xff1a; 64 位 Linux 或 Windows 系統 如果使用 Linux &#xff0c;內核版本必須不低于 3.10 能夠使用 sudo 權限的用戶 在你系統 BIOS 上啟用了 VT&#xff08;虛擬化技術&#xff09;支持 on your s…

大數據課程I4——Kafka的零拷貝技術

文章作者郵箱&#xff1a;yugongshiyesina.cn 地址&#xff1a;廣東惠州 ▲ 本章節目的 ? 掌握Kafka的零拷貝技術&#xff1b; ? 了解常規的文件傳輸過程&#xff1b; 一、常規的網絡傳輸原理 表面上一個很簡單的網絡文件輸出的過程&#xff0c;在OS底層&…

【java】設計模式——單例模式

單例模式要點&#xff1a; 一個類只需要一個實例化對象&#xff1b;必須自行創建實例&#xff1b;必須自行向整個系統提供這個實例 實現&#xff1a; 只提供私有構造方法&#xff1b;有一個該類的靜態私有對象&#xff1b;提供一個靜態公有方法用于創建、獲取靜態私有對象&…

iOS_crash文件的獲取及符號化(解析)

文章目錄 1. 使用 symbolicatecrash 解析 .ips 文件&#xff1a;2. 使用 CrashSymbolicator.py 解析 ips 文件3. 使用 atos 解析 crash 文件4. Helps4.1 .ips 文件獲取4.2 .crash 文件獲取4.3 獲取 .dSYM 和 .app 文件4.4 使用 dwarfdump 查詢 uuid 5. Tips6. 總結 1. 使用 sym…

一百五十七、Kettle——Kettle最新的官網下載地址(之前的Kettle官網已經無法下載,真坑)

一、目的 之前使用的是kettle8.2&#xff0c;不需要額外下載pentaho-hadoop-shims-hdp30-8.2.2018.11.00-342.jar&#xff0c;因為kettle8.2本身自帶 但是kettle8.2在Linux上安裝后建立共享資源庫又有問題&#xff0c;沒辦法&#xff0c;只能換成kettle9.3 結果&#xff0c;k…

華為網絡篇 RIPv2的基礎配置-25

難度 1復雜度1 目錄 一、實驗原理 1.1 RIP的版本 1.2 RIP的路由更新方式 1.3 RIP的計時器 1.4 RIP的防環機制 二、實驗拓撲 三、實驗步驟 四、實驗過程 總結 一、實驗原理 RIP&#xff08;Routing Information Protocol&#xff0c;路由信息協議&#xff09;&am…

微服務概述-7

Shiro 框架 Shiro 是一個用于 Java 應用程序的安全框架。它提供了身份驗證、授權、加密和會話管理等功能&#xff0c;可以幫助開發人員構建安全可靠的應用程序。 Java 中針對權限管理常見的有 2 個著名的框架&#xff1a;spring security 和 shiro shiro 基本概念 credentia…

機器學習筆記 - 基于C++的??深度學習 二、實現卷積運算

一、卷積 卷積是信號處理領域的老朋友。最初的定義如下 在機器學習術語中: I(…)通常稱為輸入 K(…)作為內核,并且 F(…)作為給定K的I(x)的特征圖。 慮多維離散域,我們可以將積分轉換為以下求和 對于二維數字圖像,我們可以將其重寫為: <

編程練習(1)

目錄 一.選擇題 第一題&#xff1a; 第二題&#xff1a; 第三題&#xff1a; 第四題&#xff1a; 第五題&#xff1a; ?編輯 二.編程題 第一題&#xff1a; 第二題&#xff1a; 1.暴力方法&#xff1a; 2.數組法&#xff1a; 一.選擇題 第一題&#xff1a; 解析&…

【vue】簡潔優雅的火花線、趨勢線

來由 在github發現個好看易用的vue趨勢線組件&#xff0c;特此記錄。 效果 趨勢圖生成后效果如上&#xff0c;線條為漸變色&#xff0c;可設置是否平滑。具體線條走勢&#xff0c;根據數據動態生成。 使用 安裝 npm i vuetrend -S 引入 import Vue from "vue"…

MySQL性能分析之慢查詢日志查看

一、背景 MySQL的慢查詢日志是MySQL提供的一種日志記錄,他用來記錄在MySQL中響應的時間超過閾值的語句,具體指運行時間超過long_query_time(默認是10秒)值的SQL,會被記錄到慢查詢日志中。 慢查詢日志一般用于性能分析時開啟,收集慢SQL然后通過explain進行全面分析,一…

時序預測 | MATLAB實現WOA-CNN-BiLSTM鯨魚算法優化卷積雙向長短期記憶神經網絡時間序列預測

時序預測 | MATLAB實現WOA-CNN-BiLSTM鯨魚算法優化卷積雙向長短期記憶神經網絡時間序列預測 目錄 時序預測 | MATLAB實現WOA-CNN-BiLSTM鯨魚算法優化卷積雙向長短期記憶神經網絡時間序列預測預測效果基本介紹程序設計學習總結參考資料 預測效果 基本介紹 時序預測 | MATLAB實現…

Python案例|Pandas正則表達式

字符串的處理在數據清洗中占比很大。也就是說,很多不規則的數據處理都是在對字符串進行處理。Excel提供了拆分、提取、查找和替換等對字符串處理的技術。在Pandas中同樣提供了這些功能,并且在Pandas中還有正則表達式技術的加持,讓其字符串處理能力更加強大。 01、正則 正則就是…

TypeScript相關面試題

typeScript 1.什么是TypeScript?是什么&#xff1f;特性&#xff1f;區別&#xff1f; 2.TypeScript數據類型&#xff1f;3.說說你對 TypeScript 中枚舉類型的理解&#xff1f;應用場景&#xff1f;4.說說你對 TypeScript 中接口的理解&#xff1f;應用場景&#xff1f;使用方…

docker中的jenkins之流水線構建

docker中的jenkins之流水線構建項目 1、用node這種方式&#xff08;因為我用pipeline方式一直不執行&#xff0c;不知道為什么&#xff09; 2、創建項目 創建兩個參數&#xff0c;一個是宿主端口號&#xff0c;一個是docker中的端口號 3、使用git項目中的Jenkinsfile 4、編寫…