<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          @Transactional 竟也能解決分布式事務?

          共 3799字,需瀏覽 8分鐘

           ·

          2022-06-21 12:56


            前天陳某知識星球中的朋友咨詢過我一個問題,大致內(nèi)容如下:

            這位讀者什么意思呢?簡單的總結(jié)下:在Sharding-JDBC中明明只是簡單的使用@Transactional這個本地事務注解,為什么在跨庫插入數(shù)據(jù)時候卻能夠同時回滾?

            我們知道單數(shù)據(jù)節(jié)點的情況下保持事務是非常簡單的,只需要使用本地事務即可輕松解決,比如常用的注解:@Transactional

            但是在分庫后將會存在跨庫的事務,此時本地事務還能保證事務嗎?

            這篇文章就以球友的提問來聊一下Sharding-JDBC中的本地事務

            本地事務

            Sharding-JDBC中的本地事務可能會讓大家有一個誤解,還是以商品表為例:將商品表根據(jù)商品ID進行水平分庫,分為兩個庫,如下:

            分庫的配置這里就不貼了,詳情看源碼

            此時向其中批量插入數(shù)據(jù),偽代碼如下:

            @Transactional
            public int insertBatch(){
                for(int i=0;i<10;i++){
                    insert(product);
                    .......
                }
            }

            上述案例中使用了@Transactional開啟了本地事務,但是內(nèi)部在插入數(shù)據(jù)時,Sharding-JDB會根據(jù)product_id這個分片鍵進行分庫,那么這個業(yè)務方法肯定是跨了DB1、DB2這兩個庫,@Transactional這個注解能解決嗎?

            假象:手動在內(nèi)部模擬拋出異常,還真的是都rollback

            此時很多人都迷糊了,Sharding-JDBC中的本地事務真的是可以保證分布式事務?

            真實結(jié)論:Sharding-JDBC中的本地事務無法保證分布式事務

            Sharding-JDBC中的本地事務在以下兩種情況是完全支持的

            1. 支持非跨庫事務,比如僅分表、在單庫中操作
            2. 支持因邏輯異常導致的跨庫事務,比如上述的操作,跨兩個庫插入數(shù)據(jù),插入完成后拋出異常

            本地事務不支持的情況

            1. 不支持因網(wǎng)絡、硬件異常導致的跨庫事務;例如:同一事務中,跨兩個庫更新,更新完畢后、未提交之前,第一個庫宕機,則只有第二個庫數(shù)據(jù)提交

            對于因網(wǎng)絡、硬件異常導致的跨庫事務無法支持很好理解,在分布式事務中無論是兩階段還是三階段提交都是直接或者間接滿足以下兩個條件:

            1. 有一個事務協(xié)調(diào)者
            2. 事務日志記錄

            本地事務并未滿足上述條件,自然是無法支持

            為什么邏輯異常導致的跨庫事務能夠支持?

            Spring的本地事務大家都很了解,也經(jīng)常用,并不支持的跨庫事務,那么為什么Sharding-JDBC中卻能支持呢?

            想要了解其中的貓膩必然需要從Sharding-JDBC的源碼入手,下圖是在Sharding-JDBC一條SQL處理的流程:

            Sharding-JDBC中的一條SQL會經(jīng)過改寫,拆分成不同數(shù)據(jù)源的SQL,比如一條select語句,會按照其中分片鍵拆分成對應數(shù)據(jù)源的SQL,然后在不同數(shù)據(jù)源中的執(zhí)行,最終會提交或者回滾

            想要解釋上述的問題,只需要看ShardingConnection,這是Sharding-JDBC自定義實現(xiàn)的,繼承關系如下圖:

            可以看到ShardingConnection繼承了java.sql.Connection,這個類就不必多解釋了,在學習JDBC的時候應該都有所接觸,直接和數(shù)據(jù)庫打交道的一個類。

            想要知道為什么支持跨庫事務的回滾,肯定要找到其中的rollback方法,如下:

            @Override
            public void rollback() throws SQLException {
                //① 本地事務
             f (TransactionType.LOCAL == transactionType) {
                 super.rollback();
                } else {
                   //② 非本地事務
                 shardingTransactionManager.rollback();
                }
            }

            rollback的方法中區(qū)分了本地事務分布式事務,如果是本地事務將調(diào)用父類的rollback方法,如下:

            //父類:AbstractConnectionAdapter#rollback

            @Override
            public void rollback() throws SQLException {
                //cachedConnections中存儲了數(shù)據(jù)源,這里是ds1/ds2
                forceExecuteTemplate.execute(cachedConnections.values(), Connection::rollback);
            }

            這里是調(diào)用ForceExecuteTemplate#execute()方法執(zhí)行,其實內(nèi)部就是遍歷數(shù)據(jù)源去執(zhí)行對應的rollback方法,如下:

            public void execute(final Collection<T> targets, final ForceExecuteCallback<T> callback) throws SQLException {
                    Collection<SQLException> exceptions = new LinkedList<>();
                    for (T each : targets) {
                        try {
                            callback.execute(each);
                        } catch (final SQLException ex) {
                            exceptions.add(ex);
                        }
                    }
                    throwSQLExceptionIfNecessary(exceptions);
                }

            看到這里已經(jīng)很明了了,rollback 在各個數(shù)據(jù)源中回滾且未記錄任何事務日志,因此在非硬件、網(wǎng)絡的情況下都是可以正?;貪L的,一旦因為網(wǎng)絡、硬件故障,可能導致某個數(shù)據(jù)源rollback失敗,這樣即使程序恢復了正常,也無undo日志繼續(xù)進行rollback,因此這里就造成了數(shù)據(jù)不一致了。

            總結(jié)

            僅僅依靠Spring自帶的本地事務(@Transactional)是無法保證跨庫的分布式事務,不要被Sharding-JDBC的假象迷惑了。

            當然Sharding-JDBC對于跨庫事務也是有一定的支持,大致分成三類:

            • 強一致性的XA協(xié)議事務
            • 基于Base的柔性事務
            • 通過SPI機制自定義擴展的分布式事務解決方案

            本文只是拋磚引玉簡單的介紹下分庫分表后的事務處理,后文會針對以上三類方案詳細介紹一下。

            瀏覽 47
            點贊
            評論
            收藏
            分享

            手機掃一掃分享

            分享
            舉報
            評論
            圖片
            表情
            推薦
            點贊
            評論
            收藏
            分享

            手機掃一掃分享

            分享
            舉報
            <kbd id="afajh"><form id="afajh"></form></kbd>
            <strong id="afajh"><dl id="afajh"></dl></strong>
              <del id="afajh"><form id="afajh"></form></del>
                  1. <th id="afajh"><progress id="afajh"></progress></th>
                    <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    一区二区三区播放 | 国产欧美中文字幕 | 亚洲成人黄色在线观看 | 在线观看免费黄网站 | 好吊视频一区二区三区四区 |