精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

聊聊如何優雅地Spring事務編程

開發 前端
Spring 作為一個高度靈活和可擴展的框架,早就提供了一個強大的擴展點,即事務同步器 TransactionSynchronization 。

在開發中,有時候我們需要對 Spring 事務的生命周期進行監控,比如在事務提交、回滾或掛起時觸發特定的邏輯處理。那么如何實現這種定制化操作呢?

Spring 作為一個高度靈活和可擴展的框架,早就提供了一個強大的擴展點,即事務同步器 TransactionSynchronization 。通過 TransactionSynchronization ,我們可以輕松地控制事務生命周期中的關鍵階段,實現自定義的業務邏輯與事務管理的結合。

package org.springframework.transaction.support;

import java.io.Flushable;

public interface TransactionSynchronization extends Flushable {
   /** 事務提交狀態 */
    int STATUS_COMMITTED = 0;
   /** 事務回滾狀態 */
    int STATUS_ROLLED_BACK = 1;
   /**系統異常狀態 */
    int STATUS_UNKNOWN = 2;
    //掛起該事務同步器
    default void suspend() {
    }
    //恢復事務同步器
    default void resume() {
    }
    //flush底層的session到數據庫
    default void flush() {
    }
   // 事務提交之前
    default void beforeCommit(boolean readOnly) {
    }
  // 操作完成之前(包含commit/rollback)
    default void beforeCompletion() {
    }
   // 事務提交之后
    default void afterCommit() {
    }
   // 操作完成之后(包含commit/rollback)
    default void afterCompletion(int status) {
    }
}

TransactionSynchronization 是一個接口,它里面定義了一系列與事務各生命周期階段相關的方法。比如,我們可以這樣使用:

public class UserService {

    @Transactional(rollbackFor = Exception.class)
    public void saveUser(User user) {
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                System.out.println("saveUser事務已提交...");
            }
        });
        userDao.saveUser(user);
    }
}

在 Spring 事務剛開始的時候,我們向 TransactionSynchronizationManager 事務同步管理器注冊了一個事務同步器,事務提交前/后,會遍歷執行事務同步器中對應的事務同步方法(一個 Spring 事務可以注冊多個事務同步器)。

需要注意的是注冊事務同步器必須得在一個 Spring 事務中才能注冊,否則會拋出 Transaction synchronization is not active 這個錯誤。

圖片圖片

isSynchronizationActive() 方法用來判斷當前是否存在事務(判斷線程共享變量,是否存在 TransactionSynchronization)

圖片圖片

Spring 在創建事務的時候,會初始化一個空集合放到 synchronizations 屬性中,所以只要當前存在事務,isSynchronizationActive()  就為 true。

TransactionSynchronizationManager 解析

Spring 對于事務的管理都是基于 TransactionSynchronizationManager 這個類,先看下 TransactionSynchronizationManager 的一些屬性:

private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal("Transactional resources");
    private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations = new NamedThreadLocal("Transaction synchronizations");
    private static final ThreadLocal<String> currentTransactionName = new NamedThreadLocal("Current transaction name");
    private static final ThreadLocal<Boolean> currentTransactionReadOnly = new NamedThreadLocal("Current transaction read-only status");
    private static final ThreadLocal<Integer> currentTransactionIsolationLevel = new NamedThreadLocal("Current transaction isolation level");
    private static final ThreadLocal<Boolean> actualTransactionActive = new NamedThreadLocal("Actual transaction active");
  • resources:保存連接資源,因為一個方法里面可能包含多個事務,所以就用 Map 來保存資源, key為 DataSource,value 為connectionHolder。線程可以通過該屬性獲取到同一個 Connection 對象。
  • synchronizations:事務同步器,是 Spring 交由程序員進行擴展的代碼,每個線程可以注冊N個事務同步器。
  • currentTransactionName:事務的名稱。
  • currentTransactionReadOnly:事務是否是只讀。
  • currentTransactionIsolationLevel:事務的隔離級別。
  • actualTransactionActive:用于保存當前事務是否還是 Active 狀態(事務是否開啟)。

