国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

一站式分布式事務(wù) Seata 方案

開(kāi)發(fā)
本文主要對(duì)分布式事務(wù)Seata的使用、原理做了介紹,同時(shí)在選擇方案選擇上給出一些建議。

引言

上一篇《如何選擇分布式事務(wù)解決方案?》 綜合比較了各種分布式事務(wù)方案的優(yōu)缺點(diǎn),并在技術(shù)選型上給出合理化的建議。考慮到企業(yè)應(yīng)用的普遍性和適用性,今天重點(diǎn)聊聊分布式Seata方案實(shí)踐和原理。

Seata 是什么?

Seata 是一款開(kāi)源的分布式事務(wù)解決方案,致力于提供高性能和簡(jiǎn)單易用的分布式事務(wù)服務(wù)。Seata 將為用戶提供了 AT、TCC、SAGA 和 XA 事務(wù)模式,為用戶打造一站式的分布式解決方案。默認(rèn)AT模式。

英文官網(wǎng):https://seata.io/zh-cn/

中文官網(wǎng):https://seata.io/zh-cn/

看官網(wǎng)這輕松而有趣的解釋,心中默念:

為探究這個(gè)問(wèn)題,我們嘗試從問(wèn)題中來(lái),到問(wèn)題中去。試想:

  • 不使用分布式事務(wù)會(huì)產(chǎn)生怎樣的結(jié)果?
  • 為何選擇Seata方案?
  • 這種方案如何實(shí)現(xiàn)提交和回滾保證數(shù)據(jù)一致性的?

帶著這些問(wèn)題,根據(jù)實(shí)際應(yīng)用場(chǎng)景逐步探究。。。

業(yè)務(wù)場(chǎng)景

在電商交易系統(tǒng)中,最核心的業(yè)務(wù)場(chǎng)景:下訂單 --> 減庫(kù)存 --> 調(diào)支付,要求具備數(shù)據(jù)強(qiáng)一致性。

基本模型如下:

我們要求該場(chǎng)景應(yīng)滿足以下幾個(gè)條件:

  • 訂單狀態(tài)正常(0-異常,1-正常)
  • 庫(kù)存不能出現(xiàn)負(fù)數(shù)或者下單了沒(méi)有扣庫(kù)存
  • 保證金額正常支付,不能出現(xiàn)扣款多或者扣款少的情況

業(yè)務(wù)實(shí)現(xiàn)

下面我們給出核心代碼描述業(yè)務(wù)過(guò)程。

訂單服務(wù):

public interface OrderService {
    /**
    * 創(chuàng)建訂單
    */
   void create(Order order);
}

倉(cāng)儲(chǔ)服務(wù):

public interface StorageService {
    /**
     * 扣減庫(kù)存
     */
    void deduct(Long productId, Integer count);
}

帳戶服務(wù):

public interface AccountService {

  /**
   * 扣減賬戶余額
   *
   * @param userId 用戶id
   * @param money  金額
   */
  void debit(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money);
}

這里只給出核心業(yè)務(wù)邏輯說(shuō)明問(wèn)題。在訂單業(yè)務(wù)作為核心邏輯,遠(yuǎn)程調(diào)用扣庫(kù)存和支付。

public class OrderServiceImpl implements OrderService
{
    @Resource
    private OrderDao orderDao;
    @Resource
    private StorageService storageService;
    @Resource
    private AccountService accountService;

    /**
     * 創(chuàng)建訂單->調(diào)用庫(kù)存服務(wù)扣減庫(kù)存->調(diào)用賬戶服務(wù)扣減賬戶余額->修改訂單狀態(tài)
     * 簡(jiǎn)單說(shuō):下訂單->扣庫(kù)存->減余額->改狀態(tài)
     */
    @Override
    //這里先注釋掉,用于比較實(shí)用分布式事務(wù)前后的效果
    //@GlobalTransactional(name = "fsp-create-order",rollbackFor = Exception.class)
    public void create(Order order)
    {
        //創(chuàng)建訂單
        orderDao.create(order);

        //2 扣減庫(kù)存
        storageService.deduct(order.getProductId(),order.getCount());

        //3 扣減賬戶金額
        accountService.debit(order.getUserId(),order.getMoney());

        //4 修改訂單狀態(tài),從零到1,1代表已經(jīng)完成
        orderDao.update(order.getUserId(),0);

    }
}

