网站代码 输入文字 跳出内容网站建站哪家公司好

当前位置: 首页 > news >正文

网站代码 输入文字 跳出内容,网站建站哪家公司好,网页设计有限公司,网上做医生哪个网站好一、Seata基本介绍 官网#xff1a;https://seata.apache.org/zh-cn/ Seata 是一款开源的分布式事务解决方案#xff0c;致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式#xff0c;为用户打造一站式的分布式解决方案。 我…一、Seata基本介绍 官网https://seata.apache.org/zh-cn/ Seata 是一款开源的分布式事务解决方案致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式为用户打造一站式的分布式解决方案。 我们只需要使用一个GlobalTransactional注解在业务方法上便可实现分布式事务 Seata的工作流程 纵观整个分布式事务的管理就是全局事务ID的传递和变更让开发者无感知 Seata对分布式事务的协调和控制就是13 1个XIDXID是全局事务的唯一标识它可以在服务的调用链路中传递绑定到服务的事务上下文中 3个概念TC-TM-RM: TCTransaction Coordinator事务协调器维护全局和分支事务的状态驱动全局事务提交或回滚Seata TMTransaction Manager事务管理器定义全局事务的范围开启全局事务、提交或回滚全局事务标注全局GlobalTransactional启动入口动作的微服务模块 RMResource Manager资源管理器管理分支事务处理的资源与TC交谈以注册分支事务和报告分支事务的状态并驱动分支事务提交或回滚数据库。 三个组件相互协作TC以Seata服务器Server形式独立部署TM和RM则是以Seata Client的形式集成在微服务中运行 1、TM向TC申请开启一个全局事务全局事务创建成功并生成一个全局唯一的XID 2、XID在微服务调用链路的上下文中传播 3、RM向TC注册分支事务将其纳入XID对应全局事务的管辖 4、TM向TC发起针对XID的全局提交或回滚决议 5、TC调度XID下管辖的全部分支事务完成提交或回滚请求。 二、Seata下载安装 1、下载 官方地址https://seata.apache.org/zh-cn/unversioned/download/seata-server github地址https://github.com/apache/incubator-seata/releases 2、创建数据库 在mysql8.0数据库创建seate数据库和它所需的表。 sql脚本 建库 CREATE DATABASE seata; USE seata;建表 – ——————————– The script used when storeMode is db ———————————- the table to store GlobalSession dataCREATE TABLE IF NOT EXISTS global_table(xid VARCHAR(128) NOT NULL,transaction_id BIGINT,status TINYINT NOT NULL,application_id VARCHAR(32),transaction_service_group VARCHAR(32),transaction_name VARCHAR(128),timeout INT,begin_time BIGINT,application_data VARCHAR(2000),gmt_create DATETIME,gmt_modified DATETIME,PRIMARY KEY (xid),KEY idx_status_gmt_modified (status , gmt_modified),KEY idx_transaction_id (transaction_id)) ENGINE InnoDBDEFAULT CHARSET utf8mb4;– the table to store BranchSession dataCREATE TABLE IF NOT EXISTS branch_table(branch_id BIGINT NOT NULL,xid VARCHAR(128) NOT NULL,transaction_id BIGINT,resource_group_id VARCHAR(32),resource_id VARCHAR(256),branch_type VARCHAR(8),status TINYINT,client_id VARCHAR(64),application_data VARCHAR(2000),gmt_create DATETIME(6),gmt_modified DATETIME(6),PRIMARY KEY (branch_id),KEY idx_xid (xid)) ENGINE InnoDBDEFAULT CHARSET utf8mb4;– the table to store lock dataCREATE TABLE IF NOT EXISTS lock_table(row_key VARCHAR(128) NOT NULL,xid VARCHAR(128),transaction_id BIGINT,branch_id BIGINT NOT NULL,resource_id VARCHAR(256),table_name VARCHAR(32),pk VARCHAR(36),status TINYINT NOT NULL DEFAULT 0 COMMENT 0:locked ,1:rollbacking,gmt_create DATETIME,gmt_modified DATETIME,PRIMARY KEY (row_key),KEY idx_status (status),KEY idx_branch_id (branch_id),KEY idx_xid (xid)) ENGINE InnoDBDEFAULT CHARSET utf8mb4;CREATE TABLE IF NOT EXISTS distributed_lock(lock_key CHAR(20) NOT NULL,lock_value VARCHAR(20) NOT NULL,expire BIGINT,primary key (lock_key)) ENGINE InnoDBDEFAULT CHARSET utf8mb4;INSERT INTO distributed_lock (lock_key, lock_value, expire) VALUES (AsyncCommitting, , 0);INSERT INTO distributed_lock (lock_key, lock_value, expire) VALUES (RetryCommitting, , 0);INSERT INTO distributed_lock (lock_key, lock_value, expire) VALUES (RetryRollbacking, , 0);INSERT INTO distributed_lock (lock_key, lock_value, expire) VALUES (TxTimeoutCheck, , 0); 3、更改配置 修改\seata\conf路径下的application.yml文件 # Copyright 1999-2019 Seata.io Group. #

Licensed under the Apache License, Version 2.0 (the License);

you may not use this file except in compliance with the License.

You may obtain a copy of the License at

#

http://www.apache.org/licenses/LICENSE-2.0

#

Unless required by applicable law or agreed to in writing, software

distributed under the License is distributed on an AS IS BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and

