欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Seata?AT模式前后鏡像是如何生成詳解

 更新時間:2022年11月29日 11:40:52   作者:夢想實現(xiàn)家_Z  
這篇文章主要為大家介紹了Seata?AT模式前后鏡像是如何生成的方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

Seata官網(wǎng)中,我們可以知道AT模式一階段的處理流程如下:

1.解析 SQL:得到 SQL 的類型(UPDATE),表(product),條件(where name = 'TXC')等相關(guān)的信息。

2.查詢前鏡像:根據(jù)解析得到的條件信息,生成查詢語句,定位數(shù)據(jù)。

3.執(zhí)行業(yè)務(wù) SQL。

4.查詢后鏡像:根據(jù)前鏡像的結(jié)果,通過 主鍵 定位數(shù)據(jù)。

5.插入回滾日志:把前后鏡像數(shù)據(jù)以及業(yè)務(wù) SQL 相關(guān)的信息組成一條回滾日志記錄,插入到 UNDO_LOG 表中

......

前鏡像的作用是保證在分布式事務(wù)失敗時能夠成功回滾的重要依據(jù),后鏡像是在回滾前校驗是否臟寫的數(shù)據(jù)依據(jù),那么我們一階段的前后鏡像在真實的代碼實現(xiàn)中是如何生成的呢?

前后鏡像的生成

為了能夠探尋到前后鏡像的生成原理,我們需要看一看seata源碼。最終我們把入口定位到AbstractDMLBaseExecutor.executeAutoCommitFalse()方法:

    protected T executeAutoCommitFalse(Object[] args) throws Exception {
        // 獲取前鏡像
        TableRecords beforeImage = beforeImage();
        // 執(zhí)行業(yè)務(wù)SQL
        T result = statementCallback.execute(statementProxy.getTargetStatement(), args);
        // 獲取后鏡像
        TableRecords afterImage = afterImage(beforeImage);
        // 存儲前后鏡像
        prepareUndoLog(beforeImage, afterImage);
        return result;
    }

前鏡像

繼續(xù)深入探究一下到底是怎么獲取beforeImage的,根據(jù)源碼來看,我們發(fā)現(xiàn)beforeImage()方法有很多實現(xiàn):

也就是說,Seata會根據(jù)不同的業(yè)務(wù)SQL來生成beforeImage,有點經(jīng)驗的小伙伴能夠看出,這里其實使用到了模版模式加上策略模式,我們挑一個DeleteExecutor來看一下:

@Override
    protected TableRecords beforeImage() throws SQLException {
        SQLDeleteRecognizer visitor = (SQLDeleteRecognizer) sqlRecognizer;
        // 根據(jù)表名解析出元數(shù)據(jù)
        TableMeta tmeta = getTableMeta(visitor.getTableName());
        ArrayList<List<Object>> paramAppenderList = new ArrayList<>();
        // 生成查詢beforeImage的SQL語句
        // SELECT [列名,] FROM [表名] (別名) (WHERE) (ORDER BY) (LIMIT) FOR UPDATE
        String selectSQL = buildBeforeImageSQL(visitor, tmeta, paramAppenderList);
        // 執(zhí)行SQL查詢beforeImage
        return buildTableRecords(tmeta, selectSQL, paramAppenderList);
    }

1.關(guān)鍵原理就是根據(jù)業(yè)務(wù)SQL反向查詢出被影響的數(shù)據(jù);

2.為了保證查詢到的數(shù)據(jù)不是快照數(shù)據(jù),一定要記得加上FOR UPDATE;

另外的話,我們發(fā)現(xiàn)其實UpdateExecutor的前鏡像生成方式和DeleteExecutor也差不多,像普通的insert這種SQL的前鏡像就更簡單了:

    @Override
    protected TableRecords beforeImage() throws SQLException {
        return TableRecords.empty(getTableMeta());
    }

因為普通insert語句不存在任何前鏡像,所以直接返回空記錄;

后鏡像

我們再來看一下后鏡像是如何生成的,這次我們看一下UpdateExecutor的后鏡像生成方法afterImage():

@Override
    protected TableRecords afterImage(TableRecords beforeImage) throws SQLException {
        // 獲取元數(shù)據(jù)
        TableMeta tmeta = getTableMeta();
        // 沒有前鏡像,也不存在后鏡像,說明沒有數(shù)據(jù)被修改
        if (beforeImage == null || beforeImage.size() == 0) {
            return TableRecords.empty(getTableMeta());
        }
        // 生成查詢后鏡像SQL
        // SELECT [列名,] FROM [表名] (別名) WHERE 主鍵 in (前鏡像的主鍵值)
        // 這里面有一個配置項[client.undo.onlyCareUpdateColumns],是否只關(guān)心被修改的列名,默認(rèn)是true
        String selectSQL = buildAfterImageSQL(tmeta, beforeImage);
        ResultSet rs = null;
        try (PreparedStatement pst = statementProxy.getConnection().prepareStatement(selectSQL)) {
            SqlGenerateUtils.setParamForPk(beforeImage.pkRows(), getTableMeta().getPrimaryKeyOnlyName(), pst);
            // 執(zhí)行查詢后鏡像
            rs = pst.executeQuery();
            // 包裝查詢結(jié)果
            return TableRecords.buildRecords(tmeta, rs);
        } finally {
            IOUtil.close(rs);
        }
    }