Spring 創建事務時,DataSourceTransactionManager.doBegin 方法中,將新創建的 connection 包裝成 connectionHolder ,通過 TransactionSynchronizationManager#bindResource 方法存入 resources 中。圖片

然后標注到一個事務當中的其它數據庫操作就可以通過 TransactionSynchronizationManager#getResource 方法獲取到這個連接。

@Nullable
    public static Object getResource(Object key) {
        Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
        Object value = doGetResource(actualKey);
        if (value != null && logger.isTraceEnabled()) {
            logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
        }

        return value;
    }

    @Nullable
    private static Object doGetResource(Object actualKey) {
        Map<Object, Object> map = (Map)resources.get();
        if (map == null) {
            return null;
        } else {
            Object value = map.get(actualKey);
            if (value instanceof ResourceHolder && ((ResourceHolder)value).isVoid()) {
                map.remove(actualKey);
                if (map.isEmpty()) {
                    resources.remove();
                }

                value = null;
            }

            return value;
        }
    }

從上面我們也能看到,Spring 對于多個數據庫操作的事務實現是基于 ThreadLocal 的,所以 Spring 事務操作是無法使用多線程的。

應用場景

TransactionSynchronization  可以用于一些需要在事務結束后執行清理操作或其他相關任務的場景。

應用場景舉例:

  • 資源釋放:在事務提交或回滾后釋放資源,如關閉數據庫連接、釋放文件資源等。
  • 日志記錄:在事務結束后記錄相關日志信息,例如記錄事務的執行結果或異常情況。
  • 緩存更新:在事務完成后更新緩存數據,保持緩存和數據庫數據的一致性。
  • 消息通知:在事務結束后發送消息通知相關系統或用戶,如發送郵件或短信通知。

舉例:假設一個電商系統中存在訂單支付的業務場景,當用戶支付訂單時,需要在事務提交后發送訂單支付成功的消息通知給用戶。

由于事務是和數據庫連接相綁定的,如果把發送消息和數據庫操作放在一個事務里面。當發送消息時間過長時會占用數據庫連接,所以就要把數據庫操作與發送消息到 MQ 解耦開來。

這時就可以通過 TransactionSynchronization 來實現在事務提交后發送消息通知的功能。具體示例代碼如下:

@Component
public class OrderPaymentNotification implements TransactionSynchronization {

    private String orderNo;

    public OrderPaymentNotification(String orderNo) {
        this.orderNo = orderNo;
    }

    @Override
    public void beforeCommit(boolean readOnly) {
        // 在事務提交前不執行任何操作
    }

    @Override
    public void beforeCompletion() {
        // 在事務即將完成時不執行任何操作
    }

    @Override
    public void afterCommit() {
        // 在事務提交后發送訂單支付成功的消息通知
        sendMessage("訂單支付成功", orderNo);
    }

    @Override
    public void afterCompletion(int status) {
        // 在事務完成后不執行任何操作
    }

    private void sendMessage(String message, String orderNo) {
        // 發送消息通知的具體實現邏輯
        System.out.println(message + ": " + orderNo);
    }
}
@Transactional
    public void finishOrder(String orderNo) {
        // 修改訂單成功
        updateOrderSuccess(orderNo);
        // 發送消息到 MQ
        TransactionSynchronizationManager.registerSynchronization(new OrderPaymentNotification(orderNo));
    }

這樣當事務成功提交之后,就會把消息發送給 MQ,并且不會占用數據庫連接資源。

@TransactionalEventListener

在 Spring Framework 4.2版本后還可以使用 @TransactionalEventListener 注解處理數據庫事務提交成功后的執行操作。

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@EventListener
public @interface TransactionalEventListener {
    TransactionPhase phase() default TransactionPhase.AFTER_COMMIT;

    // 表明若沒有事務的時候,對應的event是否需要執行,默認值為false表示,沒事務就不執行了。
    boolean fallbackExecution() default false;

