日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

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

來源: 責編: 時間:2024-04-24 17:33:08 210觀看
導讀在開發中,有時候我們需要對 Spring 事務的生命周期進行監控,比如在事務提交、回滾或掛起時觸發特定的邏輯處理。那么如何實現這種定制化操作呢?Spring 作為一個高度靈活和可擴展的框架,早就提供了一個強大的擴展點,即事務

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

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

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 是一個接口,它里面定義了一系列與事務各生命周期階段相關的方法。比如,我們可以這樣使用:g4r28資訊網——每日最新資訊28at.com

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 事務可以注冊多個事務同步器)。g4r28資訊網——每日最新資訊28at.com

需要注意的是注冊事務同步器必須得在一個 Spring 事務中才能注冊,否則會拋出 Transaction synchronization is not active 這個錯誤。g4r28資訊網——每日最新資訊28at.com

圖片圖片g4r28資訊網——每日最新資訊28at.com

isSynchronizationActive() 方法用來判斷當前是否存在事務(判斷線程共享變量,是否存在 TransactionSynchronization)g4r28資訊網——每日最新資訊28at.com

圖片圖片g4r28資訊網——每日最新資訊28at.com

Spring 在創建事務的時候,會初始化一個空集合放到 synchronizations 屬性中,所以只要當前存在事務,isSynchronizationActive()  就為 true。g4r28資訊網——每日最新資訊28at.com

TransactionSynchronizationManager 解析

Spring 對于事務的管理都是基于 TransactionSynchronizationManager 這個類,先看下 TransactionSynchronizationManager 的一些屬性:g4r28資訊網——每日最新資訊28at.com

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 中。圖片g4r28資訊網——每日最新資訊28at.com

然后標注到一個事務當中的其它數據庫操作就可以通過 TransactionSynchronizationManager#getResource 方法獲取到這個連接。g4r28資訊網——每日最新資訊28at.com

@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 事務操作是無法使用多線程的。g4r28資訊網——每日最新資訊28at.com

應用場景

TransactionSynchronization  可以用于一些需要在事務結束后執行清理操作或其他相關任務的場景。g4r28資訊網——每日最新資訊28at.com

應用場景舉例:g4r28資訊網——每日最新資訊28at.com

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

舉例:假設一個電商系統中存在訂單支付的業務場景,當用戶支付訂單時,需要在事務提交后發送訂單支付成功的消息通知給用戶。g4r28資訊網——每日最新資訊28at.com

由于事務是和數據庫連接相綁定的,如果把發送消息和數據庫操作放在一個事務里面。當發送消息時間過長時會占用數據庫連接,所以就要把數據庫操作與發送消息到 MQ 解耦開來。g4r28資訊網——每日最新資訊28at.com

這時就可以通過 TransactionSynchronization 來實現在事務提交后發送消息通知的功能。具體示例代碼如下:g4r28資訊網——每日最新資訊28at.com

@Componentpublic 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,并且不會占用數據庫連接資源。g4r28資訊網——每日最新資訊28at.com

@TransactionalEventListener

在 Spring Framework 4.2版本后還可以使用 @TransactionalEventListener 注解處理數據庫事務提交成功后的執行操作。g4r28資訊網——每日最新資訊28at.com

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@EventListenerpublic @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 更加優雅。它的使用方式如下:g4r28資訊網——每日最新資訊28at.com

@Datapublic class Order {    private Long orderId;    private String orderNumber;    private BigDecimal totalAmount;}@Servicepublic 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@Setterpublic class OrderCreatedEvent {    private Order order;    public OrderCreatedEvent(Order order) {        this.order = order;    }}@Component@Slf4jpublic 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());    }}

g4r28資訊網——每日最新資訊28at.com

本文鏈接:http://m.www897cc.com/showinfo-26-85225-0.html聊聊如何優雅地Spring事務編程

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 大白話講解Rust中令人頭痛的“所有權”

下一篇: 深入探索C++聯合體Union的神奇用法