后鏡像的生成原理與前鏡像的生成原理差不多,不過還是有一些小小的區(qū)別的:

1.后鏡像的查詢條件使用的是前鏡像對應(yīng)的主鍵值,就沒有用業(yè)務(wù)SQL的查詢條件;不同的Executor處理方式不同,需要根據(jù)具體的業(yè)務(wù)SQL來區(qū)分;

2.查詢后鏡像的SQL沒有使用FOR UPDATE加鎖,直接拿的快照數(shù)據(jù);

小結(jié)

通過對seata源碼的分析,我們現(xiàn)在已經(jīng)了解了前后鏡像的生成原理了:

1.通過業(yè)務(wù)SQL來判斷SQL語句的類型,從而選擇不同的Executor來獲取前后鏡像;

2.前鏡像是通過業(yè)務(wù)SQL的查詢條件,并加上FOR UPDATE來查詢業(yè)務(wù)SQL執(zhí)行前的數(shù)據(jù);(不同的Executor實現(xiàn)不同)

3.后鏡像是在業(yè)務(wù)SQL執(zhí)行完畢后,根據(jù)前鏡像內(nèi)的主鍵數(shù)據(jù)來獲取的數(shù)據(jù);(不同的Executor實現(xiàn)不同)

4.通過前后鏡像的多種實現(xiàn)可以判斷出seata AT模式所支持的SQL語句的所有類型;

以上就是Seata AT模式前后鏡像是如何生成詳解的詳細(xì)內(nèi)容,更多關(guān)于Seata AT模式生成前后鏡像的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Ajax+Servlet+jsp顯示搜索效果

    Ajax+Servlet+jsp顯示搜索效果

    這篇文章主要為大家詳細(xì)介紹了Ajax+Servlet+jsp顯示搜索效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • SpringBoot中的異常處理與參數(shù)校驗的方法實現(xiàn)

    SpringBoot中的異常處理與參數(shù)校驗的方法實現(xiàn)

    這篇文章主要介紹了SpringBoot中的異常處理與參數(shù)校驗的方法實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • java自定義線程池的原理簡介

    java自定義線程池的原理簡介

    這篇文章主要介紹了java自定義線程池的原理詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-08-08
  • SpringBoot讀取資源目錄中JSON文件的方法實例

    SpringBoot讀取資源目錄中JSON文件的方法實例

    最近做項目遇到需要將json類型的配置文件引用到項目中,已經(jīng)將讀取json文件的方法封裝成工具類,下面這篇文章主要給大家介紹了關(guān)于SpringBoot讀取資源目錄中JSON文件的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • MyBatis深入解讀動態(tài)SQL的實現(xiàn)

    MyBatis深入解讀動態(tài)SQL的實現(xiàn)

    動態(tài) SQL 是 MyBatis 的強大特性之一。如果你使用過 JDBC 或其它類似的框架,你應(yīng)該能理解根據(jù)不同條件拼接 SQL 語句有多痛苦,例如拼接時要確保不能忘記添加必要的空格,還要注意去掉列表最后一個列名的逗號。利用動態(tài) SQL,可以徹底擺脫這種痛苦
    2022-04-04
  • Java并發(fā)編程 interrupt()方法示例詳解

    Java并發(fā)編程 interrupt()方法示例詳解

    interrrupt()方法可以用來打斷正在運行的線程,也可以打斷sleep()、wait()、join()情況下的線程,但是這些情況下被打斷線程的打斷標(biāo)記不同,這篇文章主要介紹了Java并發(fā)編程 interrupt()方法示例詳解,需要的朋友可以參考下
    2023-06-06
  • SpringBoot配置Redis自定義過期時間操作

    SpringBoot配置Redis自定義過期時間操作

    這篇文章主要介紹了SpringBoot配置Redis自定義過期時間操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • idea直接修改新的git地址的方法(圖文)

    idea直接修改新的git地址的方法(圖文)

    這篇文章主要介紹了idea直接修改新的git地址的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Netty分布式pipeline管道傳播事件的邏輯總結(jié)分析

    Netty分布式pipeline管道傳播事件的邏輯總結(jié)分析

    這篇文章主要為大家介紹了Netty分布式pipeline管道傳播事件總結(jié)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-03-03
  • Java實現(xiàn)合并兩個有序序列算法示例

    Java實現(xiàn)合并兩個有序序列算法示例

    這篇文章主要介紹了Java實現(xiàn)合并兩個有序序列算法,簡單描述了序列合并算法的原理與java合并有序序列的具體操作步驟及相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2017-09-09

最新評論