最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用@TransactionalEventListener監(jiān)聽事務(wù)教程

 更新時(shí)間:2021年09月16日 09:24:32   作者:shiliang_feng  
這篇文章主要介紹了使用@TransactionalEventListener監(jiān)聽事務(wù)教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

@TransactionalEventListener監(jiān)聽事務(wù)

項(xiàng)目背景

最近在項(xiàng)目遇到一個(gè)問題

A方法體內(nèi)有 INSERT、UPDATE或者DELETE操作,最后會(huì)發(fā)送一段MQ給外部,外部接收到MQ后會(huì)再發(fā)送一段請(qǐng)求過來,系統(tǒng)收到請(qǐng)求后會(huì)執(zhí)行B方法,B方法會(huì)依賴A方法修改后的結(jié)果,這就有一個(gè)問題,如果A方法事務(wù)沒有提交;且B方法的請(qǐng)求過來了會(huì)查詢到事務(wù)未提交前的狀態(tài),這就會(huì)有問題

解決辦法:@TransactionalEventListener

在Spring4.2+,有一種叫做TransactionEventListener的方式,能夠控制在事務(wù)的時(shí)候Event事件的處理方式。 我們知道,Spring的發(fā)布訂閱模型實(shí)際上并不是異步的,而是同步的來將代碼進(jìn)行解耦。而TransactionEventListener仍是通過這種方式,只不過加入了回調(diào)的方式來解決,這樣就能夠在事務(wù)進(jìn)行Commited,Rollback…等的時(shí)候才會(huì)去進(jìn)行Event的處理。

具體實(shí)現(xiàn)

//創(chuàng)建一個(gè)事件類
package com.qk.cas.config;
import org.springframework.context.ApplicationEvent;
public class MyTransactionEvent extends ApplicationEvent {
    private static final long serialVersionUID = 1L;
    private IProcesser processer;
    public MyTransactionEvent(IProcesser processer) {
        super(processer);
        this.processer = processer;
    }
    public IProcesser getProcesser() {
        return this.processer;
    }
    @FunctionalInterface
    public interface IProcesser {
        void handle();
    }
}
//創(chuàng)建一個(gè)監(jiān)聽類
package com.qk.cas.config;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
@Component
public class MyTransactionListener {
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void hanldeOrderCreatedEvent(MyTransactionEvent event) {
        event.getProcesser().handle();
    }
}
//MQ方法的變動(dòng)
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    @Autowired
    private AmqpTemplate rabbitTemplate;
    public void sendCreditResult(String applyNo, String jsonString) {
        eventPublisher.publishEvent(new MyTransactionEvent(() -> {
            LOGGER.info("MQ。APPLY_NO:[{}]。KEY:[{}]。通知報(bào)文:[{}]", applyNo, Queues.CREDIT_RESULT, jsonString);
            rabbitTemplate.convertAndSend(Queues.CREDIT_RESULT, jsonString);
        }));
    }

拓展

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) 只有當(dāng)前事務(wù)提交之后,才會(huì)執(zhí)行事件監(jiān)聽的方法,其中參數(shù)phase默認(rèn)為AFTER_COMMIT,共有四個(gè)枚舉:

public enum TransactionPhase {
    /**
     * Fire the event before transaction commit.
     * @see TransactionSynchronization#beforeCommit(boolean)
     */
    BEFORE_COMMIT,
    /**
     * Fire the event after the commit has completed successfully.
     * <p>Note: This is a specialization of {@link #AFTER_COMPLETION} and
     * therefore executes in the same after-completion sequence of events,
     * (and not in {@link TransactionSynchronization#afterCommit()}).
     * @see TransactionSynchronization#afterCompletion(int)
     * @see TransactionSynchronization#STATUS_COMMITTED
     */
    AFTER_COMMIT,
    /**
     * Fire the event if the transaction has rolled back.
     * <p>Note: This is a specialization of {@link #AFTER_COMPLETION} and
     * therefore executes in the same after-completion sequence of events.
     * @see TransactionSynchronization#afterCompletion(int)
     * @see TransactionSynchronization#STATUS_ROLLED_BACK
     */
    AFTER_ROLLBACK,
    /**
     * Fire the event after the transaction has completed.
     * <p>For more fine-grained events, use {@link #AFTER_COMMIT} or
     * {@link #AFTER_ROLLBACK} to intercept transaction commit
     * or rollback, respectively.
     * @see TransactionSynchronization#afterCompletion(int)
     */
    AFTER_COMPLETION
}