    @AliasFor(
        annotation = EventListener.class,
        attribute = "classes"
    )
    Class<?>[] value() default {};

    @AliasFor(
        annotation = EventListener.class,
        attribute = "classes"
    )
    Class<?>[] classes() default {};

    String condition() default "";
}



public enum TransactionPhase {
    // 在事務commit之前執行
    BEFORE_COMMIT,
    // 在事務commit之后執行
    AFTER_COMMIT,
    // 在事務rollback之后執行
    AFTER_ROLLBACK,
    // 在事務完成后執行(包括commit/rollback)
    AFTER_COMPLETION;

    private TransactionPhase() {
    }
}

從命名上可以直接看出,它就是個 EventListener,效果跟 TransactionSynchronization 一樣,但比 TransactionSynchronization 更加優雅。它的使用方式如下:

@Data
public class Order {

    private Long orderId;
    private String orderNumber;
    private BigDecimal totalAmount;
}

@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Transactional
    public void createOrder(Order order) {
        // 保存訂單邏輯
        System.out.println("Creating order: " + order.getOrderNumber());
        
        orderRepository.save(order);
        
        // 發布訂單創建事件
        OrderCreatedEvent orderCreatedEvent = new OrderCreatedEvent(order);
        eventPublisher.publishEvent(orderCreatedEvent);
    }
}

@Getter
@Setter
public class OrderCreatedEvent {

    private Order order;

    public OrderCreatedEvent(Order order) {
        this.order = order;
    }
}

@Component
@Slf4j
public class OrderEventListener {

    @Autowired
    private EmailService emailService;

    /*
     * @Async加了就是異步監聽,沒加就是同步(啟動類要開啟@EnableAsync注解)
     * 可以使用@Order定義監聽者順序,默認是按代碼書寫順序
     * 可以使用SpEL表達式來設置監聽器生效的條件
     * 監聽器可以看做普通方法,如果監聽器拋出異常,在publishEvent里處理即可
     */

    @Async
    @Order(1)
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, classes = OrderCreatedEvent.class)
    public void onOrderCreatedEvent(OrderCreatedEvent event) {
        // 處理訂單創建事件,例如發送郵件通知
        log.info("Received OrderCreatedEvent for order: " + event.getOrder().getOrderNumber());
        emailService.sendOrderConfirmationEmail(event.getOrder());
    }
}

責任編輯:武曉燕 來源: Java隨想錄
相關推薦

2023-05-12 14:14:00

Java線程中斷

2021-03-24 10:20:50

Fonts前端代碼

2022-04-11 08:17:07

JVMJava進程

2024-11-13 16:37:00

Java線程池

2022-05-13 21:20:23

組件庫樣式選擇器

2021-01-18 13:17:04

鴻蒙HarmonyOSAPP

2020-03-26 11:04:00

Linux命令光標

2021-05-12 22:07:43

并發編排任務

2020-03-27 15:10:23

SpringJava框架

2021-01-28 14:53:19

PHP編碼開發

2022-05-24 06:07:48

JShack用戶代碼

2023-06-28 08:25:14

事務SQL語句

2024-01-05 16:43:30

數據庫線程

2024-12-24 08:03:56

2020-12-08 08:08:51

Java接口數據

2021-09-08 08:34:37

Go 文檔Goland

2020-10-22 10:15:33

優化Windows電腦

2023-02-13 14:37:13

開發web瀏覽器

2018-08-20 10:40:09

Redis位圖操作

2024-11-08 13:13:58

點贊
收藏

51CTO技術棧公眾號