未使用分布式事務(wù)前的場(chǎng)景

初始狀態(tài):

-- 庫(kù)存商品:100
mysql> select * from t_storage;
+----+------------+-------+------+---------+
| id | product_id | total | used | residue |
+----+------------+-------+------+---------+
|  1 |          1 |   100 |    0 |     100 |
+----+------------+-------+------+---------+
1 row in set (0.00 sec)
 
  
--賬戶余額:1000
mysql> select * from t_account;
+----+---------+-------+------+---------+
| id | user_id | total | used | residue |
+----+---------+-------+------+---------+
|  1 |       1 |  1000 |    0 |    1000 |
+----+---------+-------+------+---------+
1 row in set (0.00 sec)

  
-- 訂單為空 
mysql> select * from t_order;
Empty set (0.00 sec)

下面模擬一個(gè)賬戶扣減異常(因?yàn)镺penFeign的默認(rèn)分別是連接超時(shí)時(shí)間10秒.這處設(shè)置20秒就是為了挑事兒),然后分別啟動(dòng)訂單、庫(kù)存、賬戶服務(wù)。

/**
   * 扣減賬戶余額
   */
  @Override
  public void debit(Long userId, BigDecimal money) {
      LOGGER.info("------->account-service中扣減賬戶余額開(kāi)始");
      //模擬超時(shí)異常,全局事務(wù)回滾
      //暫停幾秒鐘線程
      try { TimeUnit.SECONDS.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); }
      accountDao.debit(userId,money);
      LOGGER.info("------->account-service中扣減賬戶余額結(jié)束");
  }

模擬下訂單過(guò)程:

http://localhost:2001/order/create?userId=1&productId=1&count=10&mnotallow=100

頁(yè)面異常因?yàn)橘~戶服務(wù)中扣減過(guò)程發(fā)生異常。我們?cè)賮?lái)觀察數(shù)據(jù)庫(kù)中的變化情況:

-- 庫(kù)存商品:100
mysql> select * from t_storage;
+----+------------+-------+------+---------+
| id | product_id | total | used | residue |
+----+------------+-------+------+---------+
|  1 |          1 |   100 |   10 |      90 |
+----+------------+-------+------+---------+
1 row in set (0.00 sec)
 
  
--賬戶余額:1000
mysql> select * from t_account;
+----+---------+-------+------+---------+
| id | user_id | total | used | residue |
+----+---------+-------+------+---------+
|  1 |       1 |  1000 |    0 |    1000 |
+----+---------+-------+------+---------+
1 row in set (0.00 sec)


  
-- 訂單為空 
mysql> select * from t_order;
+----+---------+------------+-------+-------+--------+
| id | user_id | product_id | count | money | status |
+----+---------+------------+-------+-------+--------+
|  3 |       1 |          1 |    10 |   100 |      0 |
+----+---------+------------+-------+-------+--------+
1 row in set (0.00 sec)

觀察分析,訂單狀態(tài):0-異常。庫(kù)存較少,但是余額沒(méi)有扣減。商家容易哭死。這就使我們不得不做事務(wù)的控制。以達(dá)到數(shù)據(jù)一致性。

Seata方案引入

對(duì)此,我們使用分布式事務(wù)Seata的解決方案解決此問(wèn)題。

圖片來(lái)源于官網(wǎng)

為方便測(cè)試使用,這里準(zhǔn)備了Seata的一套環(huán)境。并給出相應(yīng)業(yè)務(wù)測(cè)試用例SQL。

使用非常簡(jiǎn)單。只需要在核心業(yè)務(wù)方法上加一個(gè)注解@GlobalTransactional即可。