注解@TransactionalEventListener

例如 用戶注冊(cè)之后需要計(jì)算用戶的邀請(qǐng)關(guān)系,遞歸操作。如果注冊(cè)的時(shí)候包含多步驗(yàn)證,生成基本初始化數(shù)據(jù),這時(shí)候我們通過mq發(fā)送消息來處理這個(gè)邀請(qǐng)關(guān)系,會(huì)出現(xiàn)一個(gè)問題,就是用戶還沒注冊(cè)數(shù)據(jù)還沒入庫,邀請(qǐng)關(guān)系就開始執(zhí)行,但是查不到數(shù)據(jù),導(dǎo)致出錯(cuò)。

@TransactionalEventListener 可以實(shí)現(xiàn)事務(wù)的監(jiān)聽,可以在提交之后再進(jìn)行操作。

監(jiān)聽的對(duì)象

package com.jinglitong.springshop.interceptor; 
import com.jinglitong.springshop.entity.Customer;
import org.springframework.context.ApplicationEvent;
  
public class RegCustomerEvent extends ApplicationEvent{
    public RegCustomerEvent(Customer customer){
        super(customer);
    }
}

監(jiān)聽到之后的操作

package com.jinglitong.springshop.interceptor; 
import com.alibaba.fastjson.JSON;
import com.jinglitong.springshop.entity.Customer;
import com.jinglitong.springshop.entity.MqMessageRecord;
import com.jinglitong.springshop.servcie.MqMessageRecordService;
import com.jinglitong.springshop.util.AliMQServiceUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;  
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
 
@Component
@Slf4j
public class RegCustomerListener {
 
    @Value("${aliyun.mq.order.topic}")
    private String topic;
 
    @Value("${aliyun.mq.regist.product}")
    private String registGroup;
 
    @Value("${aliyun.mq.regist.tag}")
    private String registTag;
 
    @Autowired
    MqMessageRecordService mqMessageRecordService;
 
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void hanldeRegCustomerEvent(RegCustomerEvent regCustomerEvent) {
        Customer cust = (Customer) regCustomerEvent.getSource();
        Map<String, String> map = new HashMap<String, String>();
        map.put("custId", cust.getZid());
        map.put("account", cust.getAccount());
        log.info("put regist notice to Mq start");
        String hdResult = AliMQServiceUtil.createNewOrder(cust.getZid(), JSON.toJSONString(map),topic,registTag,registGroup);
        MqMessageRecord insert = buidBean(cust.getZid(),hdResult,registTag,JSON.toJSONString(map),registGroup);
        if(StringUtils.isEmpty(hdResult)) {
            insert.setStatus(false);
        }else {
            insert.setStatus(true);
        }
        mqMessageRecordService.insertRecord(insert);
        log.info("put regist notice to Mq end");
        log.info("regist notice userId : " + cust.getAccount());
    }
 
    private MqMessageRecord buidBean (String custId,String result ,String tag,String jsonStr,String groupId) {
        MqMessageRecord msg = new MqMessageRecord();
        msg.setFlowId(custId);
        msg.setGroupName(groupId);
        msg.setTopic(topic);
        msg.setTag(tag);
        msg.setMsgId(result);
        msg.setDataBody(jsonStr);
        msg.setSendType(3);
        msg.setGroupType(1);
        msg.setCreateTime(new Date());
        return msg;
    } 
}
@Autowired
    private ApplicationEventPublisher applicationEventPublisher;
 
applicationEventPublisher.publishEvent(new RegCustomerEvent (XXX));