欧美日韩国产一区二区在线观看| 懂色av中文在线| 欧美激情精品久久久六区热门| 91精品国产免费| 日韩av图片| 91女人18毛片水多国产| 欧美天天视频| 亚洲人成电影在线播放| 亚洲黄色片免费看| 欧洲精品二区| 久久精品视频一区| 国产日韩中文字幕在线| 久久9999久久免费精品国产| 极品美女一区二区三区| 欧美一区二区性放荡片| 老太脱裤让老头玩ⅹxxxx| 91在线免费看| 99视频热这里只有精品免费| 国产精品亚洲激情| 国产精品自拍视频一区| 天天天综合网| 亚洲色图50p| 丰满少妇一区二区三区专区| 欧美人与性动交xxⅹxx| 一区二区在线观看视频在线观看| 裸体丰满少妇做受久久99精品| 一级黄色片在线| 国产精品久久久久毛片大屁完整版| 日韩最新免费不卡| 亚洲做受高潮无遮挡| 日本高清精品| 欧洲色大大久久| 波多野结衣之无限发射| 欧美成人三区| 国产午夜精品一区二区三区四区| 国产91aaa| 国产又黄又粗又长| 丝袜美腿成人在线| 18一19gay欧美视频网站| 538精品在线观看| 99久久精品费精品国产风间由美| 亚洲欧美日韩直播| 国产一级二级在线观看| 亚洲精品一区国产| 91精品国产91久久久久久最新毛片| 免费大片在线观看| 青青青免费在线视频| 亚洲蜜臀av乱码久久精品 | 欧美黑人又粗又大又爽免费| 精精国产xxxx视频在线野外| 亚洲不卡av一区二区三区| 美女在线免费视频| 国产秀色在线www免费观看| 国产精品网站在线观看| 日本在线成人一区二区| 国产黄在线看| 国产婷婷色一区二区三区在线| 久久久久久久久久码影片| 欧美在线精品一区二区三区| 国产成人免费xxxxxxxx| 99中文视频在线| 亚洲AV无码精品国产| 国产成人精品免费在线| 国产不卡一区二区三区在线观看| 亚洲精品成av人片天堂无码| 国产成人在线色| 5566中文字幕一区二区| 草逼视频免费看| 成人污视频在线观看| 春色成人在线视频| 五月婷婷六月色| 91在线一区二区| 欧美日韩国产不卡在线看| 欧美一区二区少妇| 国产午夜亚洲精品理论片色戒| 亚洲开发第一视频在线播放| 国产黄a三级三级三级av在线看 | 日韩不卡视频在线| 久久九九电影| 国产日韩欧美在线看| a天堂视频在线| 成人国产精品免费观看动漫| 久久国产一区| 成年人在线观看| 国产精品的网站| 日本aa在线观看| 麻豆免费版在线观看| 色婷婷亚洲精品| 色www免费视频| 91亚洲无吗| 亚洲精品一区二区久| 99久久久免费精品| 影院欧美亚洲| 国产精品无码专区在线观看| 性猛交xxxx乱大交孕妇印度| 久久久精品一品道一区| 伊人狠狠色丁香综合尤物| 国内在线视频| 欧美亚洲免费在线一区| 人妻换人妻仑乱| 亚洲精品国模| 九九精品在线播放| 99超碰在线观看| 国内精品不卡在线| 麻豆亚洲一区| 亚洲精品白浆| 欧美性三三影院| 99精品一区二区三区无码吞精| 精品国产网站| 久久久免费电影| 中文字幕乱码人妻无码久久| 国产aⅴ综合色| 色999五月色| av在线理伦电影| 欧美日韩中文字幕一区二区| 人妻无码中文久久久久专区| 日韩久久精品网| 欧美亚洲激情在线| 成人av一区二区三区在线观看| 久久久一区二区三区捆绑**| 日本天堂免费a| 精品福利在线| 亚洲天堂成人在线| 日产欧产va高清| 国产精品99久| 在线成人av电影| 免费观看一级欧美片| 日韩欧美成人午夜| 中文乱码字幕高清一区二区| 久久九九国产| 精品国产91亚洲一区二区三区www| 黄色网址免费在线观看| 在线观看日韩电影| 国产精品无码网站| 亚洲精品一级| 国产免费一区二区三区| 中文在线观看免费| 6080亚洲精品一区二区| 国产成人在线网址| 日产国产欧美视频一区精品| 欧美lavv| 性欧美gay| 亚洲免费视频一区二区| 黄网在线观看视频| 成人性色生活片| 国产尤物av一区二区三区| 亚洲欧美一级| 日韩视频永久免费观看| 91国产精品一区| 中文字幕亚洲视频| 午夜免费福利视频在线观看| 成人羞羞网站| 国产区精品视频| 91在线网址| 欧美电影一区二区三区| 国产成人免费在线观看视频| 另类小说视频一区二区| 亚洲一区尤物| 99精品美女视频在线观看热舞| 日韩视频在线一区| 国产aⅴ一区二区三区| 有码一区二区三区| 成年女人免费视频| 国产日韩欧美一区在线| 欧美人与性禽动交精品| 91在线成人| 日韩在线观看免费全| 国产情侣自拍小视频| 亚洲免费视频成人| 深夜福利网站在线观看| 亚洲午夜久久久久久尤物| 精品亚洲欧美日韩| 玛雅亚洲电影| 久久久精品久久久久| 亚洲天堂中文在线| 亚洲最新在线观看| 欧美日韩人妻精品一区在线| 久久久久久网| 一区二区三区四区欧美| 伊人久久亚洲| 5278欧美一区二区三区| 2017亚洲天堂1024| 欧美xingq一区二区| 亚洲精品77777| 国产三区在线成人av| 免费av不卡在线| 亚洲美女网站| 一区二区三区视频在线播放| 动漫av一区| 青草青草久热精品视频在线网站| a√资源在线| 欧美xxxxxxxxx| 最近中文字幕在线观看视频| 亚洲精品免费一二三区| www.中文字幕av| 国产一区不卡在线| 国产男女无遮挡| 888久久久| 美脚丝袜一区二区三区在线观看| 亚洲男女网站| 欧美综合激情网| h视频在线免费观看| 亚洲免费高清视频| 国内精品国产成人国产三级| 日韩欧中文字幕| 18岁成人毛片| 国产三级欧美三级| 永久免费未满蜜桃| 极品少妇xxxx精品少妇偷拍| 国产在线青青草| 欧美午夜影院| 午夜一区二区三视频在线观看| 91精品啪在线观看国产爱臀| 国产精品三级久久久久久电影| 嗯啊主人调教在线播放视频| 久久精品视频免费播放| 好吊色视频一区二区| 欧美综合亚洲图片综合区| 久久精品欧美一区二区| 中文字幕一区二区三区四区不卡| 国产传媒第一页| 国产精品自在在线| 国产日韩欧美久久| 久久综合婷婷| 日韩av一二三四区| 亚洲精品1区| 91免费国产精品| 欧美3p视频| 欧美精品人人做人人爱视频| av综合网站| 69174成人网| www.成人| 国产三级精品网站| 成人精品一区二区三区电影| 国产成人精品电影久久久| 日本不卡1234视频| 97国产在线视频| 欧美videossex| 欧美国产日韩中文字幕在线| 在线中文字幕第一页| xxxxxxxxx欧美| 在线免费看黄网站| 中国china体内裑精亚洲片| 国产午夜视频在线观看| 亚洲精选在线观看| 四虎在线免费观看| 亚洲精品大尺度| 亚洲人成色777777老人头| 亚洲第一免费网站| 噜噜噜久久,亚洲精品国产品| 日韩欧美国产一区在线观看| 精品国产乱码一区二区三| 337p亚洲精品色噜噜| 国产美女自慰在线观看| 91精品国产丝袜白色高跟鞋| 国产精品无码一区二区桃花视频| 欧美久久久一区| 91麻豆成人精品国产免费网站| 欧美日韩另类一区| 国产欧美日韩综合精品一区二区三区| 欧美高清视频一二三区 | 欧美日韩一区二区三区免费| 亚洲调教一区| 日韩不卡av| 999精品视频| 99久久99久久精品| 亚洲国产激情| 日韩黄色片视频| 日本伊人色综合网| 亚洲日本黄色片| 高清久久久久久| av网站有哪些| 中文字幕免费一区| 欧美三级日本三级| 亚洲成人tv网| 97人妻一区二区精品视频| 欧美日韩三级视频| 国产不卡精品视频| 亚洲娇小xxxx欧美娇小| 国产日本在线观看| 乱亲女秽乱长久久久| 136福利第一导航国产在线| 国产成人一区二区三区| 台湾天天综合人成在线| 成人午夜电影在线播放| 亚洲精品无吗| 亚洲欧洲精品一区二区| 在线中文字幕第一区| 欧美啪啪免费视频| 麻豆精品精品国产自在97香蕉| 久久久久亚洲av片无码v| 91片在线免费观看| 久久久久久久麻豆| 欧美日韩国产限制| 一区二区三区亚洲视频| 精品国产乱码久久久久久图片 | 久久精品国产96久久久香蕉| 黄页网站大全在线免费观看| 国产成人精品国内自产拍免费看| 欧美大片91| 日韩欧美一区二区三区四区五区| 女生裸体视频一区二区三区| 国产乱子夫妻xx黑人xyx真爽| 精品一区二区三区久久| 北岛玲一区二区| 亚洲婷婷在线视频| 五月天婷婷导航| 日韩欧美国产麻豆| 91在线品视觉盛宴免费| 97视频免费在线看| 精品国产亚洲一区二区在线观看| 蜜桃av噜噜一区二区三| 在线电影一区二区| 国产精品入口免费软件| av一二三不卡影片| 日韩一区二区不卡视频| 91极品美女在线| 性xxxx18| 欧美激情第99页| 9999精品| 亚洲一区二区三区涩| 国产一区二区三区的电影 | 一区二区三区麻豆| 亚洲国产精品嫩草影院久久| 国产一区久久精品| 国产精品日韩久久久久| 亚洲欧洲av| 日韩黄色片在线| 国产毛片精品一区| 又色又爽的视频| 在线亚洲高清视频| 日韩a在线看| 91精品国产91久久久久久吃药| 亚洲一区二区三区四区电影 | 黄色录像a级片| 亚洲高清视频在线| www.蜜臀av| 九色精品美女在线| 久久久久亚洲精品中文字幕| 一区二区三区四区在线视频| 蜜桃一区二区三区在线观看| 强伦人妻一区二区三区| 欧美性猛交xxxx乱大交蜜桃 | 国产精品一区二区三区av| 亚洲欧洲精品在线| 欧美aaa在线| 真实乱视频国产免费观看| 一本久道中文字幕精品亚洲嫩| 天堂91在线| 日韩美女视频在线观看| 九九精品在线| 9久久婷婷国产综合精品性色 | 国产精品亚洲d| 欧洲一区二区在线观看| 天堂成人国产精品一区| 亚洲精品午夜视频| 欧美视频三区在线播放| 第九色区av在线| 成人精品视频久久久久 | 自慰无码一区二区三区| 91视频免费观看| 中文字幕在线播| 中文字幕国产精品| 91精品国产自产观看在线| www国产无套内射com| 99国产精品一区| 日韩黄色在线播放| 国产亚洲日本欧美韩国| 欧美视频在线视频精品| 神马午夜伦理影院| 成人网男人的天堂| 影音先锋在线国产| 中文字幕亚洲欧美| 精品视频在线观看免费观看| 成人免费性视频| 久久综合久久综合久久| 亚洲图片欧美在线| 色综合久久天天综线观看| 秋霞影院一区二区三区| 爆乳熟妇一区二区三区霸乳| 亚洲三级在线免费观看| 少妇荡乳情欲办公室456视频| 国产成人极品视频| 一二三区不卡| 国产精品300页| 欧美日韩久久不卡| 高h视频在线播放| 日韩久久久久久久| 国产精品一区专区| 九九热在线免费观看| 日韩中文字幕在线看| 亚洲国产视频二区| 黄色一级大片在线观看| 亚洲免费在线播放| 国产色a在线| 福利精品视频| 美女免费视频一区二区| 亚洲国产精一区二区三区性色| 伊人久久男人天堂| av成人综合|