失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > SpringBoot+ Dubbo + Mybatis + Nacos +Seata整合来实现Dubbo分布式事务

SpringBoot+ Dubbo + Mybatis + Nacos +Seata整合来实现Dubbo分布式事务

时间:2024-06-08 13:53:17

相关推荐

SpringBoot+ Dubbo + Mybatis + Nacos +Seata整合来实现Dubbo分布式事务

作者:请叫我东子

/u010046908/article/details/100536439

1.简介“本文主要介绍SpringBoot2.1.5 + Dubbo 2.7.3 + Mybatis 3.4.2 + Nacos 1.1.3 +Seata 0.8.0整合来实现Dubbo分布式事务管理,使用Nacos 作为 Dubbo和Seata的注册中心和配置中心,使用 MySQL 数据库和 MyBatis来操作数据。”如果你还对SpringBoot、Dubbo、Nacos、Seata、Mybatis 不是很了解的话,这里我为大家整理个它们的官网网站,如下SpringBoot:https://spring.io/projects/spring-bootDubbo:/en-us/Nacos:https://nacos.io/zh-cn/docs/quick-start.htmlSeata:/seata/seata/wiki/Home_ChineseMyBatis:/mybatis-3/zh/index.html在这里我们就不一个一个介绍它们是怎么使用和原理,详细请学习官方文档,在这里我将开始对它们进行整合,完成一个简单的案例,来让大家了解Seata来实现Dubbo分布式事务管理的基本流程。2.环境准备2.1 下载nacos并安装启动nacos下载:/alibaba/nacos/releases/tag/1.1.3Nacos 快速入门:https://nacos.io/en-us/docs/quick-start.htmlshstartup.sh-mstandalone1在浏览器打开Nacos web 控制台:http://192.168.10.200:8848/nacos/index.html输入nacos的账号和密码 分别为nacos:nacos这是时候naocs 就正常启动了。2.2 下载seata0.8.0 并安装启动2.2.1 在 Seata Release 下载最新版的 Seata Server 并解压得到如下目录:.├──bin├──conf├──file_store└──lib123452.2.2 修改 conf/registry.conf 配置,目前seata支持如下的file、nacos 、apollo、zk、consul的注册中心和配置中心。这里我们以nacos 为例。将 type 改为 nacosregistry{#filenacostype="nacos"nacos{serverAddr="192.168.10.200:8848"namespace="public"cluster="default"}file{name="file.conf"}}config{#file、nacos、apollo、zk、consultype="nacos"nacos{serverAddr="192.168.10.200:8848"namespace="public"cluster="default"}file{name="file.conf"}}123456789101112131415161718192223242526272829serverAddr = “192.168.10.200:8848” :nacos 的地址namespace = “public” :nacos的命名空间默认为publiccluster = “default” :集群设置未默认 default注意:seata0.9.0之后,配置如下, 其中namespace = ""registry{#filenacostype="nacos"nacos{serverAddr="192.168.10.200:8848"namespace=""cluster="default"}file{name="file.conf"}}config{#file、nacos、apollo、zk、consultype="nacos"nacos{serverAddr="192.168.10.200:8848"namespace=""}file{name="file.conf"}}123456789101112131415161718192223242526272.2.3 修改 conf/nacos-config.txt配置注意:如果你的seata是1.1之后的版本请按照如下导入方式操作下载/seata/seata/blob/develop/script/config-center/目录下的config.txt文件放入到seata-server目录下的conf中,可更改文件名为nacos-config.txt。下载/seata/seata/tree/develop/script/config-center/nacos/目录下的nacos-config.py文件(window可用python命令执行,linux也可执行,前提先有安装python)或者nacos-config.sh文件(window下可放在git命令行执行,linux可执行文件)transport.type=TCPtransport.server=NIOtransport.heartbeat=truetransport.thread-factory.boss-thread-prefix=NettyBosstransport.thread-factory.worker-thread-prefix=NettyServerNIOWorkertransport.thread-factory.server-executor-thread-prefix=NettyServerBizHandlertransport.thread-factory.share-boss-worker=falsetransport.thread-factory.client-selector-thread-prefix=NettyClientSelectortransport.thread-factory.client-selector-thread-size=1transport.thread-factory.client-worker-thread-prefix=NettyClientWorkerThreadtransport.thread-factory.boss-thread-size=1transport.thread-factory.worker-thread-size=8transport.shutdown.wait=3service.vgroup_mapping.order-service-seata-service-group=defaultservice.vgroup_mapping.account-service-seata-service-group=defaultservice.vgroup_mapping.storage-service-seata-service-group=defaultservice.vgroup_mapping.business-service-seata-service-group=defaultservice.enableDegrade=falseservice.disable=mit.retry.timeout=-1service.max.rollback.retry.timeout=-mit.buffer.limit=10000client.lock.retry.internal=10client.lock.retry.times=30store.mode=dbstore.file.dir=file_store/datastore.file.max-branch-session-size=16384store.file.max-global-session-size=512store.file.file-write-buffer-cache-size=16384store.file.flush-disk-mode=asyncstore.file.session.reload.read_size=100store.db.driver-class-name=com.mysql.jdbc.Driverstore.db.datasource=dbcpstore.db.db-type=mysqlstore.db.url=jdbc:mysql://192.168.10.200:3306/seata?useUnicode=truestore.db.user=lidongstore.db.password=cwj887766@@store.db.min-conn=1store.db.max-conn=3store.db.global.table=global_tablestore.db.branch.table=branch_tablestore.db.query-limit=100store.db.lock-table=mitting-retry-period=1000recovery.asyn-committing-retry-period=1000recovery.rollbacking-retry-period=1000recovery.timeout-retry-period=1000transaction.undo.data.validation=truetransaction.undo.log.serialization=jacksontransaction.undo.log.save.days=7transaction.undo.log.delete.period=86400000transaction.undo.log.table=undo_logtransport.serialization=pressor=nonemetrics.enabled=falsemetrics.registry-type=compactmetrics.exporter-list=prometheusmetrics.exporter-prometheus-port=9898service.default.grouplist=127.0.0.1:8091123456789101112131415161718192223242526272829303132333435363738394041424344454647484950515253545556575859这里主要修改了如下几项:store.mode :存储模式 默认file 这里我修改为db 模式 ,并且需要三个表global_table、branch_table和lock_tablestore.db.driver-class-name:默认没有,会报错。添加了 com.mysql.jdbc.Driverstore.db.datasource=dbcp :数据源 dbcpstore.db.db-type=mysql : 存储数据库的类型为mysqlstore.db.url=jdbc:mysql://192.168.10.200:3306/seata?useUnicode=true : 修改为自己的数据库url、port、数据库名称store.db.user=lidong :数据库的账号store.db.password=cwj887766@@ :数据库的密码service.vgroup_mapping.order-service-seata-service-group=defaultservice.vgroup_mapping.account-service-seata-service-group=defaultservice.vgroup_mapping.storage-service-seata-service-group=defaultservice.vgroup_mapping.business-service-seata-service-group=default也可以在 Nacos 配置页面添加,data-id 为 service.vgroup_mapping.${YOUR_SERVICE_NAME}-seata-service-group, group 为 SEATA_GROUP, 如果不添加该配置,启动后会提示no available server to connect to services-server注意: 配置文件末尾有空行,需要删除,否则会提示失败,尽管实际上是成功的db模式下的所需的三个表的数据库脚本位于seata\conf\db_store.sqlglobal_table的表结构CREATETABLE`global_table`(`xid`varchar(128)NOTNULL,`transaction_id`bigint(20)DEFAULTNULL,`status`tinyint(4)NOTNULL,`application_id`varchar(64)DEFAULTNULL,`transaction_service_group`varchar(64)DEFAULTNULL,`transaction_name`varchar(64)DEFAULTNULL,`timeout`int(11)DEFAULTNULL,`begin_time`bigint(20)DEFAULTNULL,`application_data`varchar(2000)DEFAULTNULL,`gmt_create`datetimeDEFAULTNULL,`gmt_modified`datetimeDEFAULTNULL,PRIMARYKEY(`xid`),KEY`idx_gmt_modified_status`(`gmt_modified`,`status`),KEY`idx_transaction_id`(`transaction_id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;1234567891011121314151617branch_table的表结构CREATETABLE`branch_table`(`branch_id`bigint(20)NOTNULL,`xid`varchar(128)NOTNULL,`transaction_id`bigint(20)DEFAULTNULL,`resource_group_id`varchar(32)DEFAULTNULL,`resource_id`varchar(256)DEFAULTNULL,`lock_key`varchar(128)DEFAULTNULL,`branch_type`varchar(8)DEFAULTNULL,`status`tinyint(4)DEFAULTNULL,`client_id`varchar(64)DEFAULTNULL,`application_data`varchar(2000)DEFAULTNULL,`gmt_create`datetimeDEFAULTNULL,`gmt_modified`datetimeDEFAULTNULL,PRIMARYKEY(`branch_id`),KEY`idx_xid`(`xid`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;123456789101112131415161718lock_table的表结构createtable`lock_table`(`row_key`varchar(128)notnull,`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,primarykey(`row_key`));1234567891011122.2.4 将 Seata 配置添加到 Nacos 中使用命令如下cdconfshnacos-config.shlocalhost12成功后会提示initnacosconfigfinished,pleasestartseata-server1在 Nacos 管理页面应该可以看到有 59 个 Group 为SEATA_GROUP的配置2.2.5 启动 Seata Server使用db 模式启动cd..sh./bin/seata-server.sh12这时候在 Nacos 的服务列表下面可以看到一个名为serverAddr的服务3 案例分析参考官网中用户购买商品的业务逻辑。整个业务逻辑由4个微服务提供支持:库存服务:扣除给定商品的存储数量。订单服务:根据购买请求创建订单。帐户服务:借记用户帐户的余额。业务服务:处理业务逻辑。请求逻辑架构3.1 github地址springboot-dubbo-seata:/lidong1665/springboot-dubbo-seatasamples-common :公共模块samples-account :用户账号模块samples-order :订单模块samples-storage :库存模块samples-business :业务模块3.2 账户服务:AccountDubboService/***@Author:lidong*@Description账户服务接口*@DateCreatedin/9/516:37*/publicinterfaceAccountDubboService{/***从账户扣钱*/ObjectResponsedecreaseAccount(AccountDTOaccountDTO);}1234567891011123.3 订单服务:OrderDubboService/***@Author:lidong*@Description订单服务接口*@DateCreatedin/9/516:28*/publicinterfaceOrderDubboService{/***创建订单*/ObjectResponse<OrderDTO>createOrder(OrderDTOorderDTO);}1234567891011123.4 库存服务:StorageDubboService/***@Author:lidong*@Description库存服务*@DateCreatedin/9/516:22*/publicinterfaceStorageDubboService{/***扣减库存*/ObjectResponsedecreaseStorage(CommodityDTOcommodityDTO);}123456789101112133.5 业务服务:BusinessService/***@Author:lidong*@Description*@DateCreatedin/9/517:17*/publicinterfaceBusinessService{/***出处理业务服务*@parambusinessDTO*@return*/ObjectResponsehandleBusiness(BusinessDTObusinessDTO);}123456789101112131415业务逻辑的具体实现主要体现在 订单服务的实现和业务服务的实现订单服务的实现@ServicepublicclassTOrderServiceImplextendsServiceImpl<TOrderMapper,TOrder>implementsITOrderService{@Reference(version="1.0.0")privateAccountDubboServiceaccountDubboService;/***创建订单*@Param:OrderDTO订单对象*@Return:OrderDTO订单对象*/@OverridepublicObjectResponse<OrderDTO>createOrder(OrderDTOorderDTO){ObjectResponse<OrderDTO>response=newObjectResponse<>();//扣减用户账户AccountDTOaccountDTO=newAccountDTO();accountDTO.setUserId(orderDTO.getUserId());accountDTO.setAmount(orderDTO.getOrderAmount());ObjectResponseobjectResponse=accountDubboService.decreaseAccount(accountDTO);//生成订单号orderDTO.setOrderNo(UUID.randomUUID().toString().replace("-",""));//生成订单TOrdertOrder=newTOrder();BeanUtils.copyProperties(orderDTO,tOrder);tOrder.setCount(orderDTO.getOrderCount());tOrder.setAmount(orderDTO.getOrderAmount().doubleValue());try{baseMapper.createOrder(tOrder);}catch(Exceptione){response.setStatus(RspStatusEnum.FAIL.getCode());response.setMessage(RspStatusEnum.FAIL.getMessage());returnresponse;}if(objectResponse.getStatus()!=200){response.setStatus(RspStatusEnum.FAIL.getCode());response.setMessage(RspStatusEnum.FAIL.getMessage());returnresponse;}response.setStatus(RspStatusEnum.SUCCESS.getCode());response.setMessage(RspStatusEnum.SUCCESS.getMessage());returnresponse;}}1234567891011121314151617181922232425262728293031323334353637383940414243444546整个业务的实现逻辑@Service@Slf4jpublicclassBusinessServiceImplimplementsBusinessService{@Reference(version="1.0.0")privateStorageDubboServicestorageDubboService;@Reference(version="1.0.0")privateOrderDubboServiceorderDubboService;privatebooleanflag;/***处理业务逻辑*@Param:*@Return:*/@GlobalTransactional(timeoutMills=300000,name="dubbo-gts-seata-example")@OverridepublicObjectResponsehandleBusiness(BusinessDTObusinessDTO){log.info("开始全局事务,XID="+RootContext.getXID());ObjectResponse<Object>objectResponse=newObjectResponse<>();//1、扣减库存CommodityDTOcommodityDTO=newCommodityDTO();commodityDTO.setCommodityCode(businessDTO.getCommodityCode());commodityDTO.setCount(businessDTO.getCount());ObjectResponsestorageResponse=storageDubboService.decreaseStorage(commodityDTO);//2、创建订单OrderDTOorderDTO=newOrderDTO();orderDTO.setUserId(businessDTO.getUserId());orderDTO.setCommodityCode(businessDTO.getCommodityCode());orderDTO.setOrderCount(businessDTO.getCount());orderDTO.setOrderAmount(businessDTO.getAmount());ObjectResponse<OrderDTO>response=orderDubboService.createOrder(orderDTO);//打开注释测试事务发生异常后,全局回滚功能//if(!flag){// throw new RuntimeException("测试抛异常后,分布式事务回滚!");//}if(storageResponse.getStatus()!=200||response.getStatus()!=200){thrownewDefaultException(RspStatusEnum.FAIL);}objectResponse.setStatus(RspStatusEnum.SUCCESS.getCode());objectResponse.setMessage(RspStatusEnum.SUCCESS.getMessage());objectResponse.setData(response.getData());returnobjectResponse;}}123456789101112131415161718192223242526272829303132333435363738394041424344454647484950513.6 使用seata的分布式事务解决方案处理dubbo的分布式事务我们只需要在业务处理的方法handleBusiness添加一个注解 @GlobalTransactional@GlobalTransactional(timeoutMills=300000,name="dubbo-gts-seata-example")@OverridepublicObjectResponsehandleBusiness(BusinessDTObusinessDTO){}12345timeoutMills: 超时时间name :事务名称3.7 准备数据库注意: MySQL必须使用InnoDB engine.创建数据库 并导入数据库脚本DROPDATABASEIFEXISTSseata;CREATEDATABASEseata;USEseata;DROPTABLEIFEXISTS`t_account`;CREATETABLE`t_account`(`id`int(11)NOTNULLAUTO_INCREMENT,`user_id`varchar(255)DEFAULTNULL,`amount`double(14,2)DEFAULT'0.00',PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=2DEFAULTCHARSET=utf8;--------------------------------Recordsoft_account------------------------------INSERTINTO`t_account`VALUES('1','1','4000.00');--------------------------------Tablestructurefort_order------------------------------DROPTABLEIFEXISTS`t_order`;CREATETABLE`t_order`(`id`int(11)NOTNULLAUTO_INCREMENT,`order_no`varchar(255)DEFAULTNULL,`user_id`varchar(255)DEFAULTNULL,`commodity_code`varchar(255)DEFAULTNULL,`count`int(11)DEFAULT'0',`amount`double(14,2)DEFAULT'0.00',PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=64DEFAULTCHARSET=utf8;--------------------------------Recordsoft_order--------------------------------------------------------------Tablestructurefort_storage------------------------------DROPTABLEIFEXISTS`t_storage`;CREATETABLE`t_storage`(`id`int(11)NOTNULLAUTO_INCREMENT,`commodity_code`varchar(255)DEFAULTNULL,`name`varchar(255)DEFAULTNULL,`count`int(11)DEFAULT'0',PRIMARYKEY(`id`),UNIQUEKEY`commodity_code`(`commodity_code`))ENGINE=InnoDBAUTO_INCREMENT=2DEFAULTCHARSET=utf8;--------------------------------Recordsoft_storage------------------------------INSERTINTO`t_storage`VALUES('1','C01140001','水杯','1000');--------------------------------Tablestructureforundo_log--注意此处0.3.0+增加唯一索引ux_undo_log------------------------------DROPTABLEIFEXISTS`undo_log`;CREATETABLE`undo_log`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`branch_id`bigint(20)NOTNULL,`xid`varchar(100)NOTNULL,`context`varchar(128)NOTNULL,`rollback_info`longblobNOTNULL,`log_status`int(11)NOTNULL,`log_created`datetimeNOTNULL,`log_modified`datetimeNOTNULL,`ext`varchar(100)DEFAULTNULL,PRIMARYKEY(`id`),UNIQUEKEY`ux_undo_log`(`xid`,`branch_id`))ENGINE=InnoDBAUTO_INCREMENT=1DEFAULTCHARSET=utf8;--------------------------------Recordsofundo_log------------------------------SETFOREIGN_KEY_CHECKS=1;1234567891011121314151617181922232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576会看到如上的4个表+-------------------------+|Tables_in_seata|+-------------------------+|t_account||t_order||t_storage||undo_log|+-------------------------+12345678这里为了简化我将这个三张表创建到一个库中,使用是三个数据源来实现。3.8 我们以账号服务samples-account为例 ,分析需要注意的配置项目3.8.1 引入的依赖<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="/POM/4.0.0"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.5.RELEASE</version><relativePath/><!--lookupparentfromrepository--></parent><artifactId>springboot-dubbo-seata</artifactId><packaging>pom</packaging><name>springboot-dubbo-seata</name><groupId>io.seata</groupId><version>1.0.0</version><description>samples-account</description》<properties><springboot.verison>2.1.5.RELEASE</springboot.verison><java.version>1.8</java.version><druid.version>1.1.10</druid.version><mybatis.version>1.3.2</mybatis.version><mybatis-plus.version>2.3</mybatis-plus.version><nacos.version>0.2.3</nacos.version><lombok.version>1.16.22</lombok.version><dubbo.version>2.7.3</dubbo.version><nacos-client.verison>1.1.3</nacos-client.verison><seata.version>0.8.0</seata.version><netty.version>4.1.32.Final</netty.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${springboot.verison}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>${springboot.verison}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>${springboot.verison}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>${druid.version}</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis.version}</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>${mybatis-plus.version}</version></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo</artifactId><version>${dubbo.version}</version><exclusions><exclusion><artifactId>spring</artifactId><groupId>org.springframework</groupId></exclusion></exclusions></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>${dubbo.version}</version></dependency><!--/artifact/org.apache.dubbo/dubbo-config-spring--><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-config-spring</artifactId><version>${dubbo.version}</version></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-registry-nacos</artifactId><version>${dubbo.version}</version></dependency><!--/artifact/io.seata/seata-all--><dependency><groupId>io.seata</groupId><artifactId>seata-all</artifactId><version>${seata.version}</version></dependency><dependency><groupId>com.alibaba.nacos</groupId><artifactId>nacos-client</artifactId><version>${nacos-client.verison}</version></dependency><!--/artifact/com.alibaba.boot/nacos-config-spring-boot-starter--><dependency><groupId>com.alibaba.boot</groupId><artifactId>nacos-config-spring-boot-starter</artifactId><version>${nacos.version}</version><exclusions><exclusion><artifactId>nacos-client</artifactId><groupId>com.alibaba.nacos</groupId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${springboot.verison}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency><dependency><groupId>ty</groupId><artifactId>netty-all</artifactId><version>${netty.version}</version></dependency><dependency><groupId>com.alibaba.spring</groupId><artifactId>spring-context-support</artifactId><version>1.0.2</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-deploy-plugin</artifactId><configuration><skip>true</skip></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>${java.version}</source><target>${java.version}</target></configuration></plugin></plugins></build></project>1234567891011121314151617181922232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811911122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184注意:seata-all: 这个是seata 所需的主要依赖dubbo-spring-boot-starter: springboot dubbo的依赖其他的就不一一介绍,其他的一目了然,就知道是干什么的。3.8.2 application.properties配置server.port=8102spring.application.name=dubbo-account-example#====================================Dubbo配置===============================================dubbo.application.id= dubbo-account-exampledubbo.application.name= dubbo-account-exampledubbo.protocol.id=dubbodubbo.protocol.name=dubbodubbo.registry.id=dubbo-account-example-registrydubbo.registry.address=nacos://192.168.10.200:8848dubbo.protocol.port=20880dubbo.application.qosEnable=falsedubbo.config-center.address=nacos://192.168.10.200:8848dubbo.metadata-report.address=nacos://192.168.10.200:8848#====================================mysql 配置============================================spring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.url=jdbc:mysql://192.168.10.200:3306/seata?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=truespring.datasource.username=lidongspring.datasource.password=cwj887766@@#=====================================mybatis 配置======================================mybatis.mapper-locations=classpath*:/mapper/*.xml12345678910111213141516171819222324253.8.3 registry.conf 配置 (naocs的配置)registry {# file nacostype = "nacos"nacos {serverAddr = "192.168.10.200"namespace = "public"cluster = "default"}file {name = "file.conf"}}config {# file、nacos 、apollo、zk、consultype = "nacos"file {name = "file.conf"}nacos {serverAddr = "192.168.10.200"namespace = "public"cluster = "default"}}1234567891011121314151617181922232425262728293.8.5 SeataAutoConfig 配置packageio.seata.samples.integration.account.config;importcom.alibaba.druid.pool.DruidDataSource;importio.seata.rm.datasource.DataSourceProxy;importio.seata.spring.annotation.GlobalTransactionScanner;importorg.apache.ibatis.session.SqlSessionFactory;importorg.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;importorg.mybatis.spring.SqlSessionFactoryBean;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.autoconfigure.jdbc.DataSourceProperties;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.context.annotation.Primary;importorg.springframework.core.io.support.PathMatchingResourcePatternResolver;/***@Author:llidong*@Descriptionseataglobalconfiguration*@DateCreatedin/9/0510:28*/@ConfigurationpublicclassSeataAutoConfig{/***autowireddatasourceconfig*/@AutowiredprivateDataSourcePropertiesdataSourceProperties;/***initduriddatasource**@Return:druidDataSourcedatasourceinstance*/@Bean@PrimarypublicDruidDataSourcedruidDataSource(){DruidDataSourcedruidDataSource=newDruidDataSource();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("Select1fromDUAL");druidDataSource.setTestOnBorrow(false);druidDataSource.setTestOnReturn(false);druidDataSource.setTestWhileIdle(true);druidDataSource.setTimeBetweenEvictionRunsMillis(60000);druidDataSource.setMinEvictableIdleTimeMillis(25200000);druidDataSource.setRemoveAbandoned(true);druidDataSource.setRemoveAbandonedTimeout(1800);druidDataSource.setLogAbandoned(true);returndruidDataSource;}/***initdatasourceproxy*@Param:druidDataSourcedatasourcebeaninstance*@Return:DataSourceProxydatasourceproxy*/@BeanpublicDataSourceProxydataSourceProxy(DruidDataSourcedruidDataSource){returnnewDataSourceProxy(druidDataSource);}/***initmybatissqlSessionFactory*@Param:dataSourceProxydatasourceproxy*@Return:DataSourceProxydatasourceproxy*/@BeanpublicSqlSessionFactorysqlSessionFactory(DataSourceProxydataSourceProxy)throwsException{SqlSessionFactoryBeanfactoryBean=newSqlSessionFactoryBean();factoryBean.setDataSource(dataSourceProxy);factoryBean.setMapperLocations(newPathMatchingResourcePatternResolver().getResources("classpath*:/mapper/*.xml"));returnfactoryBean.getObject();}/***initglobaltransactionscanner**@Return:GlobalTransactionScanner*/@BeanpublicGlobalTransactionScannerglobalTransactionScanner(){returnnewGlobalTransactionScanner("account-gts-seata-example","account-service-seata-service-group");}}1234567891011121314151617181922232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394其中:@BeanpublicGlobalTransactionScannerglobalTransactionScanner(){returnnewGlobalTransactionScanner("account-gts-seata-example","account-service-seata-service-group");}1234GlobalTransactionScanner: 初始化全局的事务扫描器/***InstantiatesanewGlobaltransactionscanner.**@paramapplicationIdtheapplicationid*@paramtxServiceGroupthedefaultservergroup*/publicGlobalTransactionScanner(StringapplicationId,StringtxServiceGroup){this(applicationId,txServiceGroup,DEFAULT_MODE);}123456789applicationId :为应用id 这里我传入的是account-gts-seata-exampletxServiceGroup: 默认server的分组 这里我传入的是account-service-seata-service-group 这个和我们前面在nacos 配置的是保存一致。DEFAULT_MODE:默认的事务模式 为AT_MODE + MT_MODE3.8.6 AccountExampleApplication 启动类的配置packageio.seata.samples.integration.account;importorg.apache.dubbo.config.spring.context.annotation.EnableDubbo;importorg.mybatis.spring.annotation.MapperScan;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.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")publicclassAccountExampleApplication{publicstaticvoidmain(String[]args){SpringApplication.run(AccountExampleApplication.class,args);}}1234567891011121314151617181920@EnableDubbo等同于 @DubboComponentScan和 @EnableDubboConfig组合@DubboComponentScan 扫描 classpaths 下类中添加了 @Service 和 @Reference 将自动注入到spring beans中。@EnableDubboConfig 扫描的dubbo的外部化配置。4 启动所有的sample模块启动 samples-account、samples-order、samples-storage、samples-business并且在nocos的控制台查看注册情况: http://192.168.10.200:8848/nacos/#/serviceManagement我们可以看到上面的服务都已经注册成功。5 测试5. 1 发送一个下单请求使用postman 发送 :http://localhost:8104/business/dubbo/buy参数:{"userId":"1","commodityCode":"C01140001","name":"fan","count":50,"amount":"100"}1234567返回{"status":200,"message":"成功","data":null}12345这时候控制台:-09-05 12:17:34.097 INFO 21860---[nio-8104-exec-4] i.s.s.i.c.controller.BusinessController :请求参数:BusinessDTO(userId=1, commodityCode=C01140001, name=fan, count=50, amount=100)-09-0512:17:34.146INFO21860---[nio-8104-exec-4]i.seata.tm.api.DefaultGlobalTransaction:Beginnewglobaltransaction[192.168.10.200:8091:380638]-09-0512:17:34.150INFO21860---[nio-8104-exec-4]i.s.s.i.c.service.BusinessServiceImpl:开始全局事务,XID=192.168.10.200:8091:380638-09-0512:17:36.966INFO21860---[nio-8104-exec-4]i.seata.tm.api.DefaultGlobalTransaction:[192.168.10.200:8091:380638]commitstatus:Committed1234事务提交成功,我们来看一下数据库数据变化t_accountt_ordert_storage数据没有问题。5.2 测试回滚我们samples-business将BusinessServiceImpl的handleBusiness2 下面的代码去掉注释if(!flag){thrownewRuntimeException("测试抛异常后,分布式事务回滚!");}123使用postman 发送 :http://localhost:8104/business/dubbo/buy2.响应结果:{"timestamp":"-09-05T04:29:34.178+0000","status":500,"error":"InternalServerError","message":"测试抛异常后,分布式事务回滚!","path":"/business/dubbo/buy"}1234567控制台-09-05 12:29:32.836 INFO 17264 ---[nio-8104-exec-2] i.s.s.i.c.controller.BusinessController :请求参数:BusinessDTO(userId=1, commodityCode=C01140001, name=fan, count=50, amount=100)-09-0512:29:32.843INFO17264---[nio-8104-exec-2]mon.loader.EnhancedServiceLoader:loadContextCore[null]extensionbyclass[io.seata.core.context.ThreadLocalContextCore]-09-0512:29:32.848INFO17264---[nio-8104-exec-2]mon.loader.EnhancedServiceLoader:loadTransactionManager[null]extensionbyclass[io.seata.tm.DefaultTransactionManager]-09-0512:29:32.849INFO17264---[nio-8104-exec-2]io.seata.tm.TransactionManagerHolder:TransactionManagerSingletonio.seata.tm.DefaultTransactionManager@461585ac-09-0512:29:32.859INFO17264---[nio-8104-exec-2]mon.loader.EnhancedServiceLoader:loadLoadBalance[null]extensionbyclass[io.seata.discovery.loadbalance.RandomLoadBalance]-09-0512:29:32.893INFO17264---[nio-8104-exec-2]i.seata.tm.api.DefaultGlobalTransaction:Beginnewglobaltransaction[192.168.10.200:8091:380674]-09-0512:29:32.897INFO17264---[nio-8104-exec-2]i.s.s.i.c.service.BusinessServiceImpl:开始全局事务,XID=192.168.10.200:8091:380674-09-0512:29:34.143INFO17264---[nio-8104-exec-2]i.seata.tm.api.DefaultGlobalTransaction:[192.168.10.200:8091:380674]rollbackstatus:Rollbacked-09-0512:29:34.158ERROR17264---[nio-8104-exec-2]o.a.c.c.C.[.[.[/].[dispatcherServlet]:Servlet.service()forservlet[dispatcherServlet]incontext with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException:测试抛异常后,分布式事务回滚!] with root causejava.lang.RuntimeException:测试抛异常后,分布式事务回滚!atio.seata.samples.integration.call.service.BusinessServiceImpl.handleBusiness(BusinessServiceImpl.java:60)~[classes/:na]atio.seata.samples.integration.call.service.BusinessServiceImpl$$FastClassBySpringCGLIB$$2ab3d645.invoke(<generated>)~[classes/:na]atorg.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)~[spring-core-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]atio.seata.spring.annotation.GlobalTransactionalInterceptor$1.execute(GlobalTransactionalInterceptor.java:104)~[seata-all-0.8.0.jar:0.8.0]atio.seata.tm.api.TransactionalTemplate.execute(TransactionalTemplate.java:64)~[seata-all-0.8.0.jar:0.8.0]atio.seata.spring.annotation.GlobalTransactionalInterceptor.handleGlobalTransaction(GlobalTransactionalInterceptor.java:101)~[seata-all-0.8.0.jar:0.8.0]atio.seata.spring.annotation.GlobalTransactionalInterceptor.invoke(GlobalTransactionalInterceptor.java:76)~[seata-all-0.8.0.jar:0.8.0]atorg.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]atio.seata.samples.integration.call.service.BusinessServiceImpl$$EnhancerBySpringCGLIB$$cb43f7ab.handleBusiness(<generated>)~[classes/:na]atio.seata.samples.integration.call.controller.BusinessController.handleBusiness(BusinessController.java:37)~[classes/:na]atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)~[na:1.8.0_144]atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)~[na:1.8.0_144]atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)~[na:1.8.0_144]atjava.lang.reflect.Method.invoke(Method.java:498)~[na:1.8.0_144]atorg.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039)~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]atjavax.servlet.http.HttpServlet.service(HttpServlet.java:660)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]atjavax.servlet.http.HttpServlet.service(HttpServlet.java:741)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)~[tomcat-embed-websocket-9.0.19.jar:9.0.19]atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)~[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:836)[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache..NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1747)[tomcat-embed-core-9.0.19.jar:9.0.19]atorg.apache..SocketProcessorBase.run(SocketProcessorBase.java:49)[tomcat-embed-core-9.0.19.jar:9.0.19]atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)[na:1.8.0_144]atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)[na:1.8.0_144]atorg.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)[tomcat-embed-core-9.0.19.jar:9.0.19]atjava.lang.Thread.run(Thread.java:748)[na:1.8.0_144]123456789101112131415161718192223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980我们查看数据库数据,已经回滚,和上面的数据一致。Spring 中的 Controller 和Service是线程安全的吗?一个 SpringBoot 项目该包含哪些?发现一款牛逼的IDEA插件:检测代码漏洞,一键修复!springboot+redis+Interceptor+自定义annotation实现接口自动幂等100W个微信红包封面,速度领取!!!API接口的安全设计验证:ticket,签名,时间戳牛逼,一份基于SSM框架实现的支付宝支付功能,附完整源代码...Redis、Kafka或RabbitMQ,哪个更和微服务更般配?JDK 16 即将发布,看完这些新特性,我感觉已经学不动了..点击阅读全文前往微服务电商教程

如果觉得《SpringBoot+ Dubbo + Mybatis + Nacos +Seata整合来实现Dubbo分布式事务》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。