這樣可以確保數(shù)據(jù)入庫之后再進(jìn)行異步計(jì)算

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • kafka 重新分配partition和調(diào)整replica的數(shù)量實(shí)現(xiàn)

    kafka 重新分配partition和調(diào)整replica的數(shù)量實(shí)現(xiàn)

    當(dāng)需要提升Kafka集群的性能和負(fù)載均衡時(shí),可通過kafka-reassign-partitions.sh命令手動(dòng)重新分配Partition,增加節(jié)點(diǎn)后,可以將Topic的Partition的Leader節(jié)點(diǎn)均勻分布,以提高寫入和消費(fèi)速度,感興趣的可以了解一下
    2022-03-03
  • SpringBoot靜態(tài)資源css,js,img配置方案

    SpringBoot靜態(tài)資源css,js,img配置方案

    這篇文章主要介紹了SpringBoot靜態(tài)資源css,js,img配置方案,下文給大家分享了三種解決方案,需要的朋友可以參考下
    2017-07-07
  • SpringBoot中@KafkaListener使用${}動(dòng)態(tài)指定topic問題

    SpringBoot中@KafkaListener使用${}動(dòng)態(tài)指定topic問題

    在SpringKafka中,使用${}引用Spring屬性配置,可以在不同環(huán)境中重新配置topic名稱,而無需修改代碼,在application.properties或application.yml中定義topic名稱,并在代碼中使用${}引用
    2024-12-12
  • 詳解關(guān)于java文件下載文件名亂碼問題解決方案

    詳解關(guān)于java文件下載文件名亂碼問題解決方案

    這篇文章主要介紹了詳解關(guān)于java文件下載文件名亂碼問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • 解決grails服務(wù)端口沖突的辦法(grails修改端口號(hào))

    解決grails服務(wù)端口沖突的辦法(grails修改端口號(hào))

    grails中默認(rèn)的服務(wù)端口為8080,當(dāng)本機(jī)中需要同時(shí)啟動(dòng)兩個(gè)不同的項(xiàng)目時(shí),就會(huì)造成端口沖突,下面給出解決方法
    2013-12-12
  • 使用Idea maven創(chuàng)建Spring項(xiàng)目過程圖解

    使用Idea maven創(chuàng)建Spring項(xiàng)目過程圖解

    這篇文章主要介紹了使用Idea maven創(chuàng)建Spring項(xiàng)目過程圖解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • MyBatis中動(dòng)態(tài)SQL的使用指南

    MyBatis中動(dòng)態(tài)SQL的使用指南

    MyBatis 是一個(gè)流行的持久層框架,它通過 XML 或注解將接口方法與 SQL 映射在一起,動(dòng)態(tài) SQL 是 MyBatis 的一大特性,它使得構(gòu)建靈活的查詢變得簡(jiǎn)單,本文將通過一個(gè) User 表的示例,介紹 MyBatis 中常用的動(dòng)態(tài) SQL 方法,需要的朋友可以參考下
    2024-09-09
  • 使用bitset實(shí)現(xiàn)毫秒級(jí)查詢(實(shí)例講解)

    使用bitset實(shí)現(xiàn)毫秒級(jí)查詢(實(shí)例講解)

    下面小編就為大家?guī)硪黄褂胋itset實(shí)現(xiàn)毫秒級(jí)查詢(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • Activiti開發(fā)環(huán)境的搭建過程詳解

    Activiti開發(fā)環(huán)境的搭建過程詳解

    這篇文章主要介紹了Activiti開發(fā)環(huán)境的搭建過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 基于springboot的flowable工作流實(shí)戰(zhàn)流程分析

    基于springboot的flowable工作流實(shí)戰(zhàn)流程分析

    這篇文章主要介紹了基于springboot的flowable工作流實(shí)戰(zhàn)流程分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-10-10

最新評(píng)論

元谋县| 齐齐哈尔市| 株洲市| 固安县| 高阳县| 荣昌县| 新田县| 扎鲁特旗| 鄂温| 岱山县| 汝城县| 吴旗县| 高雄市| 万州区| 县级市| 广宗县| 建始县| 衡阳县| 武汉市| 星子县| 焉耆| 上杭县| 泉州市| 黑龙江省| 江陵县| 泗阳县| 隆尧县| 昌宁县| 周至县| 绥阳县| 周口市| 读书| 全州县| 来安县| 申扎县| 松江区| 靖边县| 巢湖市| 荣昌县| 台东县| 平阳县|