@Override
    @GlobalTransactional(name = "fsp-create-order",rollbackFor = Exception.class)
    public void create(Order order)
    {
        //創(chuàng)建訂單
        orderDao.create(order);

        //2 扣減庫(kù)存
        storageService.deduct(order.getProductId(),order.getCount());

        //3 扣減賬戶金額
        accountService.debit(order.getUserId(),order.getMoney());

        //4 修改訂單狀態(tài),從零到1,1代表已經(jīng)完成
        orderDao.update(order.getUserId(),0);

    }

恢復(fù)數(shù)據(jù)初始狀態(tài),再次啟動(dòng)和重復(fù)上述測(cè)試步驟。觀察在發(fā)生異常的情況下,數(shù)據(jù)庫(kù)還是初始的狀態(tài)(為出現(xiàn)訂單異常和賬戶余額變動(dòng)的問(wèn)題)。顯然:這個(gè)注解幫助我們:在分布式環(huán)境下,當(dāng)有異常發(fā)生時(shí)進(jìn)行全局回滾,以維持?jǐn)?shù)據(jù)的一致?tīng)顟B(tài)。我們把這種全局意義上控制的事務(wù)成為全局事務(wù)。

Seata執(zhí)行流程及原理

@GlobalTransactional用事實(shí)告訴我們:極簡(jiǎn)是一種美!

是不是很好奇?

下面究其背后的原理做深層次的探究。

(1) 全局事務(wù)中的角色

  • TM 事務(wù)發(fā)起方,是業(yè)務(wù)方法上帶有@GlobalTransactional注解的服務(wù),如:本案例中訂單服務(wù)。
  • TC 事務(wù)協(xié)調(diào)者,可以理解為一個(gè)隱形的中間人,負(fù)責(zé)管理事務(wù)。
  • TR 事務(wù)參與者:本案例當(dāng)中:訂單、庫(kù)存、賬戶都是還是事務(wù)參與者

(2) 全局成功提交流程

(3) 全局失敗回滾流程

下面我們用代碼驗(yàn)證此過(guò)程:

  • 啟動(dòng)nacos;
  • 啟動(dòng)seata;
  • debug啟動(dòng)訂單、庫(kù)存、賬戶服務(wù),斷點(diǎn)跟蹤

查看數(shù)據(jù)庫(kù)變化情況(取關(guān)鍵字段信息):

-- 全局事務(wù)
mysql> select xid,transaction_id,application_id,transaction_service_group,transaction_name from global_table ;
+-------------------------------+----------------+---------------------+---------------------------+------------------+
| xid                           | transaction_id | application_id      | transaction_service_group | transaction_name |
+-------------------------------+----------------+---------------------+---------------------------+------------------+
| 192.168.0.101:8091:2155601919 |     2155601919 | seata-order-service | fsp_tx_group              | fsp-create-order |
+-------------------------------+----------------+---------------------+---------------------------+------------------+
1 row in set (0.01 sec)

  
-- 分支事務(wù)
mysql> select  xid,transaction_id,branch_id,client_id,branch_type from  branch_table;
+-------------------------------+----------------+------------+-------------------------------------------+-------------+
| xid                           | transaction_id | branch_id  | client_id                                 | branch_type |
+-------------------------------+----------------+------------+-------------------------------------------+-------------+
| 192.168.0.101:8091:2155601919 |     2155601919 | 2155601922 | seata-order-service:192.168.0.101:51952   | AT          |
| 192.168.0.101:8091:2155601919 |     2155601919 | 2155601927 | seata-storage-service:192.168.0.101:52459 | AT          |
| 192.168.0.101:8091:2155601919 |     2155601919 | 2155601930 | seata-account-service:192.168.0.101:52498 | AT          |
+-------------------------------+----------------+------------+-------------------------------------------+-------------+
3 rows in set (0.00 sec)

  
-- 鎖
mysql> select xid,transaction_id,branch_id,table_name,resource_id  from lock_table;
+-------------------------------+----------------+------------+------------+-----------------------------------------------+
| xid                           | transaction_id | branch_id  | table_name | resource_id                                   |
+-------------------------------+----------------+------------+------------+-----------------------------------------------+
| 192.168.0.101:8091:2155601919 | 2155601919     | 2155601930 | t_account  | jdbc:mysql://114.116.10.56:3306/seata_account |
| 192.168.0.101:8091:2155601919 | 2155601919     | 2155601922 | t_order    | jdbc:mysql://114.116.10.56:3306/seata_order   |
| 192.168.0.101:8091:2155601919 | 2155601919     | 2155601927 | t_storage  | jdbc:mysql://114.116.10.56:3306/seata_storage |
+-------------------------------+----------------+------------+------------+-----------------------------------------------+
3 rows in set (0.00 sec)