limitations under the License.server:port: 7091spring:application:name: seata-serverlogging:config: classpath:logback-spring.xmlfile:path: \({log.home:\){user.home}/logs/seata}extend:logstash-appender:destination: 127.0.0.1:4560kafka-appender:bootstrap-servers: 127.0.0.1:9092topic: logback_to_logstashconsole:user:username: seatapassword: seata

seata:config:type: nacosnacos:server-addr: 127.0.0.1:8848namespace:group: SEATA_GROUP #后续自己在nacos里面新建,不想新建SEATA_GROUP就写DEFAULT_GROUPusername: nacospassword: nacosregistry:type: nacosnacos:application: seata-serverserver-addr: 127.0.0.1:8848group: SEATA_GROUP #后续自己在nacos里面新建,不想新建SEATA_GROUP就写DEFAULT_GROUPnamespace:cluster: defaultusername: nacospassword: nacos store:mode: dbdb:datasource: druiddb-type: mysqldriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/seata?characterEncodingutf8useSSLfalseserverTimezoneGMT%2B8rewriteBatchedStatementstrueallowPublicKeyRetrievaltrueuser: rootpassword: 123456min-conn: 10max-conn: 100global-table: global_tablebranch-table: branch_tablelock-table: lock_tabledistributed-lock-table: distributed_lockquery-limit: 1000max-wait: 5000security:secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017tokenValidityInMilliseconds: 1800000ignore:urls: /,//*.css,//.js,/**/.html,//*.map,//.svg,/**/.png,//*.jpeg,//*.ico,/api/v1/auth/login,/metadata/v1/** 4、运行Nacos startup.cmd -m standalone 5、运行Seata 到~\seata\bin路径下双击seata-server.bat 访问http://localhost:7091/ 用户名和密码都是seata 查看nacos 三、Seata数据库和表准备 订单库存账户 3个业务数据库 案例需求 这里我们创建三个服务一个订单服务一个库存服务一个账户服务。 当用户下单时会在订单服务中创建一个订单然后通过远程调用库存服务来扣减下单商品的库存 再通过远程调用账户服务来扣减用户账户里面的余额 最后在订单服务中修改订单状态为已完成。该操作跨越三个数据库有两次远程调用很明显会有分布式事务问题。 1、创建seata_order库和表 #orderCREATE DATABASE seata_order;USE seata_order;CREATE TABLE t_order(id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,user_id BIGINT(11) DEFAULT NULL COMMENT 用户id,product_id BIGINT(11)DEFAULT NULL COMMENT 产品id,count INT(11) DEFAULT NULL COMMENT 数量,money DECIMAL(11,0) DEFAULT NULL COMMENT 金额,status INT(1) DEFAULT NULL COMMENT 订单状态: 0:创建中; 1:已完结)ENGINEINNODB AUTO_INCREMENT1 DEFAULT CHARSETutf8;SELECT * FROM t_order;– for AT mode you must to init this sql for you business database. the seata server not need it.CREATE TABLE IF NOT EXISTS undo_log(branch_id BIGINT NOT NULL COMMENT branch transaction id,xid VARCHAR(128) NOT NULL COMMENT global transaction id,context VARCHAR(128) NOT NULL COMMENT undo_log context,such as serialization,rollback_info LONGBLOB NOT NULL COMMENT rollback info,log_status INT(11) NOT NULL COMMENT 0:normal status,1:defense status,log_created DATETIME(6) NOT NULL COMMENT create datetime,log_modified DATETIME(6) NOT NULL COMMENT modify datetime,UNIQUE KEY ux_undo_log (xid, branch_id)) ENGINE InnoDB AUTO_INCREMENT 1 DEFAULT CHARSET utf8mb4 COMMENT AT transaction mode undo table;ALTER TABLE undo_log ADD INDEX ix_log_created (log_created);2、创建seata_storage库和表 #storageCREATE DATABASE seata_storage;USE seata_storage;CREATE TABLE t_storage(id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,product_id BIGINT(11) DEFAULT NULL COMMENT 产品id,total INT(11) DEFAULT NULL COMMENT 总库存,used INT(11) DEFAULT NULL COMMENT 已用库存,residue INT(11) DEFAULT NULL COMMENT 剩余库存)ENGINEINNODB AUTO_INCREMENT1 DEFAULT CHARSETutf8;INSERT INTO t_storage(id,product_id,total,used,residue)VALUES(1,1,100,0,100);SELECT * FROM t_storage;– for AT mode you must to init this sql for you business database. the seata server not need it.CREATE TABLE IF NOT EXISTS undo_log(branch_id BIGINT NOT NULL COMMENT branch transaction id,xid VARCHAR(128) NOT NULL COMMENT global transaction id,context VARCHAR(128) NOT NULL COMMENT undo_log context,such as serialization,rollback_info LONGBLOB NOT NULL COMMENT rollback info,log_status INT(11) NOT NULL COMMENT 0:normal status,1:defense status,log_created DATETIME(6) NOT NULL COMMENT create datetime,log_modified DATETIME(6) NOT NULL COMMENT modify datetime,UNIQUE KEY ux_undo_log (xid, branch_id)) ENGINE InnoDB AUTO_INCREMENT 1 DEFAULT CHARSET utf8mb4 COMMENT AT transaction mode undo table;ALTER TABLE undo_log ADD INDEX ix_log_created (log_created);3、创建seata_account库和表 #accountcreate database seata_account;use seata_account;CREATE TABLE t_account(id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT id,user_id BIGINT(11) DEFAULT NULL COMMENT 用户id,total DECIMAL(10,0) DEFAULT NULL COMMENT 总额度,used DECIMAL(10,0) DEFAULT NULL COMMENT 已用余额,residue DECIMAL(10,0) DEFAULT 0 COMMENT 剩余可用额度)ENGINEINNODB AUTO_INCREMENT2 DEFAULT CHARSETutf8;INSERT INTO t_account(id,user_id,total,used,residue)VALUES(1,1,1000,0,1000);SELECT * FROM t_account;– for AT mode you must to init this sql for you business database. the seata server not need it.CREATE TABLE IF NOT EXISTS undo_log(branch_id BIGINT NOT NULL COMMENT branch transaction id,xid VARCHAR(128) NOT NULL COMMENT global transaction id,context VARCHAR(128) NOT NULL COMMENT undo_log context,such as serialization,rollback_info LONGBLOB NOT NULL COMMENT rollback info,log_status INT(11) NOT NULL COMMENT 0:normal status,1:defense status,log_created DATETIME(6) NOT NULL COMMENT create datetime,log_modified DATETIME(6) NOT NULL COMMENT modify datetime,UNIQUE KEY ux_undo_log (xid, branch_id)) ENGINE InnoDB AUTO_INCREMENT 1 DEFAULT CHARSET utf8mb4 COMMENT AT transaction mode undo table;ALTER TABLE undo_log ADD INDEX ix_log_created (log_created);4、最终效果 undo_log表是AT模式专用其他模式不需要 undo_log表的作用 用于回滚操作记录每个分支事务在执行过程中的原始数据当发生异常时可以通过这些日志恢复数据到初始状态保证事务的原子性 四、Seata微服务编码落地实现 1、业务需求 下订单-》减库存-》扣余额-》改订单状态 2、Mybatis一键生成 config.properties #t_pay\u8868\u5305\u540D package.namecom.atguigu.cloud# mysql8.0 #jdbc.driverClass com.mysql.cj.jdbc.Driver #jdbc.url jdbc:mysql://localhost:3306/db2024?characterEncodingutf8useSSLfalseserverTimezoneGMT%2B8rewriteBatchedStatementstrueallowPublicKeyRetrievaltrue #jdbc.user root #jdbc.password 123456# seata_order #jdbc.driverClass com.mysql.cj.jdbc.Driver #jdbc.url jdbc:mysql://localhost:3306/seata_order?characterEncodingutf8useSSLfalseserverTimezoneGMT%2B8rewriteBatchedStatementstrueallowPublicKeyRetrievaltrue #jdbc.user root #jdbc.password 123456# seata_storage #jdbc.driverClass com.mysql.cj.jdbc.Driver #jdbc.url jdbc:mysql://localhost:3306/seata_storage?characterEncodingutf8useSSLfalseserverTimezoneGMT%2B8rewriteBatchedStatementstrueallowPublicKeyRetrievaltrue #jdbc.user root #jdbc.password 123456# seata_account jdbc.driverClass com.mysql.cj.jdbc.Driver jdbc.url jdbc:mysql://localhost:3306/seata_account?characterEncodingutf8useSSLfalseserverTimezoneGMT%2B8rewriteBatchedStatementstrueallowPublicKeyRetrievaltrue jdbc.user root jdbc.password 123456generatorConfig.xml ?xml version1.0 encodingUTF-8? !DOCTYPE generatorConfigurationPUBLIC -//mybatis.org//DTD MyBatis Generator Configuration 1.0//ENhttp://mybatis.org/dtd/mybatis-generator-config_1_0.dtdgeneratorConfigurationproperties resourceconfig.properties/context idMysql targetRuntimeMyBatis3Simple defaultModelTypeflatproperty namebeginningDelimiter value/property nameendingDelimiter value/plugin typetk.mybatis.mapper.generator.MapperPluginproperty namemappers valuetk.mybatis.mapper.common.Mapper/property namecaseSensitive valuetrue//pluginjdbcConnection driverClass\({jdbc.driverClass}connectionURL\){jdbc.url}userId\({jdbc.user}password\){jdbc.password}/jdbcConnectionjavaModelGenerator targetPackage\({package.name}.entities targetProjectsrc/main/java/sqlMapGenerator targetPackage\){package.name}.mapper targetProjectsrc/main/java/javaClientGenerator targetPackage${package.name}.mapper targetProjectsrc/main/java typeXMLMAPPER/!– table tableNamet_pay domainObjectNamePay– !– generatedKey columnid sqlStatementJDBC/– !– /table–!– seata_order – !– table tableNamet_order domainObjectNameOrder– !– generatedKey columnid sqlStatementJDBC/– !– /table–!–seata_storage– !– table tableNamet_storage domainObjectNameStorage– !– generatedKey columnid sqlStatementJDBC/– !– /table–!–seata_account–table tableNamet_account domainObjectNameAccountgeneratedKey columnid sqlStatementJDBC//table/context /generatorConfiguration最终效果
3、修改公共微服务模块 新增StorageFeignApi package com.atguigu.cloud.apis;import com.atguigu.cloud.resp.ResultData; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam;FeignClient(value seata-storage-service) public interface StorageFeignApi {/*** 扣减库存*/PostMapping(value /storage/decrease)ResultData decrease(RequestParam(productId) Long productId, RequestParam(count) Integer count); }新增AccountFeignApi package com.atguigu.cloud.apis;import com.atguigu.cloud.resp.ResultData; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam;FeignClient(value seata-account-service) public interface AccountFeignApi {//扣减账户余额PostMapping(/account/decrease)ResultData decrease(RequestParam(userId) Long userId, RequestParam(money) Long money); }4、新建订单Order微服务 1建Moduleseata-order-service2001 2改POM ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdcom.atguigu.cloud/groupIdartifactIdcloud2024/artifactIdversion1.0-SNAPSHOT/version/parentartifactIdseata-order-service2001/artifactIdpropertiesmaven.compiler.source17/maven.compiler.sourcemaven.compiler.target17/maven.compiler.targetproject.build.sourceEncodingUTF-8/project.build.sourceEncoding/propertiesdependencies!– nacos –dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId/dependency!–alibaba-seata–dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-seata/artifactId/dependency!–openfeign–dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId/dependency!–loadbalancer–dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-loadbalancer/artifactId/dependency!–cloud_commons_utils–dependencygroupIdcom.atguigu.cloud/groupIdartifactIdcloud-api-commons/artifactIdversion1.0-SNAPSHOT/version/dependency!–web actuator–dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency!–SpringBoot集成druid连接池–dependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactId/dependency!– Swagger3 调用方式 http://你的主机IP地址:5555/swagger-ui/index.html –dependencygroupIdorg.springdoc/groupIdartifactIdspringdoc-openapi-starter-webmvc-ui/artifactId/dependency!–mybatis和springboot整合–dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactId/dependency!–Mysql数据库驱动8 –dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependency!–persistence–dependencygroupIdjavax.persistence/groupIdartifactIdpersistence-api/artifactId/dependency!–通用Mapper4–dependencygroupIdtk.mybatis/groupIdartifactIdmapper/artifactId/dependency!–hutool–dependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactId/dependency!– fastjson2 –dependencygroupIdcom.alibaba.fastjson2/groupIdartifactIdfastjson2/artifactId/dependency!–lombok–dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.28/versionscopeprovided/scope/dependency!–test–dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build /project3写YML server:port: 2001spring:application:name: seata-order-servicecloud:nacos:discovery:server-addr: localhost:8848 #Nacos服务注册中心地址# applicationName druid-mysql8 driverdatasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/seata_order?characterEncodingutf8useSSLfalseserverTimezoneGMT%2B8rewriteBatchedStatementstrueallowPublicKeyRetrievaltrueusername: rootpassword: 123456

mybatis

mybatis:mapper-locations: classpath:mapper/.xmltype-aliases-package: com.atguigu.cloud.entitiesconfiguration:map-underscore-to-camel-case: true# seata seata:registry:type: nacosnacos:server-addr: 127.0.0.1:8848namespace: group: SEATA_GROUPapplication: seata-servertx-service-group: default_tx_group # 事务组由它获得TC服务的集群名称service:vgroup-mapping: default_tx_group: default # 事务组与TC服务集群的映射关系data-source-proxy-mode: ATlogging:level:io:seata: info 4主启动 package com.atguigu.cloud;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; import tk.mybatis.spring.annotation.MapperScan;SpringBootApplication MapperScan(com.atguigu.cloud.mapper) //import tk.mybatis.spring.annotation.MapperScan; EnableDiscoveryClient //服务注册和发现 EnableFeignClients public class SeataOrderMainApp2001 {public static void main(String[] args){SpringApplication.run(SeataOrderMainApp2001.class,args);} }5业务类 新建entitiesmapper文件夹存放mybatis一键生成的代码 OrderService接口实现 package com.atguigu.cloud.service.impl;import com.atguigu.cloud.apis.AccountFeignApi; import com.atguigu.cloud.apis.StorageFeignApi; import com.atguigu.cloud.entities.Order; import com.atguigu.cloud.mapper.OrderMapper; import com.atguigu.cloud.service.OrderService; import io.seata.core.context.RootContext; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import tk.mybatis.mapper.entity.Example;import javax.persistence.criteria.Root;/** ClassName OrderServiceImpl* Author link* Date: 2024/11/14 上午11:08* Version v1.0* Description:下订单-减库存-扣余额-改(订单)状态/ Service Slf4j public class OrderServiceImpl implements OrderService {Resourceprivate OrderMapper orderMapper;Resource//订单微服务通过OpenFeign去调用库存微服务private StorageFeignApi storageFeignApi;Resource//订单微服务通过OpenFeign去调用账户微服务private AccountFeignApi accountFeignApi;Overridepublic void create(Order order) {String xid RootContext.getXID();//1. 新建订单log.info(开始新建订单\txid_order: xid);order.setStatus(0);int insert orderMapper.insert(order);Order orderFromDB null;if (insert0){orderFromDB orderMapper.selectOne(order);log.info(——- 新建订单成功orderFromDB info: orderFromDB);System.out.println();//2. 扣减库存log.info(——- 订单微服务开始调用Storage库存做扣减count);storageFeignApi.decrease(order.getProductId(), order.getCount());log.info(——- 订单微服务结束调用Storage库存做扣减完成);System.out.println();//3. 扣减账号余额log.info(——- 订单微服务开始调用Account账号做扣减money);accountFeignApi.decrease(order.getProductId(), order.getMoney());log.info(——- 订单微服务结束调用Account账号做扣减完成);System.out.println();//4. 修改订单状态//订单状态status0创建中1已完结log.info(——- 修改订单状态);System.out.println();orderFromDB.setStatus(1);Example whereConditionnew Example(Order.class);Example.Criteria criteriawhereCondition.createCriteria();criteria.andEqualTo(userId,orderFromDB.getUserId());criteria.andEqualTo(status,0);int updateResult orderMapper.updateByExampleSelective(orderFromDB, whereCondition);log.info(——- 修改订单状态完成\tupdateResult);log.info(——- orderFromDB info: orderFromDB);}System.out.println();log.info(结束新建订单\txid_order: xid);} } OrdeController接口实现 package com.atguigu.cloud.controller;import com.atguigu.cloud.entities.Order; import com.atguigu.cloud.resp.ResultData; import com.atguigu.cloud.service.OrderService; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;/** ClassName OrderController* Author link* Date: 2024/11/14 上午11:15* Version v1.0* Description:/ RestController public class OrderController {Resourceprivate OrderService orderService;/** 创建订单*/GetMapping(/order/create)public ResultData create(Order order){orderService.create(order);return ResultData.success(order);} }5、新建库存Storage微服务 1建Moduleseata-storage-service2002 2改POM ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdcom.atguigu.cloud/groupIdartifactIdcloud2024/artifactIdversion1.0-SNAPSHOT/version/parentartifactIdseata-storage-service2002/artifactIdpropertiesmaven.compiler.source17/maven.compiler.sourcemaven.compiler.target17/maven.compiler.targetproject.build.sourceEncodingUTF-8/project.build.sourceEncoding/propertiesdependencies!– nacos –dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId/dependency!–alibaba-seata–dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-seata/artifactId/dependency!–openfeign–dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId/dependency!–loadbalancer–dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-loadbalancer/artifactId/dependency!–cloud_commons_utils–dependencygroupIdcom.atguigu.cloud/groupIdartifactIdcloud-api-commons/artifactIdversion1.0-SNAPSHOT/version/dependency!–web actuator–dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency!–SpringBoot集成druid连接池–dependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactId/dependency!– Swagger3 调用方式 http://你的主机IP地址:5555/swagger-ui/index.html –dependencygroupIdorg.springdoc/groupIdartifactIdspringdoc-openapi-starter-webmvc-ui/artifactId/dependency!–mybatis和springboot整合–dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactId/dependency!–Mysql数据库驱动8 –dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependency!–persistence–dependencygroupIdjavax.persistence/groupIdartifactIdpersistence-api/artifactId/dependency!–通用Mapper4–dependencygroupIdtk.mybatis/groupIdartifactIdmapper/artifactId/dependency!–hutool–dependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactId/dependency!– fastjson2 –dependencygroupIdcom.alibaba.fastjson2/groupIdartifactIdfastjson2/artifactId/dependency!–lombok–dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.28/versionscopeprovided/scope/dependency!–test–dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build /project3写YML server:port: 2002spring:application:name: seata-storage-servicecloud:nacos:discovery:server-addr: localhost:8848 #Nacos服务注册中心地址# applicationName druid-mysql8 driverdatasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/seata_storage?characterEncodingutf8useSSLfalseserverTimezoneGMT%2B8rewriteBatchedStatementstrueallowPublicKeyRetrievaltrueusername: rootpassword: 123456

mybatis

mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.atguigu.cloud.entitiesconfiguration:map-underscore-to-camel-case: true

seata

seata:registry:type: nacosnacos:server-addr: 127.0.0.1:8848namespace: group: SEATA_GROUPapplication: seata-servertx-service-group: default_tx_group # 事务组由它获得TC服务的集群名称service:vgroup-mapping:default_tx_group: default # 事务组与TC服务集群的映射关系data-source-proxy-mode: ATlogging:level:io:seata: info 4主启动 package com.atguigu.cloud;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; import tk.mybatis.spring.annotation.MapperScan;SpringBootApplication MapperScan(com.atguigu.cloud.mapper) //import tk.mybatis.spring.annotation.MapperScan; EnableDiscoveryClient //服务注册和发现 EnableFeignClients public class SeataStorageMainApp2002 {public static void main(String[] args){SpringApplication.run(SeataStorageMainApp2002.class,args);} }5业务类 新建entitiesmapper文件夹存放mybatis一键生成的代码 StorageMapper接口实现 package com.atguigu.cloud.mapper;import com.atguigu.cloud.entities.Storage; import org.apache.ibatis.annotations.Param; import tk.mybatis.mapper.common.Mapper;public interface StorageMapper extends MapperStorage {/*** 扣减库存/void decrease(Param(productId) Long productId, Param(count) Integer count); }?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.atguigu.cloud.mapper.StorageMapperresultMap idBaseResultMap typecom.atguigu.cloud.entities.Storage!–WARNING - mbg.generated–id columnid jdbcTypeBIGINT propertyid /result columnproduct_id jdbcTypeBIGINT propertyproductId /result columntotal jdbcTypeINTEGER propertytotal /result columnused jdbcTypeINTEGER propertyused /result columnresidue jdbcTypeINTEGER propertyresidue //resultMapupdate iddecreaseUPDATEt_storageSETused used #{count},residue residue - #{count}WHERE product_id #{productId}/update /mapperStorageService接口实现 package com.atguigu.cloud.service.impl.impl;import com.atguigu.cloud.mapper.StorageMapper; import com.atguigu.cloud.service.impl.StorageService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service;/** ClassName StorageServiceImpl* Author link* Date: 2024/11/14 上午11:55* Version v1.0* Description:/ Service Slf4j public class StorageServiceImpl implements StorageService {Resourceprivate StorageMapper storageMapper;/** 扣减库存/Overridepublic void decrease(Long productId, Integer count) {log.info(——-storage-service中扣减库存开始);storageMapper.decrease(productId, count);log.info(——-storage-service中扣减库存结束);}}StorageController接口实现 package com.atguigu.cloud.controller;import com.atguigu.cloud.resp.ResultData; import com.atguigu.cloud.service.impl.StorageService; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;/** ClassName StorageController* Author link* Date: 2024/11/14 下午1:38* Version v1.0* Description:/ RestController public class StorageController {Resourceprivate StorageService storageService;/** 扣减库存*/RequestMapping(/storage/decrease)public ResultData decrease(Long productId, Integer count) {storageService.decrease(productId, count);return ResultData.success(扣减库存成功!);} }6、新建账户Account微服务 1建Moduleseata-account-service2003 2改POM ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdcom.atguigu.cloud/groupIdartifactIdcloud2024/artifactIdversion1.0-SNAPSHOT/version/parentartifactIdseata-account-service2003/artifactIdpropertiesmaven.compiler.source17/maven.compiler.sourcemaven.compiler.target17/maven.compiler.targetproject.build.sourceEncodingUTF-8/project.build.sourceEncoding/propertiesdependencies!– nacos –dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId/dependency!–alibaba-seata–dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-seata/artifactId/dependency!–openfeign–dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId/dependency!–loadbalancer–dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-loadbalancer/artifactId/dependency!–cloud_commons_utils–dependencygroupIdcom.atguigu.cloud/groupIdartifactIdcloud-api-commons/artifactIdversion1.0-SNAPSHOT/version/dependency!–web actuator–dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency!–SpringBoot集成druid连接池–dependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactId/dependency!– Swagger3 调用方式 http://你的主机IP地址:5555/swagger-ui/index.html –dependencygroupIdorg.springdoc/groupIdartifactIdspringdoc-openapi-starter-webmvc-ui/artifactId/dependency!–mybatis和springboot整合–dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactId/dependency!–Mysql数据库驱动8 –dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependency!–persistence–dependencygroupIdjavax.persistence/groupIdartifactIdpersistence-api/artifactId/dependency!–通用Mapper4–dependencygroupIdtk.mybatis/groupIdartifactIdmapper/artifactId/dependency!–hutool–dependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactId/dependency!– fastjson2 –dependencygroupIdcom.alibaba.fastjson2/groupIdartifactIdfastjson2/artifactId/dependency!–lombok–dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.28/versionscopeprovided/scope/dependency!–test–dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build /project3写YML server:port: 2003spring:application:name: seata-account-servicecloud:nacos:discovery:server-addr: localhost:8848 #Nacos服务注册中心地址# applicationName druid-mysql8 driverdatasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/seata_account?characterEncodingutf8useSSLfalseserverTimezoneGMT%2B8rewriteBatchedStatementstrueallowPublicKeyRetrievaltrueusername: rootpassword: 123456

mybatis

mybatis:mapper-locations: classpath:mapper/.xmltype-aliases-package: com.atguigu.cloud.entitiesconfiguration:map-underscore-to-camel-case: true# seata seata:registry:type: nacosnacos:server-addr: 127.0.0.1:8848namespace: group: SEATA_GROUPapplication: seata-servertx-service-group: default_tx_group # 事务组由它获得TC服务的集群名称service:vgroup-mapping:default_tx_group: default # 事务组与TC服务集群的映射关系data-source-proxy-mode: ATlogging:level:io:seata: info 4主启动 package com.atguigu.cloud;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; import tk.mybatis.spring.annotation.MapperScan;EnableDiscoveryClient EnableFeignClients MapperScan(com.atguigu.cloud.mapper) //import tk.mybatis.spring.annotation.MapperScan; SpringBootApplication public class SeataAccountMainApp2003 {public static void main(String[] args){SpringApplication.run(SeataAccountMainApp2003.class,args);} }5业务类 新建entitiesmapper文件夹存放mybatis一键生成的代码 AccountMapper接口实现 package com.atguigu.cloud.mapper;import com.atguigu.cloud.entities.Account; import org.apache.ibatis.annotations.Param; import tk.mybatis.mapper.common.Mapper;public interface AccountMapper extends MapperAccount {/** param userId* param money 本次消费金额/void decrease(Param(userId) Long userId, Param(money) Long money); }?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.atguigu.cloud.mapper.AccountMapperresultMap idBaseResultMap typecom.atguigu.cloud.entities.Account!–WARNING - mbg.generated–id columnid jdbcTypeBIGINT propertyid /result columnuser_id jdbcTypeBIGINT propertyuserId /result columntotal jdbcTypeDECIMAL propertytotal /result columnused jdbcTypeDECIMAL propertyused /result columnresidue jdbcTypeDECIMAL propertyresidue //resultMap!–money 本次消费金额t_account数据库表total总额度 累计已消费金额(used) 剩余可用额度(residue)–update iddecreaseUPDATEt_accountSETresidue residue - #{money},used used #{money}WHERE user_id #{userId};/update /mapperAccountService接口实现 package com.atguigu.cloud.service.impl.impl;import com.atguigu.cloud.mapper.AccountMapper; import com.atguigu.cloud.service.impl.AccountService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;/** ClassName AccountServiceImpl* Author link* Date: 2024/11/14 下午1:49* Version v1.0* Description:/ Service Slf4j public class AccountServiceImpl implements AccountService {ResourceAccountMapper accountMapper;/** 扣减账户余额/Overridepublic void decrease(Long userId, Long money) {log.info(——-account-service中扣减账户余额开始);accountMapper.decrease(userId,money);//myTimeOut();//int age 100;log.info(——-account-service中扣减账户余额结束);}/** 模拟超时异常全局事务回滚/private static void myTimeOut(){try { TimeUnit.SECONDS.sleep(65); } catch (InterruptedException e) { e.printStackTrace(); }} }AccountController接口实现 package com.atguigu.cloud.controller;import com.atguigu.cloud.resp.ResultData; import com.atguigu.cloud.service.impl.AccountService; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;/** ClassName AccountController* Author link* Date: 2024/11/14 下午1:51* Version v1.0* Description:/ RestController public class AccountController {ResourceAccountService accountService;/** 扣减账户余额/RequestMapping(/account/decrease)public ResultData decrease(RequestParam(userId) Long userId, RequestParam(money) Long money){accountService.decrease(userId,money);return ResultData.success(扣减账户余额成功);} }五、Seata案例测试 1、正常下单情况 启动Nacos、Seata、2001、2002、2003服务 访问http://localhost:2001/order/create?userId1productId1count10money100 报错原因springbootspringcloud版本太高导致和阿里巴巴Seata不兼容 减低父pom版本 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.atguigu.cloud/groupIdartifactIdcloud2024/artifactIdversion1.0-SNAPSHOT/versionpackagingpom/packagingmodulesmodulemybatis_generator2024/modulemodulecloud-provider-payment8001/modulemodulecloud-consumer-order80/modulemodulecloud-api-commons/modulemodulecloud-provider-payment8002/modulemodulecloud-consumer-feign-order80/modulemodulecloud-gateway9527/modulemodulecloudalibaba-provider-payment9001/modulemodulecloudalibaba-consumer-nacos-order83/modulemodulecloudalibaba-config-nacos-client3377/modulemodulecloudalibaba-sentinel-service8401/modulemodulecloudalibaba-sentinel-gateway9528/modulemoduleseata-order-service2001/modulemoduleseata-storage-service2002/modulemoduleseata-account-service2003/module/modulespropertiesmaven.compiler.source17/maven.compiler.sourcemaven.compiler.target17/maven.compiler.targetproject.build.sourceEncodingUTF-8/project.build.sourceEncodinghutool.version5.8.22/hutool.versionlombok.version1.18.26/lombok.versiondruid.version1.1.20/druid.versionmybatis.springboot.version3.0.3/mybatis.springboot.versionmysql.version8.0.11/mysql.versionswagger3.version2.2.0/swagger3.versionmapper.version4.2.3/mapper.versionfastjson2.version2.0.40/fastjson2.versionpersistence-api.version1.0.2/persistence-api.versionspring.boot.test.version3.1.5/spring.boot.test.version !– spring.boot.version3.2.0/spring.boot.version– !– spring.cloud.version2023.0.0/spring.cloud.version–spring.cloud.alibaba.version2022.0.0.0-RC2/spring.cloud.alibaba.versionmicrometer-tracing.version1.2.0/micrometer-tracing.versionmicrometer-observation.version1.12.0/micrometer-observation.versionfeign-micrometer.version12.5/feign-micrometer.versionzipkin-reporter-brave.version2.17.0/zipkin-reporter-brave.version!–仅为了整合openfeign alibaba sentinel和seata的案例降低版本处理下–spring.boot.version3.0.9/spring.boot.versionspring.cloud.version2022.0.2/spring.cloud.version/propertiesdependencyManagementdependencies!–springboot 3.2.0–dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion\({spring.boot.version}/versiontypepom/typescopeimport/scope/dependency!--springcloud 2023.0.0--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-dependencies/artifactIdversion\){spring.cloud.version}/versiontypepom/typescopeimport/scope/dependency!–springcloud alibaba 2022.0.0.0-RC2–dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-alibaba-dependencies/artifactIdversion\({spring.cloud.alibaba.version}/versiontypepom/typescopeimport/scope/dependency!--SpringBoot集成mybatis--dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion\){mybatis.springboot.version}/version/dependency!–Mysql数据库驱动8 –dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion\({mysql.version}/version/dependency!--SpringBoot集成druid连接池--dependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactIdversion\){druid.version}/version/dependency!–通用Mapper4之tk.mybatis–dependencygroupIdtk.mybatis/groupIdartifactIdmapper/artifactIdversion\({mapper.version}/version/dependency!--persistence--dependencygroupIdjavax.persistence/groupIdartifactIdpersistence-api/artifactIdversion\){persistence-api.version}/version/dependency!– fastjson2 –dependencygroupIdcom.alibaba.fastjson2/groupIdartifactIdfastjson2/artifactIdversion\({fastjson2.version}/version/dependency!-- swagger3 调用方式 http://你的主机IP地址:5555/swagger-ui/index.html --dependencygroupIdorg.springdoc/groupIdartifactIdspringdoc-openapi-starter-webmvc-ui/artifactIdversion\){swagger3.version}/version/dependency!–hutool–dependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion\({hutool.version}/version/dependency!--lombok--dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion\){lombok.version}/versionoptionaltrue/optional/dependency!– spring-boot-starter-test –dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdversion\({spring.boot.test.version}/versionscopetest/scope/dependency!--micrometer-tracing-bom导入链路追踪版本中心 1--dependencygroupIdio.micrometer/groupIdartifactIdmicrometer-tracing-bom/artifactIdversion\){micrometer-tracing.version}/versiontypepom/typescopeimport/scope/dependency!–micrometer-tracing指标追踪 2–dependencygroupIdio.micrometer/groupIdartifactIdmicrometer-tracing/artifactIdversion\({micrometer-tracing.version}/version/dependency!--micrometer-tracing-bridge-brave适配zipkin的桥接包 3--dependencygroupIdio.micrometer/groupIdartifactIdmicrometer-tracing-bridge-brave/artifactIdversion\){micrometer-tracing.version}/version/dependency!–micrometer-observation 4–dependencygroupIdio.micrometer/groupIdartifactIdmicrometer-observation/artifactIdversion\({micrometer-observation.version}/version/dependency!--feign-micrometer 5--dependencygroupIdio.github.openfeign/groupIdartifactIdfeign-micrometer/artifactIdversion\){feign-micrometer.version}/version/dependency!–zipkin-reporter-brave 6–dependencygroupIdio.zipkin.reporter2/groupIdartifactIdzipkin-reporter-brave/artifactIdversion${zipkin-reporter-brave.version}/version/dependency/dependencies/dependencyManagement/project查看数据库也发现数据有对应的减少测试正常通过~ 2、超时异常出错没添加GlobalTransactional 修改2003服务的AccountServiceImpl添加超时 package com.atguigu.cloud.service.impl.impl;import com.atguigu.cloud.mapper.AccountMapper; import com.atguigu.cloud.service.impl.AccountService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;/** ClassName AccountServiceImpl* Author link* Date: 2024/11/14 下午1:49* Version v1.0* Description:/ Service Slf4j public class AccountServiceImpl implements AccountService {ResourceAccountMapper accountMapper;/** 扣减账户余额/Overridepublic void decrease(Long userId, Long money) {log.info(——-account-service中扣减账户余额开始);accountMapper.decrease(userId,money);myTimeOut();//int age 100;log.info(——-account-service中扣减账户余额结束);}/** 模拟超时异常全局事务回滚/private static void myTimeOut(){try { TimeUnit.SECONDS.sleep(65); } catch (InterruptedException e) { e.printStackTrace(); }} }测试http://localhost:2001/order/create?userId1productId1count10money100 当库存和账户都扣减完但是因为超时状态没回写库存和账号订单也没做回滚 3、超时异常出错添加GlobalTransactional 在2001微服务模块OrderServiceImpl中添加GlobalTransactional注解 package com.atguigu.cloud.service.impl;import com.atguigu.cloud.apis.AccountFeignApi; import com.atguigu.cloud.apis.StorageFeignApi; import com.atguigu.cloud.entities.Order; import com.atguigu.cloud.mapper.OrderMapper; import com.atguigu.cloud.service.OrderService; import io.seata.core.context.RootContext; import io.seata.spring.annotation.GlobalTransactional; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import tk.mybatis.mapper.entity.Example;import javax.persistence.criteria.Root;/** ClassName OrderServiceImpl* Author link* Date: 2024/11/14 上午11:08* Version v1.0* Description:下订单-减库存-扣余额-改(订单)状态*/ Service Slf4j public class OrderServiceImpl implements OrderService {Resourceprivate OrderMapper orderMapper;Resource//订单微服务通过OpenFeign去调用库存微服务private StorageFeignApi storageFeignApi;Resource//订单微服务通过OpenFeign去调用账户微服务private AccountFeignApi accountFeignApi;OverrideGlobalTransactional(name lk-create-order,rollbackFor Exception.class)public void create(Order order) {String xid RootContext.getXID();//1. 新建订单log.info(开始新建订单\txid_order: xid);order.setStatus(0);int insert orderMapper.insert(order);Order orderFromDB null;if (insert0){orderFromDB orderMapper.selectOne(order);log.info(——- 新建订单成功orderFromDB info: orderFromDB);System.out.println();//2. 扣减库存log.info(——- 订单微服务开始调用Storage库存做扣减count);storageFeignApi.decrease(order.getProductId(), order.getCount());log.info(——- 订单微服务结束调用Storage库存做扣减完成);System.out.println();//3. 扣减账号余额log.info(——- 订单微服务开始调用Account账号做扣减money);accountFeignApi.decrease(order.getProductId(), order.getMoney());log.info(——- 订单微服务结束调用Account账号做扣减完成);System.out.println();//4. 修改订单状态//订单状态status0创建中1已完结log.info(——- 修改订单状态);System.out.println();orderFromDB.setStatus(1);Example whereConditionnew Example(Order.class);Example.Criteria criteriawhereCondition.createCriteria();criteria.andEqualTo(userId,orderFromDB.getUserId());criteria.andEqualTo(status,0);int updateResult orderMapper.updateByExampleSelective(orderFromDB, whereCondition);log.info(——- 修改订单状态完成\tupdateResult);log.info(——- orderFromDB info: orderFromDB);}System.out.println();log.info(结束新建订单\txid_order: xid);} }保留上一步的超时再次测试http://localhost:2001/order/create?userId1productId1count10money100 测试成功数据确实被回滚了 六、Seata总结 AT模式如何做到对业务的无侵入 1、一阶段加载 在一阶段Seata 会拦截“业务 SQL” 1 解析 SQL 语义找到“业务 SQL”要更新的业务数据在业务数据被更新前将其保存成“before image” 2 执行“业务 SQL”更新业务数据在业务数据更新之后 3 其保存成“after image”最后生成行锁。 以上操作全部在一个数据库事务内完成这样保证了一阶段操作的原子性。 2、二阶段分两种情况 正常提交 因为“业务 SQL”在一阶段已经提交至数据库所以Seata框架只需将一阶段保存的快照数据和行锁删掉完成数据清理即可。 异常回滚 二阶段如果是回滚的话Seata 就需要回滚一阶段已经执行的“业务 SQL”还原业务数据。 回滚方式便是用“before image”还原业务数据但在还原前要首先要校验脏写对比“数据库当前业务数据”和 “after image” 如果两份数据完全一致就说明没有脏写可以还原业务数据如果不一致就说明有脏写出现脏写就需要转人工处理。