<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      springboot-@Transactional

      springboot @Transactional
       
      在 Spring Boot 中,@Transactional是聲明式事務(wù)管理的核心注解,用于簡(jiǎn)化事務(wù)控制邏輯。它基于 AOP(面向切面編程)實(shí)現(xiàn),通過注解聲明方法或類需要在事務(wù)中運(yùn)行,從而保證數(shù)據(jù)操作的原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability)(即 ACID 特性)。

      一、基本作用

      @Transactional的核心作用是:自動(dòng)為標(biāo)注的方法或類添加事務(wù)管理邏輯(如事務(wù)開啟、提交、回滾等),無需手動(dòng)編寫try-catchTransactionStatus相關(guān)代碼。

      二、使用位置

      • 方法上:僅對(duì)當(dāng)前方法生效。
      • 類上:對(duì)類中所有public 方法生效(方法上的注解會(huì)覆蓋類上的配置)。

      三、核心屬性

      @Transactional提供了多個(gè)屬性用于定制事務(wù)行為,常用屬性如下:
      屬性名作用可選值(常用)
      propagation 事務(wù)傳播行為(定義方法間事務(wù)的嵌套規(guī)則) REQUIRED(默認(rèn))、REQUIRES_NEWSUPPORTSMANDATORYNEVER
      isolation 事務(wù)隔離級(jí)別(解決并發(fā)問題:臟讀、不可重復(fù)讀、幻讀) DEFAULT(默認(rèn),使用數(shù)據(jù)庫隔離級(jí)別)、READ_COMMITTEDREPEATABLE_READ
      readOnly 是否為只讀事務(wù)(查詢操作建議設(shè)為true,優(yōu)化性能) true/false(默認(rèn)false
      rollbackFor 指定哪些異常觸發(fā)事務(wù)回滾(默認(rèn)僅對(duì)RuntimeExceptionError回滾) 異常類數(shù)組(如{Exception.class}
      noRollbackFor 指定哪些異常不觸發(fā)事務(wù)回滾 異常類數(shù)組(如{BusinessException.class}
      timeout 事務(wù)超時(shí)時(shí)間(超過時(shí)間未完成則回滾,單位:秒) 整數(shù)(默認(rèn)-1,表示不超時(shí))

      1. 事務(wù)傳播行為(propagation)

      定義多個(gè)事務(wù)方法嵌套調(diào)用時(shí),事務(wù)的創(chuàng)建 / 關(guān)聯(lián)規(guī)則(最常用的兩個(gè)):
      • REQUIRED(默認(rèn)):如果當(dāng)前存在事務(wù),則加入該事務(wù);如果沒有,則新建一個(gè)事務(wù)。
         
        例:ServiceA.methodA(帶事務(wù))調(diào)用 ServiceB.methodB(REQUIRED),methodB 會(huì)加入 methodA 的事務(wù),若 methodB 失敗,整個(gè)事務(wù)回滾。
      • REQUIRES_NEW:無論當(dāng)前是否有事務(wù),都新建一個(gè)事務(wù);原事務(wù)會(huì)被掛起,直到新事務(wù)完成。
         
        例:methodA(事務(wù))調(diào)用 methodB(REQUIRES_NEW),methodB 的事務(wù)獨(dú)立,即使 methodB 失敗,僅回滾自身,不影響 methodA 的事務(wù)。

      2. 事務(wù)隔離級(jí)別(isolation)

      解決并發(fā)場(chǎng)景下的事務(wù)沖突問題(依賴數(shù)據(jù)庫支持):
      • DEFAULT:使用數(shù)據(jù)庫默認(rèn)隔離級(jí)別(MySQL 默認(rèn)REPEATABLE_READ,Oracle 默認(rèn)READ_COMMITTED)。
      • READ_COMMITTED:只能讀取已提交的數(shù)據(jù),避免臟讀(讀取未提交的數(shù)據(jù))。
      • REPEATABLE_READ:保證多次讀取同一數(shù)據(jù)結(jié)果一致,避免不可重復(fù)讀(兩次讀取數(shù)據(jù)不一致)。
      • SERIALIZABLE:最高隔離級(jí)別,完全串行化執(zhí)行,避免幻讀(讀取到新增的數(shù)據(jù)),但性能最差。

      四、使用示例

      java
       
      運(yùn)行
       
       
       
       
      @Service
      public class UserService {
      
          @Autowired
          private UserMapper userMapper;
      
          // 聲明事務(wù):傳播行為REQUIRED,對(duì)所有Exception回滾,超時(shí)30秒
          @Transactional(propagation = Propagation.REQUIRED, 
                         rollbackFor = Exception.class, 
                         timeout = 30)
          public void transferMoney(Long fromId, Long toId, BigDecimal amount) throws Exception {
              // 扣錢
              userMapper.decreaseBalance(fromId, amount);
              // 模擬異常(如網(wǎng)絡(luò)波動(dòng))
              if (amount.compareTo(new BigDecimal("10000")) > 0) {
                  throw new Exception("轉(zhuǎn)賬金額過大"); // 觸發(fā)回滾
              }
              // 加錢
              userMapper.increaseBalance(toId, amount);
          }
      }
      
       

      五、注意事項(xiàng)(避坑點(diǎn))

      1. 僅對(duì) public 方法生效:Spring AOP 默認(rèn)只代理public方法,非public方法(如privateprotected)的@Transactional會(huì)失效。
      2. 自調(diào)用事務(wù)失效:同一類中,無事務(wù)的方法 A 調(diào)用有事務(wù)的方法 B 時(shí),B 的事務(wù)會(huì)失效(因未經(jīng)過 Spring 代理對(duì)象)。解決:注入自身代理對(duì)象(@Autowired private UserService self;),通過self.methodB()調(diào)用。
      3. 異常被捕獲會(huì)導(dǎo)致回滾失效:若方法內(nèi)部捕獲異常且未重新拋出(如try-catch后不throw),Spring 無法感知異常,事務(wù)不會(huì)回滾。解決:捕獲后需重新拋出異常(如throw new RuntimeException(e))。
      4. 數(shù)據(jù)庫引擎支持:事務(wù)依賴數(shù)據(jù)庫支持,例如 MySQL 的MyISAM引擎不支持事務(wù),需使用InnoDB
      5. rollbackFor 默認(rèn)行為:默認(rèn)僅對(duì)RuntimeException(非檢查異常)和Error回滾,對(duì)Exception(檢查異常,如IOException)不回滾。若需對(duì)檢查異常回滾,需顯式指定rollbackFor = Exception.class

      總結(jié)

      @Transactional是 Spring Boot 中簡(jiǎn)化事務(wù)管理的核心工具,通過合理配置傳播行為、隔離級(jí)別等屬性,并規(guī)避使用中的常見問題,可有效保證數(shù)據(jù)操作的一致性。
       
      @Transactional 事務(wù)注入案例
       
      下面通過一個(gè)訂單創(chuàng)建與庫存扣減的業(yè)務(wù)場(chǎng)景,展示@Transactional事務(wù)注入(即事務(wù)在多個(gè)組件 / 方法間的傳播與協(xié)同)的具體案例。該案例將包含 Service 間調(diào)用、事務(wù)傳播行為的實(shí)際效果,以及常見問題的對(duì)比。

      場(chǎng)景說明

      業(yè)務(wù)流程:用戶創(chuàng)建訂單時(shí),需要完成兩個(gè)核心操作 ——?jiǎng)?chuàng)建訂單記錄和扣減商品庫存。這兩個(gè)操作必須在同一個(gè)事務(wù)中:要么都成功,要么都失敗(例如庫存不足時(shí),訂單需回滾)。額外需求:無論訂單創(chuàng)建成功與否,都需要記錄操作日志(日志記錄需獨(dú)立事務(wù),不受主事務(wù)影響)。

      技術(shù)依賴

      • Spring Boot 2.7.x
      • MyBatis(數(shù)據(jù)訪問,也可替換為 JPA)
      • MySQL(InnoDB 引擎,支持事務(wù))

      代碼實(shí)現(xiàn)

      1. 實(shí)體類

      java
       
      運(yùn)行
       
       
       
       
      // 訂單實(shí)體
      @Data
      public class Order {
          private Long id;
          private Long userId;
          private Long productId;
          private Integer quantity; // 購買數(shù)量
          private LocalDateTime createTime;
      }
      
      // 商品實(shí)體(庫存)
      @Data
      public class Product {
          private Long id;
          private String name;
          private Integer stock; // 庫存數(shù)量
      }
      
      // 操作日志實(shí)體
      @Data
      public class OperateLog {
          private Long id;
          private String content; // 日志內(nèi)容
          private LocalDateTime createTime;
      }
      
       

      2. 數(shù)據(jù)訪問層(Mapper)

      java
       
      運(yùn)行
       
       
       
       
      // 訂單Mapper
      @Mapper
      public interface OrderMapper {
          // 插入訂單
          @Insert("INSERT INTO `order`(user_id, product_id, quantity, create_time) " +
                  "VALUES(#{userId}, #{productId}, #{quantity}, #{createTime})")
          void insert(Order order);
      }
      
      // 商品Mapper
      @Mapper
      public interface ProductMapper {
          // 扣減庫存(where條件確保庫存充足時(shí)才扣減)
          @Update("UPDATE product SET stock = stock - #{quantity} " +
                  "WHERE id = #{productId} AND stock >= #{quantity}")
          int decreaseStock(@Param("productId") Long productId, @Param("quantity") Integer quantity);
      
          // 查詢商品
          @Select("SELECT * FROM product WHERE id = #{id}")
          Product selectById(Long id);
      }
      
      // 日志Mapper
      @Mapper
      public interface OperateLogMapper {
          @Insert("INSERT INTO operate_log(content, create_time) VALUES(#{content}, #{createTime})")
          void insert(OperateLog log);
      }
      
       

      3. Service 層(核心事務(wù)邏輯)

      3.1 庫存服務(wù)(ProductService)
      負(fù)責(zé)扣減庫存,聲明事務(wù)(默認(rèn)傳播行為REQUIRED,加入調(diào)用者的事務(wù))。
      java
       
      運(yùn)行
       
       
       
       
      @Service
      public class ProductService {
      
          @Autowired
          private ProductMapper productMapper;
      
          /**
           * 扣減庫存(事務(wù)傳播行為:REQUIRED,默認(rèn))
           * 若庫存不足,拋出異常觸發(fā)回滾
           */
          @Transactional
          public void decreaseStock(Long productId, Integer quantity) {
              // 扣減庫存(返回影響行數(shù),0表示庫存不足)
              int rows = productMapper.decreaseStock(productId, quantity);
              if (rows == 0) {
                  // 庫存不足,拋出異常(會(huì)被上層事務(wù)捕獲并觸發(fā)回滾)
                  throw new RuntimeException("商品庫存不足");
              }
          }
      }
      
       
      3.2 日志服務(wù)(LogService)
      負(fù)責(zé)記錄日志,使用REQUIRES_NEW傳播行為,確保日志事務(wù)獨(dú)立(不受主事務(wù)影響)。
      java
       
      運(yùn)行
       
       
       
       
      @Service
      public class LogService {
      
          @Autowired
          private OperateLogMapper logMapper;
      
          /**
           * 記錄日志(事務(wù)傳播行為:REQUIRES_NEW,獨(dú)立事務(wù))
           */
          @Transactional(propagation = Propagation.REQUIRES_NEW)
          public void recordLog(String content) {
              OperateLog log = new OperateLog();
              log.setContent(content);
              log.setCreateTime(LocalDateTime.now());
              logMapper.insert(log);
          }
      }
      
       
      3.3 訂單服務(wù)(OrderService)
      核心業(yè)務(wù)邏輯:創(chuàng)建訂單 + 調(diào)用庫存服務(wù)扣減庫存 + 調(diào)用日志服務(wù)記錄日志。聲明事務(wù)(REQUIRED),確保訂單創(chuàng)建和庫存扣減在同一事務(wù)中。
      java
       
      運(yùn)行
       
       
       
       
      @Service
      public class OrderService {
      
          @Autowired
          private OrderMapper orderMapper;
      
          @Autowired
          private ProductService productService; // 注入庫存服務(wù)(事務(wù)協(xié)同)
      
          @Autowired
          private LogService logService; // 注入日志服務(wù)(獨(dú)立事務(wù))
      
          /**
           * 創(chuàng)建訂單(主事務(wù):REQUIRED)
           * 流程:扣減庫存 -> 創(chuàng)建訂單 -> 記錄日志(成功/失敗)
           */
          @Transactional(rollbackFor = Exception.class) // 對(duì)所有異常回滾
          public void createOrder(Long userId, Long productId, Integer quantity) {
              String logContent;
              try {
                  // 1. 扣減庫存(調(diào)用ProductService,加入當(dāng)前事務(wù))
                  productService.decreaseStock(productId, quantity);
      
                  // 2. 創(chuàng)建訂單(與扣減庫存同事務(wù))
                  Order order = new Order();
                  order.setUserId(userId);
                  order.setProductId(productId);
                  order.setQuantity(quantity);
                  order.setCreateTime(LocalDateTime.now());
                  orderMapper.insert(order);
      
                  logContent = "訂單創(chuàng)建成功:用戶" + userId + "購買商品" + productId + ",數(shù)量" + quantity;
              } catch (Exception e) {
                  // 3. 若異常(如庫存不足),記錄失敗日志
                  logContent = "訂單創(chuàng)建失敗:" + e.getMessage();
                  throw e; // 關(guān)鍵:必須重新拋出異常,否則主事務(wù)不會(huì)回滾!
              } finally {
                  // 4. 記錄日志(調(diào)用LogService,獨(dú)立事務(wù),無論成敗都會(huì)執(zhí)行)
                  logService.recordLog(logContent);
              }
          }
      }
      
       

      4. Controller 層(接口調(diào)用)

      java
       
      運(yùn)行
       
       
       
       
      @RestController
      @RequestMapping("/orders")
      public class OrderController {
      
          @Autowired
          private OrderService orderService;
      
          @PostMapping
          public String createOrder(
                  @RequestParam Long userId,
                  @RequestParam Long productId,
                  @RequestParam Integer quantity) {
              try {
                  orderService.createOrder(userId, productId, quantity);
                  return "訂單創(chuàng)建成功";
              } catch (Exception e) {
                  return "訂單創(chuàng)建失敗:" + e.getMessage();
              }
          }
      }
      
       

      事務(wù)注入效果測(cè)試

      測(cè)試 1:正常流程(庫存充足)

      • 操作:調(diào)用接口,購買庫存充足的商品(如商品 A 庫存 100,購買 10)。
      • 結(jié)果:
        • 庫存扣減成功(100→90)。
        • 訂單表新增一條記錄。
        • 日志表新增一條 “成功” 日志。
        • 所有操作在事務(wù)中完成,數(shù)據(jù)一致。

      測(cè)試 2:異常流程(庫存不足)

      • 操作:調(diào)用接口,購買庫存不足的商品(如商品 A 庫存 5,購買 10)。
      • 結(jié)果:
        • ProductService.decreaseStock扣減庫存失敗,拋出RuntimeException
        • OrderService.createOrder捕獲異常后重新拋出,觸發(fā)主事務(wù)回滾:訂單記錄不會(huì)插入數(shù)據(jù)庫。
        • LogService.recordLogREQUIRES_NEW,獨(dú)立事務(wù)提交:日志表新增一條 “失敗” 日志。
        • 最終狀態(tài):庫存不變,無訂單,有失敗日志(符合業(yè)務(wù)預(yù)期)。

      測(cè)試 3:驗(yàn)證事務(wù)傳播行為

      • LogService.recordLog使用默認(rèn)REQUIRED傳播行為:
         
        當(dāng)主事務(wù)回滾時(shí),日志的插入也會(huì)被回滾(不符合 “必須記錄日志” 的需求)。
         
        這就是REQUIRES_NEW的作用 —— 強(qiáng)制新建事務(wù),確保日志獨(dú)立。

      關(guān)鍵注意點(diǎn)

      1. 事務(wù)注入的核心是傳播行為:多個(gè) Service 方法調(diào)用時(shí),propagation屬性決定事務(wù)是否共享、新建或掛起(如案例中REQUIREDREQUIRES_NEW的區(qū)別)。
      2. 異常必須拋出:OrderServicecatch異常后必須throw e,否則 Spring 無法感知異常,主事務(wù)不會(huì)回滾(這是最常見的坑)。
      3. 避免自調(diào)用失效:若OrderService中一個(gè)無事務(wù)的方法 A 調(diào)用自身有事務(wù)的方法 B,B 的事務(wù)會(huì)失效(需通過@Autowired注入自身代理對(duì)象調(diào)用)。
      4. 數(shù)據(jù)庫支持:確保使用 InnoDB 引擎(MyISAM 不支持事務(wù))。
      通過這個(gè)案例可以清晰看到:@Transactional通過 “注入”(即不同 Service 間的調(diào)用)實(shí)現(xiàn)了事務(wù)的協(xié)同管理,既保證了核心業(yè)務(wù)的原子性,又通過傳播行為滿足了特殊場(chǎng)景(如獨(dú)立日志)的需求。
      posted @ 2025-10-28 08:27  hanease  閱讀(10)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 亚洲精品乱码久久久久久蜜桃| 国产精品色悠悠在线观看| 二区三区亚洲精品国产| 久久视频这里只精品| 99久久婷婷国产综合精品青草漫画| 国内自拍av在线免费| 精品国产精品中文字幕| 无码一区二区三区免费| 9久9久热精品视频在线观看| 99热久久这里只有精品| 亚洲经典在线中文字幕| 性人久久久久| 久久精品道一区二区三区| 午夜福利精品国产二区| 4hu44四虎www在线影院麻豆| 99RE6在线观看国产精品| 国产免费一区二区不卡| 久久发布国产伦子伦精品| 亚洲国产精品久久久久婷婷图片| 国产精品九九久久精品女同| 国产精品乱码人妻一区二区三区 | 无码人妻精品一区二区三区夜夜嗨| 亚洲欧美人成人让影院| 久久精品国产精品亚洲综合| 午夜激情福利一区二区| 中文字幕国产精品资源| 亚洲精品国产自在现线最新| 西西人体44WWW高清大胆| 偏关县| 亚洲熟妇自偷自拍另亚洲| 亚洲日本va午夜在线电影| 久久久久久亚洲精品成人| 亚洲激情在线一区二区三区| 东京热一精品无码av| 国产情侣激情在线对白| 一区二区三区日本久久九| 亚洲精品亚洲人成人网| 水蜜桃精品综合视频在线| 国内精品视频区在线2021 | 国产熟女一区二区三区四区| 国产亚洲一二三区精品|