標簽:
  • 熱門焦點
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
欧美日韩亚洲一区二区三区四区| 欧美在线3区| 精品999在线观看| 亚洲电影免费观看高清完整版在线| 亚洲国产精品一区二区第一页| 99riav1国产精品视频| 亚洲特级毛片| 久久久久久伊人| 欧美激情一区二区三区全黄 | 欧美亚洲一区三区| 久久久青草婷婷精品综合日韩| 欧美高清在线一区二区| 国产精品白丝黑袜喷水久久久| 亚洲午夜激情免费视频| 欧美在现视频| 欧美精品一区二区三区很污很色的| 国产精品高潮呻吟视频| 伊人久久婷婷色综合98网| 亚洲乱码久久| 欧美一区二区三区视频在线| 女人香蕉久久**毛片精品| 国产精品sm| 亚洲第一精品夜夜躁人人躁| 亚洲一区二区三区精品动漫| 麻豆成人精品| 国产精品有限公司| 亚洲精品永久免费| 久久国产毛片| 欧美性猛交99久久久久99按摩 | 亚洲国产精品传媒在线观看 | 久久久国产精品亚洲一区| 欧美日韩国产在线播放网站| 韩国成人精品a∨在线观看| 一本一本久久a久久精品牛牛影视| 久久av一区二区三区漫画| 欧美日韩一区在线视频| 在线成人中文字幕| 欧美色欧美亚洲高清在线视频| 国产日韩视频一区二区三区| 日韩亚洲视频| 久久综合色8888| 国产欧美成人| 99热免费精品| 欧美成人情趣视频| 激情五月***国产精品| 亚洲欧美日韩一区在线| 亚洲一区二区精品视频| 美女网站久久| 国产三级欧美三级| 亚洲小说欧美另类婷婷| 欧美另类在线播放| 亚洲第一页中文字幕| 久久精品电影| 国产伦精品一区二区三区视频黑人| 日韩一区二区福利| 欧美成人69| 在线观看日韩| 久久全国免费视频| 国产亚洲欧美日韩精品| 亚洲欧洲99久久| 国产精品高清在线观看| 夜久久久久久| 欧美久久久久久久久久| 亚洲国产另类 国产精品国产免费| 久久精品国产精品亚洲| 国产精品专区h在线观看| 亚洲伊人第一页| 欧美色大人视频| 99日韩精品| 欧美日韩精品一本二本三本| 亚洲精品欧美日韩| 欧美精品成人| 亚洲另类在线一区| 欧美人与性动交cc0o| 亚洲精品久久在线| 欧美片第一页| 亚洲最新合集| 欧美视频在线观看免费网址| 在线视频日韩| 国产精品第十页| 亚洲欧美一区二区精品久久久| 国产精品久久久久高潮| 亚洲免费在线| 国产亚洲精品aa| 久久久久久久91| 亚洲大胆人体在线| 欧美第一黄色网| 日韩午夜三级在线| 欧美视频精品一区| 亚洲欧洲99久久| 激情视频一区二区三区| 狂野欧美一区| 亚洲人成在线观看| 欧美日韩在线看| 亚洲欧美国产高清| 国产日韩欧美不卡| 久久偷看各类wc女厕嘘嘘偷窃| 亚洲第一级黄色片| 欧美精品九九99久久| 一区二区三区四区五区在线| 国产精品你懂的在线| 久久精品国产2020观看福利| 在线视频成人| 欧美日韩精品| 亚洲欧美日韩一区二区三区在线| 国产一区二区三区高清在线观看| 另类综合日韩欧美亚洲| 亚洲另类黄色| 国产精品美腿一区在线看| 欧美在线播放高清精品| 亚洲丶国产丶欧美一区二区三区| 欧美精品成人91久久久久久久| 亚洲视频在线看| 国产丝袜一区二区| 欧美成人a∨高清免费观看| 一区二区冒白浆视频| 国产欧美日本一区视频| 老色鬼精品视频在线观看播放| 亚洲美女av在线播放| 国产精品三级视频| 久久亚洲欧美| 9人人澡人人爽人人精品| 国产欧美日韩免费| 免费久久99精品国产| 中文高清一区| 韩曰欧美视频免费观看| 欧美区在线播放| 午夜欧美电影在线观看| 在线观看一区二区视频| 欧美丝袜一区二区| 久久精选视频| 一区二区av在线| 好看的日韩视频| 欧美日韩一区二区视频在线| 久久国产精品久久国产精品| 亚洲欧洲一区| 国产欧美日韩精品在线| 欧美激情久久久| 欧美一区永久视频免费观看| 最新日韩在线视频| 国产午夜精品久久久久久免费视| 欧美国产欧美亚洲国产日韩mv天天看完整 | 久久精品国产免费观看| 亚洲美女黄网| 国产一区二区三区丝袜| 欧美日韩ab片| 久久久蜜桃一区二区人| 亚洲视频视频在线| 亚洲电影免费| 国产日产欧美一区| 欧美日韩你懂的| 久久伊人一区二区| 午夜精品久久| 夜色激情一区二区| 亚洲国产精品女人久久久| 国产精品爽爽爽| 欧美日韩大陆在线| 久热这里只精品99re8久| 午夜精品av| 一本久久精品一区二区| 亚洲成人资源网| 国产一区二区三区丝袜| 欧美午夜在线| 欧美精品国产精品| 久久综合久久综合久久| 欧美一级淫片aaaaaaa视频| 一本久久综合亚洲鲁鲁| 亚洲高清自拍| 国内精品国语自产拍在线观看| 国产精品久久久久久久app| 欧美激情麻豆| 久久一区二区视频| 久久精品123| 小黄鸭视频精品导航| 亚洲午夜影视影院在线观看| 亚洲日韩中文字幕在线播放| 伊人一区二区三区久久精品| 国产日韩精品久久久| 国产精品美女一区二区| 欧美三区视频| 欧美日韩福利视频| 欧美激情一区| 欧美激情按摩| 欧美成人午夜激情在线| 玖玖视频精品| 久久躁狠狠躁夜夜爽| 久久精品视频在线播放| 性欧美18~19sex高清播放| 亚洲欧美日韩一区二区在线| 亚洲午夜高清视频| 亚洲视频成人| 亚洲桃花岛网站| 亚洲特色特黄| 亚洲小少妇裸体bbw| 一区二区三区鲁丝不卡| 一本色道久久综合亚洲精品不| 亚洲乱码久久| 欧美区在线观看| 欧美高清在线观看| 欧美精品激情| 欧美日韩情趣电影| 欧美日韩在线视频观看| 欧美午夜视频| 国产精品毛片a∨一区二区三区|