注意:全局事務(wù)xid 和分支事務(wù)branch_id 之間的對(duì)應(yīng)關(guān)系,比對(duì)上圖中成功提交流程.

我們觀察業(yè)務(wù)庫(kù)中的undo_log日志情況:(重點(diǎn)關(guān)注rollback_info字段信息)

格式化一下rollback_info信息:

當(dāng)然,讀者感興趣可以查看下seata_account庫(kù)和 seata_storage庫(kù)中undo_log的情況,與此類似。

所以我們可以將Seata的執(zhí)行原理歸納為:

(1) 在一階段,Seata 會(huì)攔截“業(yè)務(wù) SQL”,

  • 解析 SQL 語(yǔ)義,找到“業(yè)務(wù) SQL”要更新的業(yè)務(wù)數(shù)據(jù),在業(yè)務(wù)數(shù)據(jù)被更新前,將其保存成“before image”;
  • 執(zhí)行“業(yè)務(wù) SQL”更新業(yè)務(wù)數(shù)據(jù);
  • 在業(yè)務(wù)數(shù)據(jù)更新之后,其保存成“after image”,最后生成行鎖。

以上操作全部在一個(gè)數(shù)據(jù)庫(kù)事務(wù)內(nèi)完成,這樣保證了一階段操作的原子性。

圖片來(lái)源于學(xué)習(xí)筆記

(2) 二階段提交:

天空不留下鳥(niǎo)兒的痕跡,但它已經(jīng)飛過(guò)),完成數(shù)據(jù)清理即可。

圖片來(lái)源于學(xué)習(xí)筆記

(3) 二階段回滾:

二階段如果是回滾的話,Seata 就需要回滾一階段已經(jīng)執(zhí)行的“業(yè)務(wù) SQL”,還原業(yè)務(wù)數(shù)據(jù)。回滾方式便是用“before image”還原業(yè)務(wù)數(shù)據(jù)。

  • 還原前要首先要校驗(yàn)臟寫(xiě);
  • 對(duì)比“數(shù)據(jù)庫(kù)當(dāng)前業(yè)務(wù)數(shù)據(jù)”和 “after image”
  • 如果兩份數(shù)據(jù)完全一致就說(shuō)明沒(méi)有臟寫(xiě),可以還原業(yè)務(wù)數(shù)據(jù),如果不一致就說(shuō)明有臟寫(xiě),出現(xiàn)臟寫(xiě)就需要轉(zhuǎn)人工處理。

圖片來(lái)源于學(xué)習(xí)筆記

總結(jié)

本文主要對(duì)分布式事務(wù)Seata的使用、原理做了介紹,同時(shí)在選擇方案選擇上給出如下建議:

  • 非必要不引入分布式事務(wù)的處理;
  • 分布式事務(wù)在分布式環(huán)境下使用,單體應(yīng)用不必考慮;
  • 一般多用在遠(yuǎn)程調(diào)用三方外部平臺(tái)之間,內(nèi)部系統(tǒng)服務(wù)之間建議使用Spring事務(wù)
  • Seata分布式事務(wù)方案默認(rèn)AT模式,代碼無(wú)入侵,使用簡(jiǎn)單,在數(shù)據(jù)一致性要求比較高的系統(tǒng)中,是很好的分布式事務(wù)解決方案。常用于電商支付、金融轉(zhuǎn)賬類業(yè)務(wù)。
  • Seata配置繁瑣,引入子系統(tǒng)會(huì)產(chǎn)生很多其它問(wèn)題。應(yīng)根據(jù)實(shí)際場(chǎng)景合理選擇。
