<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>

          SpringBoot+ Dubbo + Mybatis + Nacos +Seata整合來實(shí)現(xiàn)Dubbo分布式事務(wù)

          共 15857字,需瀏覽 32分鐘

           ·

          2021-02-15 18:25

          作者:請(qǐng)叫我東子

          https://blog.csdn.net/u010046908/article/details/100536439

          1.簡介

          本文主要介紹SpringBoot2.1.5 + Dubbo 2.7.3 + Mybatis 3.4.2 + Nacos 1.1.3 +Seata 0.8.0整合來實(shí)現(xiàn)Dubbo分布式事務(wù)管理,使用Nacos 作為 Dubbo和Seata的注冊(cè)中心和配置中心,使用 MySQL 數(shù)據(jù)庫和 MyBatis來操作數(shù)據(jù)。

          如果你還對(duì)SpringBootDubboNacosSeataMybatis 不是很了解的話,這里我為大家整理個(gè)它們的官網(wǎng)網(wǎng)站,如下

          • SpringBoot:https://spring.io/projects/spring-boot
          • Dubbo:http://dubbo.apache.org/en-us/
          • Nacos:https://nacos.io/zh-cn/docs/quick-start.html
          • Seata:https://github.com/seata/seata/wiki/Home_Chinese
          • MyBatis:http://www.mybatis.org/mybatis-3/zh/index.html

          在這里我們就不一個(gè)一個(gè)介紹它們是怎么使用和原理,詳細(xì)請(qǐng)學(xué)習(xí)官方文檔,在這里我將開始對(duì)它們進(jìn)行整合,完成一個(gè)簡單的案例,來讓大家了解Seata來實(shí)現(xiàn)Dubbo分布式事務(wù)管理的基本流程。

          2.環(huán)境準(zhǔn)備

          2.1 下載nacos并安裝啟動(dòng)

          nacos下載:https://github.com/alibaba/nacos/releases/tag/1.1.3

          Nacos 快速入門:https://nacos.io/en-us/docs/quick-start.html

          sh?startup.sh?-m?standalone
          1

          在瀏覽器打開Nacos web 控制臺(tái):http://192.168.10.200:8848/nacos/index.html

          輸入nacos的賬號(hào)和密碼 分別為nacos:nacos

          這是時(shí)候naocs 就正常啟動(dòng)了。

          2.2 下載seata0.8.0 并安裝啟動(dòng)

          2.2.1 在 Seata Release 下載最新版的 Seata Server 并解壓得到如下目錄:

          .
          ├──bin
          ├──conf
          ├──file_store
          └──lib
          12345

          2.2.2 修改 conf/registry.conf 配置,

          目前seata支持如下的file、nacos 、apollo、zk、consul的注冊(cè)中心和配置中心。這里我們以nacos 為例。將 type 改為 nacos

          registry?{
          ??#?file?nacos
          ??type?=?"nacos"

          ??nacos?{
          ????serverAddr?=?"192.168.10.200:8848"
          ????namespace?=?"public"
          ????cluster?=?"default"
          ??}
          ??file?{
          ????name?=?"file.conf"
          ??}
          }

          config?{
          ??#?file、nacos?、apollo、zk、consul
          ??type?=?"nacos"

          ??nacos?{
          ????serverAddr?=?"192.168.10.200:8848"
          ????namespace?=?"public"
          ????cluster?=?"default"
          ??}

          ??file?{
          ????name?=?"file.conf"
          ??}
          }

          1234567891011121314151617181920212223242526272829
          • serverAddr = “192.168.10.200:8848” :nacos 的地址
          • namespace = “public” :nacos的命名空間默認(rèn)為public
          • cluster = “default” :集群設(shè)置未默認(rèn) default

          注意:seata0.9.0之后,配置如下, 其中namespace = ""

          registry?{
          ??#?file?nacos
          ??type?=?"nacos"

          ??nacos?{
          ????serverAddr?=?"192.168.10.200:8848"
          ????namespace?=?""
          ????cluster?=?"default"
          ??}
          ??file?{
          ????name?=?"file.conf"
          ??}
          }

          config?{
          ??#?file、nacos?、apollo、zk、consul
          ??type?=?"nacos"

          ??nacos?{
          ????serverAddr?=?"192.168.10.200:8848"
          ????namespace?=?""
          ??}

          ??file?{
          ????name?=?"file.conf"
          ??}
          }
          123456789101112131415161718192021222324252627

          2.2.3 修改 conf/nacos-config.txt配置

          注意:如果你的seata是1.1之后的版本請(qǐng)按照如下導(dǎo)入方式操作

          1. 下載https://github.com/seata/seata/blob/develop/script/config-center/目錄下的config.txt文件放入到seata-server目錄下的conf中,可更改文件名為nacos-config.txt
          2. 下載https://github.com/seata/seata/tree/develop/script/config-center/nacos/目錄下的nacos-config.py文件(window可用python命令執(zhí)行,linux也可執(zhí)行,前提先有安裝python)或者nacos-config.sh文件(window下可放在git命令行執(zhí)行,linux可執(zhí)行文件)
          transport.type=TCP
          transport.server=NIO
          transport.heartbeat=true
          transport.thread-factory.boss-thread-prefix=NettyBoss
          transport.thread-factory.worker-thread-prefix=NettyServerNIOWorker
          transport.thread-factory.server-executor-thread-prefix=NettyServerBizHandler
          transport.thread-factory.share-boss-worker=false
          transport.thread-factory.client-selector-thread-prefix=NettyClientSelector
          transport.thread-factory.client-selector-thread-size=1
          transport.thread-factory.client-worker-thread-prefix=NettyClientWorkerThread
          transport.thread-factory.boss-thread-size=1
          transport.thread-factory.worker-thread-size=8
          transport.shutdown.wait=3
          service.vgroup_mapping.order-service-seata-service-group=default
          service.vgroup_mapping.account-service-seata-service-group=default
          service.vgroup_mapping.storage-service-seata-service-group=default
          service.vgroup_mapping.business-service-seata-service-group=default
          service.enableDegrade=false
          service.disable=false
          service.max.commit.retry.timeout=-1
          service.max.rollback.retry.timeout=-1
          client.async.commit.buffer.limit=10000
          client.lock.retry.internal=10
          client.lock.retry.times=30
          store.mode=db
          store.file.dir=file_store/data
          store.file.max-branch-session-size=16384
          store.file.max-global-session-size=512
          store.file.file-write-buffer-cache-size=16384
          store.file.flush-disk-mode=async
          store.file.session.reload.read_size=100
          store.db.driver-class-name=com.mysql.jdbc.Driver
          store.db.datasource=dbcp
          store.db.db-type=mysql
          store.db.url=jdbc:mysql://192.168.10.200:3306/seata?useUnicode=true
          store.db.user=lidong
          store.db.password=cwj887766@@
          store.db.min-conn=1
          store.db.max-conn=3
          store.db.global.table=global_table
          store.db.branch.table=branch_table
          store.db.query-limit=100
          store.db.lock-table=lock_table
          recovery.committing-retry-period=1000
          recovery.asyn-committing-retry-period=1000
          recovery.rollbacking-retry-period=1000
          recovery.timeout-retry-period=1000
          transaction.undo.data.validation=true
          transaction.undo.log.serialization=jackson
          transaction.undo.log.save.days=7
          transaction.undo.log.delete.period=86400000
          transaction.undo.log.table=undo_log
          transport.serialization=seata
          transport.compressor=none
          metrics.enabled=false
          metrics.registry-type=compact
          metrics.exporter-list=prometheus
          metrics.exporter-prometheus-port=9898
          service.default.grouplist=127.0.0.1:8091
          1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859

          這里主要修改了如下幾項(xiàng):

          • store.mode :存儲(chǔ)模式 默認(rèn)file 這里我修改為db 模式 ,并且需要三個(gè)表global_tablebranch_tablelock_table
          • store.db.driver-class-name:默認(rèn)沒有,會(huì)報(bào)錯(cuò)。添加了 com.mysql.jdbc.Driver
          • store.db.datasource=dbcp :數(shù)據(jù)源 dbcp
          • store.db.db-type=mysql : 存儲(chǔ)數(shù)據(jù)庫的類型為mysql
          • store.db.url=jdbc:mysql://192.168.10.200:3306/seata?useUnicode=true : 修改為自己的數(shù)據(jù)庫urlport數(shù)據(jù)庫名稱
          • store.db.user=lidong :數(shù)據(jù)庫的賬號(hào)
          • store.db.password=cwj887766@@ :數(shù)據(jù)庫的密碼
          • service.vgroup_mapping.order-service-seata-service-group=default
          • service.vgroup_mapping.account-service-seata-service-group=default
          • service.vgroup_mapping.storage-service-seata-service-group=default
          • service.vgroup_mapping.business-service-seata-service-group=default

          也可以在 Nacos 配置頁面添加,data-id 為 service.vgroup_mapping.${YOUR_SERVICE_NAME}-seata-service-group, group 為 SEATA_GROUP, 如果不添加該配置,啟動(dòng)后會(huì)提示no available server to connect to services-server

          注意: 配置文件末尾有空行,需要?jiǎng)h除,否則會(huì)提示失敗,盡管實(shí)際上是成功的

          db模式下的所需的三個(gè)表的數(shù)據(jù)庫腳本位于seata\conf\db_store.sql

          global_table的表結(jié)構(gòu)

          CREATE?TABLE?`global_table`?(
          ??`xid`?varchar(128)?NOT?NULL,
          ??`transaction_id`?bigint(20)?DEFAULT?NULL,
          ??`status`?tinyint(4)?NOT?NULL,
          ??`application_id`?varchar(64)?DEFAULT?NULL,
          ??`transaction_service_group`?varchar(64)?DEFAULT?NULL,
          ??`transaction_name`?varchar(64)?DEFAULT?NULL,
          ??`timeout`?int(11)?DEFAULT?NULL,
          ??`begin_time`?bigint(20)?DEFAULT?NULL,
          ??`application_data`?varchar(2000)?DEFAULT?NULL,
          ??`gmt_create`?datetime?DEFAULT?NULL,
          ??`gmt_modified`?datetime?DEFAULT?NULL,
          ??PRIMARY?KEY?(`xid`),
          ??KEY?`idx_gmt_modified_status`?(`gmt_modified`,`status`),
          ??KEY?`idx_transaction_id`?(`transaction_id`)
          )?ENGINE=InnoDB?DEFAULT?CHARSET=utf8mb4;

          1234567891011121314151617

          branch_table的表結(jié)構(gòu)

          CREATE?TABLE?`branch_table`?(
          ??`branch_id`?bigint(20)?NOT?NULL,
          ??`xid`?varchar(128)?NOT?NULL,
          ??`transaction_id`?bigint(20)?DEFAULT?NULL,
          ??`resource_group_id`?varchar(32)?DEFAULT?NULL,
          ??`resource_id`?varchar(256)?DEFAULT?NULL,
          ??`lock_key`?varchar(128)?DEFAULT?NULL,
          ??`branch_type`?varchar(8)?DEFAULT?NULL,
          ??`status`?tinyint(4)?DEFAULT?NULL,
          ??`client_id`?varchar(64)?DEFAULT?NULL,
          ??`application_data`?varchar(2000)?DEFAULT?NULL,
          ??`gmt_create`?datetime?DEFAULT?NULL,
          ??`gmt_modified`?datetime?DEFAULT?NULL,
          ??PRIMARY?KEY?(`branch_id`),
          ??KEY?`idx_xid`?(`xid`)
          )?ENGINE=InnoDB?DEFAULT?CHARSET=utf8mb4;


          123456789101112131415161718

          lock_table的表結(jié)構(gòu)

          create?table?`lock_table`?(
          ??`row_key`?varchar(128)?not?null,
          ??`xid`?varchar(96),
          ??`transaction_id`?long?,
          ??`branch_id`?long,
          ??`resource_id`?varchar(256)?,
          ??`table_name`?varchar(32)?,
          ??`pk`?varchar(32)?,
          ??`gmt_create`?datetime?,
          ??`gmt_modified`?datetime,
          ??primary?key(`row_key`)
          );
          123456789101112

          2.2.4 將 Seata 配置添加到 Nacos 中

          使用命令如下

          cd?conf
          sh?nacos-config.sh?localhost
          12

          成功后會(huì)提示

          init?nacos?config?finished,?please?start?seata-server
          1

          在 Nacos 管理頁面應(yīng)該可以看到有 59 個(gè) Group 為SEATA_GROUP的配置

          2.2.5 啟動(dòng) Seata Server

          使用db 模式啟動(dòng)

          ?cd?..
          ?sh?./bin/seata-server.sh
          12

          這時(shí)候在 Nacos 的服務(wù)列表下面可以看到一個(gè)名為serverAddr的服務(wù)

          3 案例分析

          參考官網(wǎng)中用戶購買商品的業(yè)務(wù)邏輯。整個(gè)業(yè)務(wù)邏輯由4個(gè)微服務(wù)提供支持:

          • 庫存服務(wù):扣除給定商品的存儲(chǔ)數(shù)量。
          • 訂單服務(wù):根據(jù)購買請(qǐng)求創(chuàng)建訂單。
          • 帳戶服務(wù):借記用戶帳戶的余額。
          • 業(yè)務(wù)服務(wù):處理業(yè)務(wù)邏輯。

          請(qǐng)求邏輯架構(gòu)

          3.1 github地址

          springboot-dubbo-seata:https://github.com/lidong1665/springboot-dubbo-seata

          • samples-common :公共模塊
          • samples-account :用戶賬號(hào)模塊
          • samples-order :訂單模塊
          • samples-storage :庫存模塊
          • samples-business :業(yè)務(wù)模塊

          3.2 賬戶服務(wù):AccountDubboService

          /**
          ?*?@Author:?lidong
          ?*?@Description??賬戶服務(wù)接口
          ?*?@Date?Created?in?2019/9/5?16:37
          ?*/

          public?interface?AccountDubboService?{

          ????/**
          ?????*?從賬戶扣錢
          ?????*/

          ????ObjectResponse?decreaseAccount(AccountDTO?accountDTO);
          }
          123456789101112

          3.3 訂單服務(wù):OrderDubboService

          /**
          ?*?@Author:?lidong
          ?*?@Description??訂單服務(wù)接口
          ?*?@Date?Created?in?2019/9/5?16:28
          ?*/

          public?interface?OrderDubboService?{

          ????/**
          ?????*?創(chuàng)建訂單
          ?????*/

          ????ObjectResponse?createOrder(OrderDTO?orderDTO);
          }
          123456789101112

          3.4 庫存服務(wù):StorageDubboService

          /**
          ?*?@Author:?lidong
          ?*?@Description??庫存服務(wù)
          ?*?@Date?Created?in?2019/9/5?16:22
          ?*/

          public?interface?StorageDubboService?{

          ????/**
          ?????*?扣減庫存
          ?????*/

          ????ObjectResponse?decreaseStorage(CommodityDTO?commodityDTO);
          }

          12345678910111213

          3.5 業(yè)務(wù)服務(wù):BusinessService

          /**
          ?*?@Author:?lidong
          ?*?@Description
          ?*?@Date?Created?in?2019/9/5?17:17
          ?*/

          public?interface?BusinessService?{

          ????/**
          ?????*?出處理業(yè)務(wù)服務(wù)
          ??????*?@param?businessDTO
          ?????*?@return
          ?????*/

          ????ObjectResponse?handleBusiness(BusinessDTO?businessDTO);
          }
          123456789101112131415

          業(yè)務(wù)邏輯的具體實(shí)現(xiàn)主要體現(xiàn)在 訂單服務(wù)的實(shí)現(xiàn)和業(yè)務(wù)服務(wù)的實(shí)現(xiàn)

          訂單服務(wù)的實(shí)現(xiàn)

          @Service
          public?class?TOrderServiceImpl?extends?ServiceImpl<TOrderMapper,?TOrder>?implements?ITOrderService?{

          ????@Reference(version?=?"1.0.0")
          ????private?AccountDubboService?accountDubboService;

          ????/**
          ?????*?創(chuàng)建訂單
          ?????*?@Param:??OrderDTO??訂單對(duì)象
          ?????*?@Return:??OrderDTO??訂單對(duì)象
          ?????*/

          ????@Override
          ????public?ObjectResponse?createOrder(OrderDTO?orderDTO)?{
          ????????ObjectResponse?response?=?new?ObjectResponse<>();
          ????????//扣減用戶賬戶
          ????????AccountDTO?accountDTO?=?new?AccountDTO();
          ????????accountDTO.setUserId(orderDTO.getUserId());
          ????????accountDTO.setAmount(orderDTO.getOrderAmount());
          ????????ObjectResponse?objectResponse?=?accountDubboService.decreaseAccount(accountDTO);

          ????????//生成訂單號(hào)
          ????????orderDTO.setOrderNo(UUID.randomUUID().toString().replace("-",""));
          ????????//生成訂單
          ????????TOrder?tOrder?=?new?TOrder();
          ????????BeanUtils.copyProperties(orderDTO,tOrder);
          ????????tOrder.setCount(orderDTO.getOrderCount());
          ????????tOrder.setAmount(orderDTO.getOrderAmount().doubleValue());
          ????????try?{
          ????????????baseMapper.createOrder(tOrder);
          ????????}?catch?(Exception?e)?{
          ????????????response.setStatus(RspStatusEnum.FAIL.getCode());
          ????????????response.setMessage(RspStatusEnum.FAIL.getMessage());
          ????????????return?response;
          ????????}

          ????????if?(objectResponse.getStatus()?!=?200)?{
          ????????????response.setStatus(RspStatusEnum.FAIL.getCode());
          ????????????response.setMessage(RspStatusEnum.FAIL.getMessage());
          ????????????return?response;
          ????????}

          ????????response.setStatus(RspStatusEnum.SUCCESS.getCode());
          ????????response.setMessage(RspStatusEnum.SUCCESS.getMessage());
          ????????return?response;
          ????}
          }
          12345678910111213141516171819202122232425262728293031323334353637383940414243444546

          整個(gè)業(yè)務(wù)的實(shí)現(xiàn)邏輯

          @Service
          @Slf4j
          public?class?BusinessServiceImpl?implements?BusinessService{

          ????@Reference(version?=?"1.0.0")
          ????private?StorageDubboService?storageDubboService;

          ????@Reference(version?=?"1.0.0")
          ????private?OrderDubboService?orderDubboService;

          ????private?boolean?flag;

          ????/**
          ?????*?處理業(yè)務(wù)邏輯
          ?????*?@Param:
          ?????*?@Return:
          ?????*/


          ????@GlobalTransactional(timeoutMills?=?300000,?name?=?"dubbo-gts-seata-example")
          ????@Override
          ????public?ObjectResponse?handleBusiness(BusinessDTO?businessDTO)?{
          ????????log.info("開始全局事務(wù),XID?=?"?+?RootContext.getXID());
          ????????ObjectResponse?objectResponse?=?new?ObjectResponse<>();
          ????????//1、扣減庫存
          ????????CommodityDTO?commodityDTO?=?new?CommodityDTO();
          ????????commodityDTO.setCommodityCode(businessDTO.getCommodityCode());
          ????????commodityDTO.setCount(businessDTO.getCount());
          ????????ObjectResponse?storageResponse?=?storageDubboService.decreaseStorage(commodityDTO);
          ????????//2、創(chuàng)建訂單
          ????????OrderDTO?orderDTO?=?new?OrderDTO();
          ????????orderDTO.setUserId(businessDTO.getUserId());
          ????????orderDTO.setCommodityCode(businessDTO.getCommodityCode());
          ????????orderDTO.setOrderCount(businessDTO.getCount());
          ????????orderDTO.setOrderAmount(businessDTO.getAmount());
          ????????ObjectResponse?response?=?orderDubboService.createOrder(orderDTO);

          ????????//打開注釋測試事務(wù)發(fā)生異常后,全局回滾功能
          //????????if?(!flag)?{
          //??????????? throw new RuntimeException("測試拋異常后,分布式事務(wù)回滾!");
          //????????}

          ????????if?(storageResponse.getStatus()?!=?200?||?response.getStatus()?!=?200)?{
          ????????????throw?new?DefaultException(RspStatusEnum.FAIL);
          ????????}

          ????????objectResponse.setStatus(RspStatusEnum.SUCCESS.getCode());
          ????????objectResponse.setMessage(RspStatusEnum.SUCCESS.getMessage());
          ????????objectResponse.setData(response.getData());
          ????????return?objectResponse;
          ????}
          }
          123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051

          3.6 使用seata的分布式事務(wù)解決方案處理dubbo的分布式事務(wù)

          我們只需要在業(yè)務(wù)處理的方法handleBusiness添加一個(gè)注解 @GlobalTransactional

          @GlobalTransactional(timeoutMills?=?300000,?name?=?"dubbo-gts-seata-example")
          ????@Override
          ????public?ObjectResponse?handleBusiness(BusinessDTO?businessDTO)?{
          ????
          ????}
          12345
          • timeoutMills: 超時(shí)時(shí)間
          • name :事務(wù)名稱

          3.7 準(zhǔn)備數(shù)據(jù)庫

          注意: MySQL必須使用InnoDB engine.

          創(chuàng)建數(shù)據(jù)庫 并導(dǎo)入數(shù)據(jù)庫腳本

          DROP?DATABASE?IF?EXISTS?seata;
          CREATE?DATABASE?seata;
          USE?seata;

          DROP?TABLE?IF?EXISTS?`t_account`;
          CREATE?TABLE?`t_account`?(
          ??`id`?int(11)?NOT?NULL?AUTO_INCREMENT,
          ??`user_id`?varchar(255)?DEFAULT?NULL,
          ??`amount`?double(14,2)?DEFAULT?'0.00',
          ??PRIMARY?KEY?(`id`)
          )?ENGINE=InnoDB?AUTO_INCREMENT=2?DEFAULT?CHARSET=utf8;

          --?----------------------------
          --?Records?of?t_account
          --?----------------------------
          INSERT?INTO?`t_account`?VALUES?('1',?'1',?'4000.00');

          --?----------------------------
          --?Table?structure?for?t_order
          --?----------------------------
          DROP?TABLE?IF?EXISTS?`t_order`;
          CREATE?TABLE?`t_order`?(
          ??`id`?int(11)?NOT?NULL?AUTO_INCREMENT,
          ??`order_no`?varchar(255)?DEFAULT?NULL,
          ??`user_id`?varchar(255)?DEFAULT?NULL,
          ??`commodity_code`?varchar(255)?DEFAULT?NULL,
          ??`count`?int(11)?DEFAULT?'0',
          ??`amount`?double(14,2)?DEFAULT?'0.00',
          ??PRIMARY?KEY?(`id`)
          )?ENGINE=InnoDB?AUTO_INCREMENT=64?DEFAULT?CHARSET=utf8;

          --?----------------------------
          --?Records?of?t_order
          --?----------------------------

          --?----------------------------
          --?Table?structure?for?t_storage
          --?----------------------------
          DROP?TABLE?IF?EXISTS?`t_storage`;
          CREATE?TABLE?`t_storage`?(
          ??`id`?int(11)?NOT?NULL?AUTO_INCREMENT,
          ??`commodity_code`?varchar(255)?DEFAULT?NULL,
          ??`name`?varchar(255)?DEFAULT?NULL,
          ??`count`?int(11)?DEFAULT?'0',
          ??PRIMARY?KEY?(`id`),
          ??UNIQUE?KEY?`commodity_code`?(`commodity_code`)
          )?ENGINE=InnoDB?AUTO_INCREMENT=2?DEFAULT?CHARSET=utf8;

          --?----------------------------
          --?Records?of?t_storage
          --?----------------------------
          INSERT?INTO?`t_storage`?VALUES?('1',?'C201901140001',?'水杯',?'1000');

          --?----------------------------
          --?Table?structure?for?undo_log
          --?注意此處0.3.0+?增加唯一索引?ux_undo_log
          --?----------------------------
          DROP?TABLE?IF?EXISTS?`undo_log`;
          CREATE?TABLE?`undo_log`?(
          ??`id`?bigint(20)?NOT?NULL?AUTO_INCREMENT,
          ??`branch_id`?bigint(20)?NOT?NULL,
          ??`xid`?varchar(100)?NOT?NULL,
          ??`context`?varchar(128)?NOT?NULL,
          ??`rollback_info`?longblob?NOT?NULL,
          ??`log_status`?int(11)?NOT?NULL,
          ??`log_created`?datetime?NOT?NULL,
          ??`log_modified`?datetime?NOT?NULL,
          ??`ext`?varchar(100)?DEFAULT?NULL,
          ??PRIMARY?KEY?(`id`),
          ??UNIQUE?KEY?`ux_undo_log`?(`xid`,`branch_id`)
          )?ENGINE=InnoDB?AUTO_INCREMENT=1?DEFAULT?CHARSET=utf8;

          --?----------------------------
          --?Records?of?undo_log
          --?----------------------------
          SET?FOREIGN_KEY_CHECKS=1;
          12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576

          會(huì)看到如上的4個(gè)表

          +-------------------------+
          |?Tables_in_seata?????????|
          +-------------------------+
          |?t_account???????????????|
          |?t_order?????????????????|
          |?t_storage???????????????|
          |?undo_log????????????????|
          +-------------------------+
          12345678

          這里為了簡化我將這個(gè)三張表創(chuàng)建到一個(gè)庫中,使用是三個(gè)數(shù)據(jù)源來實(shí)現(xiàn)。

          3.8 我們以賬號(hào)服務(wù)samples-account為例 ,分析需要注意的配置項(xiàng)目

          3.8.1 引入的依賴

          "1.0"?encoding="UTF-8"?>
          "http://maven.apache.org/POM/4.0.0"?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          ?????????xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?http://maven.apache.org/xsd/maven-4.0.0.xsd">
          ????4.0.0
          ????
          ????????org.springframework.boot
          ????????spring-boot-starter-parent
          ????????2.1.5.RELEASE
          ?????????
          ????

          ????springboot-dubbo-seata
          ????pom
          ????springboot-dubbo-seata
          ????io.seata
          ????1.0.0
          ????samples-account
          ????
          ????????2.1.5.RELEASE
          ????????1.8
          ????????1.1.10
          ????????1.3.2
          ????????2.3
          ????????0.2.3
          ????????1.16.22
          ????????2.7.3
          ????????1.1.3
          ????????0.8.0
          ????????4.1.32.Final
          ????


          ????
          ????????
          ????????????org.springframework.boot
          ????????????spring-boot-starter-web
          ????????????${springboot.verison}
          ????????


          ????????
          ????????????org.springframework.boot
          ????????????spring-boot-starter
          ????????????${springboot.verison}
          ????????


          ????????
          ????????????org.springframework.boot
          ????????????spring-boot-starter-test
          ????????????${springboot.verison}
          ????????


          ????????
          ????????????com.alibaba
          ????????????druid
          ????????????${druid.version}
          ????????


          ????????
          ????????????org.mybatis.spring.boot
          ????????????mybatis-spring-boot-starter
          ????????????${mybatis.version}
          ????????


          ????????
          ????????????com.baomidou
          ????????????mybatis-plus
          ????????????${mybatis-plus.version}
          ????????


          ????????
          ????????????org.apache.dubbo
          ????????????dubbo
          ????????????${dubbo.version}
          ????????????
          ????????????????
          ????????????????????spring
          ????????????????????org.springframework
          ????????????????

          ????????????

          ????????

          ????????
          ????????????org.apache.dubbo
          ????????????dubbo-spring-boot-starter
          ????????????${dubbo.version}
          ????????


          ????????
          ????????
          ????????????org.apache.dubbo
          ????????????dubbo-config-spring
          ????????????${dubbo.version}
          ????????

          ????????
          ????????????org.apache.dubbo
          ????????????dubbo-registry-nacos
          ????????????${dubbo.version}
          ????????


          ????????
          ????????
          ????????????io.seata
          ????????????seata-all
          ????????????${seata.version}
          ????????



          ????????
          ????????????com.alibaba.nacos
          ????????????nacos-client
          ????????????${nacos-client.verison}
          ????????


          ????????
          ????????
          ????????????com.alibaba.boot
          ????????????nacos-config-spring-boot-starter
          ????????????${nacos.version}
          ????????????
          ????????????????
          ????????????????????nacos-client
          ????????????????????com.alibaba.nacos
          ????????????????

          ????????????

          ????????

          ????????
          ????????????org.springframework.boot
          ????????????spring-boot-maven-plugin
          ????????????${springboot.verison}
          ????????

          ????????
          ????????????org.projectlombok
          ????????????lombok
          ????????????${lombok.version}
          ????????



          ????????
          ????????????io.netty
          ????????????netty-all
          ????????????${netty.version}
          ????????

          ????????
          ????????????com.alibaba.spring
          ????????????spring-context-support
          ????????????1.0.2
          ????????

          ????????
          ????????????org.apache.httpcomponents
          ????????????httpclient
          ????????????4.5
          ????????


          ????????
          ????????????mysql
          ????????????mysql-connector-java
          ????????????5.1.47
          ????????

          ????



          ????
          ????????
          ????????????
          ????????????????org.springframework.boot
          ????????????????spring-boot-maven-plugin
          ????????????

          ????????????
          ????????????????org.apache.maven.plugins
          ????????????????maven-deploy-plugin
          ????????????????
          ????????????????????true
          ????????????????

          ????????????

          ????????????
          ????????????????org.apache.maven.plugins
          ????????????????maven-compiler-plugin
          ????????????????
          ????????????????????${java.version}
          ????????????????????${java.version}
          ????????????????

          ????????????

          ????????

          ????



          123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184

          注意:

          • seata-all: 這個(gè)是seata 所需的主要依賴
          • dubbo-spring-boot-starter: springboot dubbo的依賴

          其他的就不一一介紹,其他的一目了然,就知道是干什么的。

          3.8.2 application.properties配置

          server.port=8102
          spring.application.name=dubbo-account-example

          #====================================Dubbo配置===============================================
          dubbo.application.id= dubbo-account-example
          dubbo.application.name= dubbo-account-example
          dubbo.protocol.id=dubbo
          dubbo.protocol.name=dubbo
          dubbo.registry.id=dubbo-account-example-registry
          dubbo.registry.address=nacos://192.168.10.200:8848
          dubbo.protocol.port=20880
          dubbo.application.qosEnable=false
          dubbo.config-center.address=nacos://192.168.10.200:8848
          dubbo.metadata-report.address=nacos://192.168.10.200:8848

          #====================================mysql 配置============================================
          spring.datasource.driver-class-name=com.mysql.jdbc.Driver
          spring.datasource.url=jdbc:mysql://192.168.10.200:3306/seata?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
          spring.datasource.username=lidong
          spring.datasource.password=cwj887766@@


          #=====================================mybatis 配置======================================
          mybatis.mapper-locations=classpath*:/mapper/*.xml

          12345678910111213141516171819202122232425

          3.8.3 registry.conf 配置 (naocs的配置)

          registry {
          # file nacos
          type = "nacos"

          nacos {
          serverAddr = "192.168.10.200"
          namespace = "public"
          cluster = "default"
          }
          file {
          name = "file.conf"
          }
          }

          config {
          # file、nacos 、apollo、zk、consul
          type = "nacos"

          file {
          name = "file.conf"
          }

          nacos {
          serverAddr = "192.168.10.200"
          namespace = "public"
          cluster = "default"
          }
          }

          1234567891011121314151617181920212223242526272829

          3.8.5 SeataAutoConfig 配置

          package?io.seata.samples.integration.account.config;

          import?com.alibaba.druid.pool.DruidDataSource;

          import?io.seata.rm.datasource.DataSourceProxy;
          import?io.seata.spring.annotation.GlobalTransactionScanner;
          import?org.apache.ibatis.session.SqlSessionFactory;
          import?org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
          import?org.mybatis.spring.SqlSessionFactoryBean;
          import?org.springframework.beans.factory.annotation.Autowired;
          import?org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
          import?org.springframework.context.annotation.Bean;
          import?org.springframework.context.annotation.Configuration;
          import?org.springframework.context.annotation.Primary;
          import?org.springframework.core.io.support.PathMatchingResourcePatternResolver;

          /**
          ?*?@Author:?llidong
          ?*?@Description??seata?global?configuration
          ?*?@Date?Created?in?2019/9/05?10:28
          ?*/

          @Configuration
          public?class?SeataAutoConfig?{

          ????/**
          ?????*?autowired?datasource?config
          ?????*/

          ????@Autowired
          ????private?DataSourceProperties?dataSourceProperties;

          ????/**
          ?????*?init?durid?datasource
          ?????*
          ?????*?@Return:?druidDataSource??datasource?instance
          ?????*/

          ????@Bean
          ????@Primary
          ????public?DruidDataSource?druidDataSource(){
          ????????DruidDataSource?druidDataSource?=?new?DruidDataSource();
          ????????druidDataSource.setUrl(dataSourceProperties.getUrl());
          ????????druidDataSource.setUsername(dataSourceProperties.getUsername());
          ????????druidDataSource.setPassword(dataSourceProperties.getPassword());
          ????????druidDataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
          ????????druidDataSource.setInitialSize(0);
          ????????druidDataSource.setMaxActive(180);
          ????????druidDataSource.setMaxWait(60000);
          ????????druidDataSource.setMinIdle(0);
          ????????druidDataSource.setValidationQuery("Select?1?from?DUAL");
          ????????druidDataSource.setTestOnBorrow(false);
          ????????druidDataSource.setTestOnReturn(false);
          ????????druidDataSource.setTestWhileIdle(true);
          ????????druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
          ????????druidDataSource.setMinEvictableIdleTimeMillis(25200000);
          ????????druidDataSource.setRemoveAbandoned(true);
          ????????druidDataSource.setRemoveAbandonedTimeout(1800);
          ????????druidDataSource.setLogAbandoned(true);
          ????????return?druidDataSource;
          ????}

          ????/**
          ?????*?init?datasource?proxy
          ?????*?@Param:?druidDataSource??datasource?bean?instance
          ?????*?@Return:?DataSourceProxy??datasource?proxy
          ?????*/

          ????@Bean
          ????public?DataSourceProxy?dataSourceProxy(DruidDataSource?druidDataSource){
          ????????return?new?DataSourceProxy(druidDataSource);
          ????}

          ????/**
          ?????*?init?mybatis?sqlSessionFactory
          ?????*?@Param:?dataSourceProxy??datasource?proxy
          ?????*?@Return:?DataSourceProxy??datasource?proxy
          ?????*/

          ????@Bean
          ????public?SqlSessionFactory?sqlSessionFactory(DataSourceProxy?dataSourceProxy)?throws?Exception?{
          ????????SqlSessionFactoryBean?factoryBean?=?new?SqlSessionFactoryBean();
          ????????factoryBean.setDataSource(dataSourceProxy);
          ????????factoryBean.setMapperLocations(new?PathMatchingResourcePatternResolver()
          ????????????????.getResources("classpath*:/mapper/*.xml"));
          ????????return?factoryBean.getObject();
          ????}

          ????/**
          ?????*?init?global?transaction?scanner
          ?????*
          ?????*?@Return:?GlobalTransactionScanner
          ?????*/

          ????@Bean
          ????public?GlobalTransactionScanner?globalTransactionScanner(){
          ????????return?new?GlobalTransactionScanner("account-gts-seata-example",?"account-service-seata-service-group");
          ????}
          }

          12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394

          其中:

          @Bean
          ????public?GlobalTransactionScanner?globalTransactionScanner(){
          ????????return?new?GlobalTransactionScanner("account-gts-seata-example",?"account-service-seata-service-group");
          ????}
          1234

          GlobalTransactionScanner: 初始化全局的事務(wù)掃描器

          ?/**
          ?????*?Instantiates?a?new?Global?transaction?scanner.
          ?????*
          ?????*?@param?applicationId??the?application?id
          ?????*?@param?txServiceGroup?the?default?server?group
          ?????*/
          ????public?GlobalTransactionScanner(String?applicationId,?String?txServiceGroup)?{
          ????????this(applicationId,?txServiceGroup,?DEFAULT_MODE);
          ????}
          123456789
          • applicationId :為應(yīng)用id 這里我傳入的是account-gts-seata-example
          • txServiceGroup: 默認(rèn)server的分組 這里我傳入的是account-service-seata-service-group 這個(gè)和我們前面在nacos 配置的是保存一致。
          • DEFAULT_MODE:默認(rèn)的事務(wù)模式 為AT_MODE + MT_MODE

          3.8.6 AccountExampleApplication 啟動(dòng)類的配置

          package?io.seata.samples.integration.account;

          import?org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
          import?org.mybatis.spring.annotation.MapperScan;
          import?org.springframework.boot.SpringApplication;
          import?org.springframework.boot.autoconfigure.SpringBootApplication;
          import?org.springframework.boot.context.config.ConfigFileApplicationListener;

          @SpringBootApplication(scanBasePackages?=?"io.seata.samples.integration.account")
          @MapperScan({"io.seata.samples.integration.account.mapper"})
          @EnableDubbo(scanBasePackages?=?"io.seata.samples.integration.account")
          public?class?AccountExampleApplication?{

          ????public?static?void?main(String[]?args)?{
          ????????SpringApplication.run(AccountExampleApplication.class,?args);
          ????}

          }


          1234567891011121314151617181920
          • @EnableDubbo等同于 @DubboComponentScan@EnableDubboConfig組合
          • @DubboComponentScan 掃描 classpaths 下類中添加了 @Service@Reference 將自動(dòng)注入到spring beans中。
          • @EnableDubboConfig 掃描的dubbo的外部化配置。

          4 啟動(dòng)所有的sample模塊

          啟動(dòng) samples-accountsamples-ordersamples-storagesamples-business

          并且在nocos的控制臺(tái)查看注冊(cè)情況: http://192.168.10.200:8848/nacos/#/serviceManagement

          我們可以看到上面的服務(wù)都已經(jīng)注冊(cè)成功。

          5 測試

          5. 1 發(fā)送一個(gè)下單請(qǐng)求

          使用postman 發(fā)送 :http://localhost:8104/business/dubbo/buy

          參數(shù):

          {
          ????"userId":"1",
          ????"commodityCode":"C201901140001",
          ????"name":"fan",
          ????"count":50,
          ????"amount":"100"
          }
          1234567

          返回

          {
          ????"status":?200,
          ????"message":?"成功",
          ????"data":?null
          }
          12345

          這時(shí)候控制臺(tái):

          2019-09-05 12:17:34.097  INFO 21860?---?[nio-8104-exec-4] i.s.s.i.c.controller.BusinessController ?:?請(qǐng)求參數(shù):BusinessDTO(userId=1, commodityCode=C201901140001, name=fan, count=50, amount=100)
          2019-09-05?12:17:34.146??INFO?21860?---?[nio-8104-exec-4]?i.seata.tm.api.DefaultGlobalTransaction??:?Begin?new?global?transaction?[192.168.10.200:8091:2021380638]
          2019-09-05?12:17:34.150??INFO?21860?---?[nio-8104-exec-4]?i.s.s.i.c.service.BusinessServiceImpl????:?開始全局事務(wù),XID?=?192.168.10.200:8091:2021380638
          2019-09-05?12:17:36.966??INFO?21860?---?[nio-8104-exec-4]?i.seata.tm.api.DefaultGlobalTransaction??:?[192.168.10.200:8091:2021380638]?commit?status:Committed
          1234

          事務(wù)提交成功,

          我們來看一下數(shù)據(jù)庫數(shù)據(jù)變化

          t_accountt_order

          t_storage

          數(shù)據(jù)沒有問題。

          5.2 測試回滾

          我們samples-businessBusinessServiceImplhandleBusiness2 下面的代碼去掉注釋

          if?(!flag)?{
          ??throw?new?RuntimeException("測試拋異常后,分布式事務(wù)回滾!");
          }
          123

          使用postman 發(fā)送 :http://localhost:8104/business/dubbo/buy2

          .響應(yīng)結(jié)果:

          {
          ????"timestamp":?"2019-09-05T04:29:34.178+0000",
          ????"status":?500,
          ????"error":?"Internal?Server?Error",
          ????"message":?"測試拋異常后,分布式事務(wù)回滾!",
          ????"path":?"/business/dubbo/buy"
          }
          1234567

          控制臺(tái)

          2019-09-05 12:29:32.836  INFO 17264 ---?[nio-8104-exec-2] i.s.s.i.c.controller.BusinessController ?:?請(qǐng)求參數(shù):BusinessDTO(userId=1, commodityCode=C201901140001, name=fan, count=50, amount=100)
          2019-09-05?12:29:32.843??INFO?17264?---?[nio-8104-exec-2]?i.s.common.loader.EnhancedServiceLoader??:?load?ContextCore[null]?extension?by?class[io.seata.core.context.ThreadLocalContextCore]
          2019-09-05?12:29:32.848??INFO?17264?---?[nio-8104-exec-2]?i.s.common.loader.EnhancedServiceLoader??:?load?TransactionManager[null]?extension?by?class[io.seata.tm.DefaultTransactionManager]
          2019-09-05?12:29:32.849??INFO?17264?---?[nio-8104-exec-2]?io.seata.tm.TransactionManagerHolder?????:?TransactionManager?Singleton?io.seata.tm.DefaultTransactionManager@461585ac
          2019-09-05?12:29:32.859??INFO?17264?---?[nio-8104-exec-2]?i.s.common.loader.EnhancedServiceLoader??:?load?LoadBalance[null]?extension?by?class[io.seata.discovery.loadbalance.RandomLoadBalance]
          2019-09-05?12:29:32.893??INFO?17264?---?[nio-8104-exec-2]?i.seata.tm.api.DefaultGlobalTransaction??:?Begin?new?global?transaction?[192.168.10.200:8091:2021380674]
          2019-09-05?12:29:32.897??INFO?17264?---?[nio-8104-exec-2]?i.s.s.i.c.service.BusinessServiceImpl????:?開始全局事務(wù),XID?=?192.168.10.200:8091:2021380674
          2019-09-05?12:29:34.143??INFO?17264?---?[nio-8104-exec-2]?i.seata.tm.api.DefaultGlobalTransaction??:?[192.168.10.200:8091:2021380674]?rollback?status:Rollbacked
          2019-09-05?12:29:34.158?ERROR?17264?---?[nio-8104-exec-2]?o.a.c.c.C.[.[.[/].[dispatcherServlet]????:?Servlet.service()?for?servlet?[dispatcherServlet]?in?context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException:?測試拋異常后,分布式事務(wù)回滾!] with root cause

          java.lang.RuntimeException:?測試拋異常后,分布式事務(wù)回滾!
          ?at?io.seata.samples.integration.call.service.BusinessServiceImpl.handleBusiness(BusinessServiceImpl.java:60)?~[classes/:na]
          ?at?io.seata.samples.integration.call.service.BusinessServiceImpl$$FastClassBySpringCGLIB$$2ab3d645.invoke()?~[classes/:na]
          ?at?org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)?~[spring-core-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)?~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)?~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?io.seata.spring.annotation.GlobalTransactionalInterceptor$1.execute(GlobalTransactionalInterceptor.java:104)?~[seata-all-0.8.0.jar:0.8.0]
          ?at?io.seata.tm.api.TransactionalTemplate.execute(TransactionalTemplate.java:64)?~[seata-all-0.8.0.jar:0.8.0]
          ?at?io.seata.spring.annotation.GlobalTransactionalInterceptor.handleGlobalTransaction(GlobalTransactionalInterceptor.java:101)?~[seata-all-0.8.0.jar:0.8.0]
          ?at?io.seata.spring.annotation.GlobalTransactionalInterceptor.invoke(GlobalTransactionalInterceptor.java:76)?~[seata-all-0.8.0.jar:0.8.0]
          ?at?org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)?~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)?~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?io.seata.samples.integration.call.service.BusinessServiceImpl$$EnhancerBySpringCGLIB$$cb43f7ab.handleBusiness()?~[classes/:na]
          ?at?io.seata.samples.integration.call.controller.BusinessController.handleBusiness(BusinessController.java:37)?~[classes/:na]
          ?at?sun.reflect.NativeMethodAccessorImpl.invoke0(Native?Method)?~[na:1.8.0_144]
          ?at?sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)?~[na:1.8.0_144]
          ?at?sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)?~[na:1.8.0_144]
          ?at?java.lang.reflect.Method.invoke(Method.java:498)?~[na:1.8.0_144]
          ?at?org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)?~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)?~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)?~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)?~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)?~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)?~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039)?~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)?~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)?~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)?~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?javax.servlet.http.HttpServlet.service(HttpServlet.java:660)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)?~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?javax.servlet.http.HttpServlet.service(HttpServlet.java:741)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)?~[tomcat-embed-websocket-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)?~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)?~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)?~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)?~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)?~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)?~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)?~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)?~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          ?at?org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)?~[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)?[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)?[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)?[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)?[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)?[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)?[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)?[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)?[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:836)?[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1747)?[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)?[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)?[na:1.8.0_144]
          ?at?java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)?[na:1.8.0_144]
          ?at?org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)?[tomcat-embed-core-9.0.19.jar:9.0.19]
          ?at?java.lang.Thread.run(Thread.java:748)?[na:1.8.0_144]


          1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980

          我們查看數(shù)據(jù)庫數(shù)據(jù),已經(jīng)回滾,和上面的數(shù)據(jù)一致。


          點(diǎn)擊閱讀全文前往微服務(wù)電商教程
          瀏覽 68
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                    人成网站在线观看 | 欧美成人免费网站 | 免费日韩在线三级黄色电影网址 | 爱搞搞91搞搞 | 日韩无码xxx |