責(zé)任編輯:趙寧寧 來(lái)源: 碼易有道
相關(guān)推薦

2022-06-27 08:21:05

Seata分布式事務(wù)微服務(wù)

2023-11-06 13:15:32

分布式事務(wù)Seata

2022-06-21 08:27:22

Seata分布式事務(wù)

2017-05-04 21:30:32

前端異常監(jiān)控捕獲方案

2022-03-24 07:51:27

seata分布式事務(wù)Java

2023-01-06 09:19:12

Seata分布式事務(wù)

2025-04-28 00:44:04

2010-05-06 16:02:26

2022-07-10 20:24:48

Seata分布式事務(wù)

2025-05-07 00:10:00

分布式事務(wù)TCC模式

2023-02-04 18:24:10

SeataJava業(yè)務(wù)

2013-06-14 09:30:52

2013-10-20 13:30:07

華為一站式BYOD敏捷辦公

2025-08-27 09:11:48

2024-10-09 14:14:07

2021-04-23 08:15:51

Seata XA AT

2025-04-30 10:44:02

2015-12-15 17:33:57

戴爾云計(jì)算

2015-04-19 16:36:10

騰訊云

2013-12-12 15:34:00

Moneta移動(dòng)支付一站式解決方案
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

亚洲欧美一区二区三区四区| 精品一二线国产| 亚洲免费高清视频在线| 污污视频在线| 国产精品99一区二区| 亚洲小视频在线观看| 欧洲一级在线观看| 中文字幕一区二区三区视频| 91大学生片黄在线观看| 国产精品黄色| 国产精品69久久久久| 99久久999| 日韩成人av在线播放| 电影av一区| 亚洲影视在线观看| 天堂av在线网站| 北条麻妃国产九九精品视频| 欧美日韩高清在线一区| 日本欧美国产| 91精品国产91久久久久久最新 | 日色在线视频| 久久国产福利国产秒拍| 久久精品99国产| 狠狠做深爱婷婷综合一区| 国产精品久久久久久超碰| 欧美国产精品劲爆| 嫩草影院中文字幕| 日韩高清不卡一区二区| 国产精品久久久久久久小唯西川| 免费av一区二区三区四区| 欧美精品免费在线| 久久青青草综合| 日韩一区二区三区免费看| 成年美女网站| 日本一区二区三区高清不卡 | 污视频免费在线观看| 欧美日韩亚洲系列| 日日噜噜夜夜狠狠视频| 男人的天堂久久精品| 亚洲男人天堂2019| 日韩在线资源| 欧美福利一区二区| 国产在线高清视频| 欧美一二三四在线| 蜜桃麻豆av在线| 国产精品色在线网站| 男女猛烈激情xx00免费视频| 美女视频黄久久| 国产精品久久久久久久天堂第1集| 成年女人的天堂在线| 天天爽天天爽夜夜爽| 国产乱淫av一区二区三区| 伊人婷婷久久| 国产精品白丝jk白祙喷水网站| 最新中文字幕久久| 久久99国产精品久久99果冻传媒| 亚洲一区二区在线观| 久久国产精品免费| 成年人网站国产| 国产欧美日韩不卡免费| 国产字幕中文| 亚洲成av人片一区二区| 你懂的视频在线免费| 91超碰这里只有精品国产| 欧一区二区三区| 欧美高清激情brazzers| 国产精品久久久久久福利| 精品久久久影院| 电影久久久久久| 久久久久久久爱| 水蜜桃精品av一区二区| 欧美大陆一区二区| 成人午夜碰碰视频| 国产91福利| 7777精品伊人久久久大香线蕉经典版下载 | 亚洲精品自在久久| 久久久加勒比| 国产a∨精品一区二区三区不卡| 中文字幕亚洲综合久久五月天色无吗''| 国产欧美日韩亚洲| 四虎成人精品一区二区免费网站| 国产综合第一页| 日日欢夜夜爽一区| 日韩a在线播放| 亚洲一区中文日韩| 色爱综合区网| 欧美激情亚洲国产| 亚洲大片在线| 国产视频在线一区二区| 17c精品麻豆一区二区免费| a看欧美黄色女同性恋| 4p变态网欧美系列| 竹菊久久久久久久| 亚洲一二三四在线观看| www.av在线播放| 国产一区二区三区在线观看视频| 美女一区2区| 久久免费一区| 欧美国产国产综合| 香蕉视频在线免费看| 日韩色av导航| 国产麻豆日韩欧美久久| 91偷拍精品一区二区三区| 国内精品在线播放| 在线观看成年人视频| 精品久久久三级丝袜| 亚洲春色h网| 在线免费观看一区二区三区| 亚洲人成亚洲人成在线观看图片| h片在线播放| 欧美一级bbbbb性bbbb喷潮片| 美女尤物久久精品| 福利在线免费| 国产视频综合在线| 亚洲色图国产| 爱情岛论坛成人| 亚洲国产精品yw在线观看| 精品国产中文字幕第一页| 在线观看av的网址| 欧美午夜在线观看| 亚洲a级精品| 久久aimee| 亚洲精品v天堂中文字幕| 蜜乳av综合| 日韩精品在线观看av| 欧美一区成人| 欧美成人sm免费视频| 亚洲电影在线| 国外av网站| www.xxxx精品| 亚洲美女一区| 亚洲精选一区| 超碰aⅴ人人做人人爽欧美| 3d动漫啪啪精品一区二区免费| 五月婷婷综合色| 最近日韩中文字幕| 91成人福利社区| 一区二区免费在线观看| 欧洲av一区二区嗯嗯嗯啊| 亚洲美女久久| 91色国产在线| 久久夜色精品国产欧美乱| 精品一区二区免费视频| 欧美激情视频在线播放| 91成人免费视频| 亚洲一二三四在线| 欧美精选一区二区三区| 97涩在线观看视频| 久久久久久噜噜噜久久久精品| 不卡一区二区中文字幕| 亚洲一二三四| a级黄色片网站| 日韩电影中文 亚洲精品乱码| 国产精品日本| 99热国产在线| 日韩欧美一区二区三区四区| 91精品国产aⅴ一区二区| 亚洲乱码视频| 韩国成人一区| 亚洲xxxx在线| 亚洲国产精品久久久| ·天天天天操| 91精品国产高清久久久久久91| 99精品国产99久久久久久白柏| 日韩电影网站| www.av片| 欧美激情亚洲精品| 尤物视频一区二区| 北条麻妃在线一区二区免费播放| 亚洲伊人伊成久久人综合网| 91在线色戒在线| 精品国产乱码久久久久久婷婷 | 国产欧美亚洲日本| 日本乱人伦一区| 亚洲作爱视频| 麻豆蜜桃在线| 国产精品免费一区二区三区| 伊人久久大香线蕉av超碰演员| 91最新在线| 亚洲五月六月| 日韩在线视频国产| 国产日韩欧美一区二区三区综合 | 国严精品久久久久久亚洲影视| 欧美日韩国产高清一区二区三区 | 欧美成人明星100排名| 91中文精品字幕在线视频| 欧美一a一片一级一片| 日韩和的一区二区| 欧美韩国日本| 激情视频免费| www.av在线播放| 午夜在线免费视频| 欧洲s码亚洲m码精品一区| 亚洲乱码国产乱码精品精的特点| 日韩在线综合| 波多野结衣在线高清| 一级特黄性色生活片| 亚洲自拍av在线| 亚洲天堂免费在线| 亚洲激情自拍视频|