戴尔电脑网站建设方案范文,重庆网络建站,网站建设的销售话术,商务网站建设策划书范文1. Seata 是什么?
由于业务和技术的发展#xff0c;单体应用被拆分成微服务应用#xff0c;原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源#xff0c;业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证#xff0c; 但是全…1. Seata 是什么?
由于业务和技术的发展单体应用被拆分成微服务应用原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证 但是全局的数据一致性问题没法保证。
Seata 是一款开源的分布式事务解决方案致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式为用户打造一站式的分布式解决方案。https://seata.io/zh-cn/docs/overview/what-is-seata.html
seata分布式事务处理过程的一ID三组件模型
Transaction ID XID 全局唯一的事务ID三组件概念 TC (Transaction Coordinator) - 事务协调者维护全局和分支事务的状态驱动全局事务提交或回滚。TM (Transaction Manager) - 事务管理器定义全局事务的范围开始全局事务、提交或回滚全局事务。RM (Resource Manager) - 资源管理器管理分支事务处理的资源与TC交谈以注册分支事务和报告分支事务的状态并驱动分支事务提交或回滚。
处理过程
TM向TC申请开启一个全局事务全局事务创建成功并生成一个全局唯一的XIDXID在微服务调用链路的上下文中传播RM向TC注册分支事务将其纳入XID对应全局事务的管辖TM向TC发起针对XID的全局提交或回滚决议TC调度XID下管辖的全部分支事务完成提交或回滚请求。
2. seata安装
Seata分TC、TM和RM三个角色TCServer端为单独服务端部署TM和RMClient端由业务系统集成。 本例前置条件 默认nacos已经安装完成并启动并开启了持久化配置使用mysql8.0数据库 2.1. Server端安装
seata1.5.2安装 nacos2.1.1服务注册和配置中心集成 1. 下载seata 1.5.2 https://github.com/seata/seata/releases
2. 放在合适的路径下解压缩 注意路径中一定不能出现中文和空格否则会导致之后的git命令无法成功执行
3. 在数据库中创建全局事务所需要的表 全局事务会话信息由3块内容构成全局事务–分支事务–全局锁对应表global_table、branch_table、lock_table 在数据库中创建一个名叫seata的数据库 执行sql脚本创建数据表该脚本可以在seata安装包中查看或在git项目中https://github.com/seata/seata/blob/master/script/server/db/mysql.sql获取最新的sql脚本。 seata 1.5.0 新增了distributed_lock表用于 seata-server 异步任务调度并将字符集改为了utf8mb4。默认事务分组的由my_test_tx_group 修改为 default_tx_group更多升级信息可以查看官方文档https://seata.io/zh-cn/docs/ops/upgrade.html -- -------------------------------- The script used when storeMode is db --------------------------------
-- the table to store GlobalSession data
CREATE 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 data
CREATE 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 data
CREATE 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_and_branch_id (xid , branch_id)
) 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);修改seata - config下的application.yaml配置文件使用nacos作为服务注册发现中心和配置中心其他详细配置可以参照seata提供的模板application.example.yml 3.1. 在nacos中新建一个命名空间并记录下空间ID 3.2. 修改application.yml主要修改项seata 下的 config、registry、store
server:port: 7091spring:application:name: seata-serverlogging:config: classpath:logback-spring.xmlfile:path: ${user.home}/logs/seataextend:logstash-appender:destination: 127.0.0.1:4560kafka-appender:bootstrap-servers: 127.0.0.1:9092topic: logback_to_logstashconsole:user:username: seatapassword: seataseata:config:# support: nacos, consul, apollo, zk, etcd3type: nacosnacos:server-addr: localhost:8848namespace: 704a579f-f1ef-45fd-818e-4e5c113ca50dgroup: SEATA_GROUPusername: nacospassword: nacos#data-id: seataServer.properties registry:# support: nacos, eureka, redis, zk, consul, etcd3, sofatype: nacosnacos:application: seata-serverserver-addr: localhost:8848group: SEATA_GROUPnamespace: 704a579f-f1ef-45fd-818e-4e5c113ca50dcluster: defaultusername: nacospassword: nacos##if use MSE Nacos with auth, mutex with username/password attribute#access-key: #secret-key: store:# support: file 、 db 、 redismode: dbdb:datasource: druiddb-type: mysqldriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/seata?rewriteBatchedStatementstrueuseUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghaiuser: rootpassword: 123456min-conn: 1max-conn: 20global-table: global_tablebranch-table: branch_tablelock-table: lock_tabledistributed-lock-table: distributed_lockquery-limit: 100max-wait: 10000server:service-port: 8091 #If not configured, the default is ${server.port} 1000max-commit-retry-timeout: -1max-rollback-retry-timeout: -1rollback-retry-timeout-unlock-enable: falseenable-check-auth: trueenable-parallel-request-handle: trueretry-dead-threshold: 130000xaer-nota-retry-timeout: 60000undo:log-save-days: 7log-delete-period: 86400000session:branch-async-queue-size: 5000 #branch async remove queue sizeenable-branch-async-remove: false #enable to asynchronous remove branchSessionsecurity:secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017tokenValidityInMilliseconds: 1800000ignore:urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login3.3. 修改config配置文件 将D:\seata\script\config-center下的config.txt复制一份到seata的目录下与bin目录同级并修改配置信息主要修改store.mode和store.db可以将不需要的配置信息删除掉以防在nacos配置中心中产生太多无用的配置项例如file和Redis的相关配置
#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.typeTCP
transport.serverNIO
transport.heartbeattrue
transport.enableTmClientBatchSendRequestfalse
transport.enableRmClientBatchSendRequesttrue
transport.enableTcServerBatchSendResponsefalse
transport.rpcRmRequestTimeout30000
transport.rpcTmRequestTimeout30000
transport.rpcTcRequestTimeout30000
transport.threadFactory.bossThreadPrefixNettyBoss
transport.threadFactory.workerThreadPrefixNettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefixNettyServerBizHandler
transport.threadFactory.shareBossWorkerfalse
transport.threadFactory.clientSelectorThreadPrefixNettyClientSelector
transport.threadFactory.clientSelectorThreadSize1
transport.threadFactory.clientWorkerThreadPrefixNettyClientWorkerThread
transport.threadFactory.bossThreadSize1
transport.threadFactory.workerThreadSizedefault
transport.shutdown.wait3
transport.serializationseata
transport.compressornone#Transaction routing rules configuration, only for the client
service.vgroupMapping.default_tx_groupdefault
#If you use a registry, you can ignore it
service.default.grouplist127.0.0.1:8091
service.enableDegradefalse
service.disableGlobalTransactionfalse#Transaction rule configuration, only for the client
client.rm.asyncCommitBufferLimit10000
client.rm.lock.retryInterval10
client.rm.lock.retryTimes30
client.rm.lock.retryPolicyBranchRollbackOnConflicttrue
client.rm.reportRetryCount5
client.rm.tableMetaCheckEnabletrue
client.rm.tableMetaCheckerInterval60000
client.rm.sqlParserTypedruid
client.rm.reportSuccessEnablefalse
client.rm.sagaBranchRegisterEnablefalse
client.rm.sagaJsonParserfastjson
client.rm.tccActionInterceptorOrder-2147482648
client.tm.commitRetryCount5
client.tm.rollbackRetryCount5
client.tm.defaultGlobalTransactionTimeout60000
client.tm.degradeCheckfalse
client.tm.degradeCheckAllowTimes10
client.tm.degradeCheckPeriod2000
client.tm.interceptorOrder-2147482648
client.undo.dataValidationtrue
client.undo.logSerializationjackson
client.undo.onlyCareUpdateColumnstrue
server.undo.logSaveDays7
server.undo.logDeletePeriod86400000
client.undo.logTableundo_log
client.undo.compress.enabletrue
client.undo.compress.typezip
client.undo.compress.threshold64k
#For TCC transaction mode
tcc.fence.logTableNametcc_fence_log
tcc.fence.cleanPeriod1h#Log rule configuration, for client and server
log.exceptionRate100#Transaction storage configuration, only for the server. The file, DB, and redis configuration values are optional.
store.modedb
store.lock.modedb
store.session.modedb
#Used for password encryption
store.publicKey#These configurations are required if the store mode is db. If store.mode,store.lock.mode,store.session.mode are not equal to db, you can remove the configuration block.
store.db.datasourcedruid
store.db.dbTypemysql
store.db.driverClassNamecom.mysql.cj.jdbc.Driver
store.db.urljdbc:mysql://localhost:3306/seata?rewriteBatchedStatementstrueuseUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai
store.db.userroot
store.db.password123456
store.db.minConn1
store.db.maxConn20
store.db.globalTableglobal_table
store.db.branchTablebranch_table
store.db.distributedLockTabledistributed_lock
store.db.queryLimit100
store.db.lockTablelock_table
store.db.maxWait10000#Transaction rule configuration, only for the server
server.recovery.committingRetryPeriod1000
server.recovery.asynCommittingRetryPeriod1000
server.recovery.rollbackingRetryPeriod1000
server.recovery.timeoutRetryPeriod1000
server.maxCommitRetryTimeout-1
server.maxRollbackRetryTimeout-1
server.rollbackRetryTimeoutUnlockEnablefalse
server.distributedLockExpireTime10000
server.xaerNotaRetryTimeout60000
server.session.branchAsyncQueueSize5000
server.session.enableBranchAsyncRemovefalse
server.enableParallelRequestHandlefalse#Metrics configuration, only for the server
metrics.enabledfalse
metrics.registryTypecompact
metrics.exporterListprometheus
metrics.exporterPrometheusPort9898 注意需要将store.mode的三项DB改为小写dbrewriteBatchedStatementstrue,数据库链接中这一句是特别要加的可以提升执行效率 3.4. 使用git将上面修改好的seata的配置导入nacos配置中心 复制D:\seata\script\config-center\nacos下的nacos-config.sh到D:\seata\conf文件夹下 右键启用git命令输入以下命令并回车执行等待数据同步即可
sh nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t 704a579f-f1ef-45fd-818e-4e5c113ca50d -u nacos -w nacos参数详情 -h -p 指定nacos的端口地址 -g 指定配置的分组注意是配置的分组 -t 指定命名空间ID -u -w指定nacos的用户名和密码使用nacos注册和配置认证的才需要指定。
导入成功后可以在nacos中查看到配置信息
2.2. Client端集成
基于springcloud分布式项目集成seata-Client端首先需要搭建一个简单的测试服务环境使用典型的订单系统创建分布式微服务系统共三个微服务模块
订单管理seata-order-service库存管理seata-storage-service账户管理seata-account-service 本例前置条件 1. 使用openFeign作为微服务远程调用框架 2. 使用mybatis作为持久层框架 3. 使用nacos作为服务注册中心 4. 需要注意各框架版本否则会出现版本冲突详细信息查看https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明 2.2.1. 创建父Maven项目进行依赖版本控制
主要的依赖项和使用版本 propertiesproject.build.sourceEncodingUTF-8/project.build.sourceEncodingmaven.compiler.source1.8/maven.compiler.sourcemaven.compiler.target1.8/maven.compiler.targetjunit.version4.12/junit.versionlog4j.version1.2.17/log4j.versionlombok.version1.16.18/lombok.versionmysql.version8.0.23/mysql.versiondruid.version1.2.8/druid.versionmybatis.spring.boot.version1.3.2/mybatis.spring.boot.version/propertiesdependencyManagementdependencies!--springboot--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-dependencies/artifactIdversion2.3.12.RELEASE/versiontypepom/typescopeimport/scope/dependency!--springCloud--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-dependencies/artifactIdversionHoxton.SR12/versiontypepom/typescopeimport/scope/dependency!--springCloud alibaba--dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-alibaba-dependencies/artifactIdversion2.2.9.RELEASE/versiontypepom/typescopeimport/scope/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion${mysql.version}/version/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactIdversion${druid.version}/version/dependencydependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion${mybatis.spring.boot.version}/version/dependency!--junit--dependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion${junit.version}/version/dependency!--log4j--dependencygroupIdlog4j/groupIdartifactIdlog4j/artifactIdversion${log4j.version}/version/dependency/dependencies/dependencyManagement2.2.2. 创建库存管理微服务seata-storage-service
1. 添加pom依赖在父项目下新建module seata-storage-service2002并添加依赖
artifactIdseata-storage-service2002/artifactIddependencies!--nacos--dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId/dependency!--seata--dependencygroupIdio.seata/groupIdartifactIdseata-spring-boot-starter/artifactIdversion1.5.2/version/dependencydependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-seata/artifactIdversion2021.1/versionexclusionsexclusiongroupIdio.seata/groupIdartifactIdseata-spring-boot-starter/artifactId/exclusion/exclusions/dependency!--web--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency!--mysql connector--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependency!--mysql druid--dependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactId/dependency!--mybatis--dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependency/dependencies2. 修改application.yaml配置以下为全部配置信息 需要先创建一个名叫seata_storage的数据库以便数据库链接的配置
server:port: 2002spring:application:name: seata-storage-servicecloud:nacos:discovery:server-addr: localhost:8848datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/seata_storage?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghaiusername: rootpassword: 123456mybatis:mapper-locations: classpath:mapper/*.xml# seata 配置
seata:# seata配置中心tx-service-group: default_tx_groupconfig:type: nacosnacos:namespace: 704a579f-f1ef-45fd-818e-4e5c113ca50d# nacos配置中心地址server-addr: localhost:8848# 分组group: SEATA_GROUP# nacos的账号和密码userName: nacospassword: nacos# seata的注册中心registry:type: nacosnacos:application: seata-serverserver-addr: localhost:8848namespace: 704a579f-f1ef-45fd-818e-4e5c113ca50duserName: nacospassword: nacosservice:vgroup-mapping:default_tx_group: default3. 编写业务代码 整体包结构
domain包 CommonResult
package com.atguigu.alibaba.seata.domain;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月17日*/
Data
AllArgsConstructor
NoArgsConstructor
public class CommonResultT {private Integer code;private String message;private T data;public CommonResult(Integer code, String message){this(code,message,null);}
}Storage
package com.atguigu.alibaba.seata.domain;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
Data
NoArgsConstructor
AllArgsConstructor
public class Storage {private Long id; //主键private Long productId; //产品IDprivate Integer total; //库存总量private Integer used; //已用库存数量private Integer residue; //剩余库存数量
}数据库建表sql在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 seata_storage.t_storage(id, product_id, total, used, residue)
VALUES (1, 1, 100, 0,100);SELECT * FROM t_storage;dao包 StorageDao
package com.atguigu.alibaba.seata.dao;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
Mapper
public interface StorageDao {public void decrease(Param(productId) Long productId, Param(count) Integer count);
}在resources下创建一个名叫mapper的文件夹用来放mybatis的xml映射文件
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd
!--Dao的全路径--
mapper namespacecom.atguigu.alibaba.seata.dao.StorageDao!--对应entity的全路径--resultMap idBaseResultMap typecom.atguigu.alibaba.seata.domain.Storageid columnid propertyid jdbcTypeBIGINT/result columnproduct_id propertyproductId jdbcTypeBIGINT/result columntotal propertytotal jdbcTypeINTEGER/result columnused propertyused jdbcTypeINTEGER/result columnresidue propertyresidue jdbcTypeINTEGER//resultMapupdate iddecreaseupdatet_storagesetused used #{count}, residue residue - #{count}whereproduct_id #{productId}/update
/mapperservice包 StorageService
package com.atguigu.alibaba.seata.service;import org.springframework.web.bind.annotation.RequestParam;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
public interface StorageService {public void decrease(RequestParam(productId) Long productId,RequestParam(count) Integer count);
}service.impl包 StorageServiceImpl
package com.atguigu.alibaba.seata.service.impl;import com.atguigu.alibaba.seata.dao.StorageDao;
import com.atguigu.alibaba.seata.service.StorageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;import javax.annotation.Resource;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
Service
public class StorageServiceImpl implements StorageService {private static final Logger LOGGER LoggerFactory.getLogger(StorageServiceImpl.class);Resourceprivate StorageDao storageDao;Overridepublic void decrease(Long productId, Integer count) {LOGGER.info(-------storage-service中扣减库存开始);storageDao.decrease(productId,count);LOGGER.info(-------storage-service中扣减库存结束);}
}controller包 StorageController
package com.atguigu.alibaba.seata.controller;import com.atguigu.alibaba.seata.domain.CommonResult;
import com.atguigu.alibaba.seata.service.StorageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
RestController
Slf4j
public class StorageController {Resourceprivate StorageService storageService;RequestMapping(/storage/decrease)public CommonResult decrease(RequestParam(productId) Long productId,RequestParam(count) Integer count){storageService.decrease(productId, count);return new CommonResult(200,扣减库存成功);}
}config包配置mybatis的包扫描 MyBatisConfig
package com.atguigu.alibaba.seata.config;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
Configuration
MapperScan({com.atguigu.alibaba.seata.dao})
public class MyBatisConfig {}主程序入口
package com.atguigu.alibaba.seata;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
EnableDiscoveryClient
SpringBootApplication
public class StorageMain {public static void main(String[] args) {SpringApplication.run(StorageMain.class,args);}
}2.2.3. 创建账户管理微服务seata-account-service
1. 添加pom依赖在父项目下新建module seata-account-service2003并添加依赖 artifactIdseata-account-service2003/artifactIddependencies!--nacos--dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId/dependency!--seata--dependencygroupIdio.seata/groupIdartifactIdseata-spring-boot-starter/artifactIdversion1.5.2/version/dependencydependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-seata/artifactIdversion2021.1/versionexclusionsexclusiongroupIdio.seata/groupIdartifactIdseata-spring-boot-starter/artifactId/exclusion/exclusions/dependency!--web--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency!--mysql connector--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependency!--mysql druid--dependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactId/dependency!--mybatis--dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependency/dependencies2. 修改application.yaml配置以下为全部配置信息 需要先创建一个名叫seata_account的数据库以便数据库链接的配置
server:port: 2003spring:application:name: seata-account-servicecloud:nacos:discovery:server-addr: localhost:8848datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/seata_account?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghaiusername: rootpassword: 123456mybatis:mapper-locations: classpath:mapper/*.xml# seata 配置
seata:# seata配置中心tx-service-group: default_tx_groupconfig:type: nacosnacos:namespace: 704a579f-f1ef-45fd-818e-4e5c113ca50d# nacos配置中心地址server-addr: localhost:8848# 分组group: SEATA_GROUP# nacos的账号和密码userName: nacospassword: nacos# seata的注册中心registry:type: nacosnacos:application: seata-serverserver-addr: localhost:8848namespace: 704a579f-f1ef-45fd-818e-4e5c113ca50duserName: nacospassword: nacosservice:vgroup-mapping:default_tx_group: default3. 编写业务代码 整体包结构
domain包 CommonResult
package com.atguigu.alibaba.seata.domain;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月17日*/
Data
AllArgsConstructor
NoArgsConstructor
public class CommonResultT {private Integer code;private String message;private T data;public CommonResult(Integer code, String message){this(code,message,null);}
}Account
package com.atguigu.alibaba.seata.domain;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.math.BigDecimal;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
Data
AllArgsConstructor
NoArgsConstructor
public class Account {private Long id; //主键private Long userId; //用户IDprivate BigDecimal total; //账户总额private BigDecimal used; //已使用额度private BigDecimal residue; //剩余额度
}数据库建表sql在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_INCREMENT1 DEFAULT CHARSETutf8;INSERT INTO seata_account.t_account(id, user_id, total, used, residue)
VALUES (1, 1, 1000, 0, 1000);SELECT * FROM t_account;dao包 AccountDao
package com.atguigu.alibaba.seata.dao;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.math.BigDecimal;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
Mapper
public interface AccountDao {public void decrease(Param(userId) Long userId,Param(money) BigDecimal money);
}在resources下创建一个名叫mapper的文件夹用来放mybatis的xml映射文件
?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.alibaba.seata.dao.AccountDaoresultMap idBaseResultMap typecom.atguigu.alibaba.seata.domain.Accountid propertyid columnid jdbcTypeBIGINT/result propertyuserId columnuser_id jdbcTypeBIGINT/result propertytotal columntotal jdbcTypeDECIMAL/result propertyused columnused jdbcTypeDECIMAL/result propertyresidue columnresidue jdbcTypeDECIMAL//resultMapupdate iddecreaseupdatet_accountsetresidue residue - #{money}, used used #{money}whereuser_id #{userId}/update
/mapperservice包 AccountService
package com.atguigu.alibaba.seata.service;import org.springframework.web.bind.annotation.RequestParam;import java.math.BigDecimal;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
public interface AccountService {public void decrease (RequestParam(userId) Long userId,RequestParam(money) BigDecimal money);
}service.impl包 AccountServiceImpl
package com.atguigu.alibaba.seata.service.impl;import com.atguigu.alibaba.seata.dao.AccountDao;
import com.atguigu.alibaba.seata.service.AccountService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.math.BigDecimal;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
Service
public class AccountServiceImpl implements AccountService {private static final Logger LOGGER LoggerFactory.getLogger(AccountServiceImpl.class);Resourceprivate AccountDao accountDao;Overridepublic void decrease(Long userId, BigDecimal money) {LOGGER.info(-------Account-service中扣减金额开始);accountDao.decrease(userId, money);LOGGER.info(-------Account-service中扣减金额结束);}
}controller包
package com.atguigu.alibaba.seata.controller;import com.atguigu.alibaba.seata.domain.CommonResult;
import com.atguigu.alibaba.seata.service.AccountService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.math.BigDecimal;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
RestController
public class AccountController {Resourceprivate AccountService accountService;RequestMapping(/account/decrease)public CommonResult decrease(RequestParam(userId) Long userId,RequestParam(money) BigDecimal money){accountService.decrease(userId, money);return new CommonResult(200,扣减账户余额成功);}
}config包 MyBatisConfig
package com.atguigu.alibaba.seata.config;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
Configuration
MapperScan({com.atguigu.alibaba.seata.dao})
public class MyBatisConfig {}主程序入口
package com.atguigu.alibaba.seata;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月18日*/
EnableDiscoveryClient
SpringBootApplication
public class AccountMain {public static void main(String[] args) {SpringApplication.run(AccountMain.class,args);}
}2.2.4. 创建订单管理微服务seata-order-service
1. 添加pom依赖在父项目下新建module seata-order-service2001并添加依赖 artifactIdseata-order-service2001/artifactIddependencies!--nacos--dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId/dependency!--seata 官方文档推荐依赖添加方式--dependencygroupIdio.seata/groupIdartifactIdseata-spring-boot-starter/artifactIdversion1.5.2/version/dependencydependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-seata/artifactIdversion2021.1/versionexclusionsexclusiongroupIdio.seata/groupIdartifactIdseata-spring-boot-starter/artifactId/exclusion/exclusions/dependency!--openfeign--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactIdversion2.2.0.RELEASE/version/dependency!--web-actuator--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency!--mysql-druid--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactIdversion1.1.10/version/dependency!--mybatis--dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependency/dependencies2. 修改application.yaml配置以下为全部配置信息 需要先创建一个名叫seata_order的数据库以便数据库链接的配置
server:port: 2001spring:application:name: seata-order-servicecloud:nacos:discovery:server-addr: localhost:8848datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/seata_order?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghaiusername: rootpassword: 123456mybatis:mapper-locations: classpath:mapper/*.xml# seata 配置
seata:# seata配置中心tx-service-group: default_tx_groupconfig:type: nacosnacos:namespace: 704a579f-f1ef-45fd-818e-4e5c113ca50d# nacos配置中心地址server-addr: localhost:8848# 分组group: SEATA_GROUP# nacos的账号和密码userName: nacospassword: nacos# seata的注册中心registry:type: nacosnacos:application: seata-serverserver-addr: localhost:8848namespace: 704a579f-f1ef-45fd-818e-4e5c113ca50duserName: nacospassword: nacosservice:vgroup-mapping:default_tx_group: default3. 编写业务代码 整体包结构
domain包 CommonResult
package com.atguigu.alibaba.seata.domain;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月17日*/
Data
AllArgsConstructor
NoArgsConstructor
public class CommonResultT {private Integer code;private String message;private T data;public CommonResult(Integer code, String message){this(code,message,null);}
}Order也就是entity和数据库字段对应
package com.atguigu.alibaba.seata.domain;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.math.BigDecimal;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月17日*/
Data
AllArgsConstructor
NoArgsConstructor
public class Order {private Long id;private Long userId;private Long productId;private Integer count;private BigDecimal money;private Integer status; //订单状态0创建中1已完结
}数据库建表sql在数据库中新建一个名叫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;dao包 OrderDao
package com.atguigu.alibaba.seata.dao;import com.atguigu.alibaba.seata.domain.Order;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月17日*/
Mapper
public interface OrderDao {//1 新建订单public void create(Order order);//2 修改订单状态从零改为1public void update(Param(userId) Long userId, Param(status) Integer status);
}在resources下创建一个名叫mapper的文件夹用来放mybatis的xml映射文件
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd
!--Dao的全路径--
mapper namespacecom.atguigu.alibaba.seata.dao.OrderDao!--对应entity的全路径--resultMap idBaseResultMap typecom.atguigu.alibaba.seata.domain.Orderid columnid propertyid jdbcTypeBIGINT/result columnuser_id propertyuserId jdbcTypeBIGINT/result columnproduct_id propertyproductId jdbcTypeBIGINT/result columncount propertycount jdbcTypeINTEGER/result columnmoney propertymoney jdbcTypeDECIMAL/result columnstatus propertystatus jdbcTypeINTEGER//resultMapinsert idcreateinsert into t_order (id,user_id,product_id,count,money,status)values (null,#{userId},#{productId},#{count},#{money},0);/insertupdate idupdateupdate t_order set status 1where user_id#{userId} and status #{status};/update
/mapperservice包因为订单服务需要调用库存和账户服务所以需要使用openFeign进行远程调用服务接口并且需要先行将这两个服务的接口创建好 StorageService
package com.atguigu.alibaba.seata.service;import com.atguigu.alibaba.seata.domain.CommonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月17日*/
Service(storageService)
FeignClient(value seata-storage-service)
public interface StorageService {PostMapping(value /storage/decrease)CommonResult decrease(RequestParam(productId) Long productId, RequestParam(count) Integer count);
}AccountService
package com.atguigu.alibaba.seata.service;import com.atguigu.alibaba.seata.domain.CommonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;import java.math.BigDecimal;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月17日*/
Service(accountService)
FeignClient(value seata-account-service)
public interface AccountService {PostMapping(value /account/decrease)CommonResult decrease(RequestParam(userId) Long userId,RequestParam(money) BigDecimal money);
}OrderService
package com.atguigu.alibaba.seata.service;import com.atguigu.alibaba.seata.domain.Order;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月17日*/
public interface OrderService {void create(Order order);
}service.impl包 OrderServiceImpl
package com.atguigu.alibaba.seata.service.impl;import com.atguigu.alibaba.seata.dao.OrderDao;
import com.atguigu.alibaba.seata.domain.Order;
import com.atguigu.alibaba.seata.service.AccountService;
import com.atguigu.alibaba.seata.service.OrderService;
import com.atguigu.alibaba.seata.service.StorageService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import javax.annotation.Resource;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月17日*/
Service
Slf4j
public class OrderServiceImpl implements OrderService {Resourceprivate OrderDao orderDao;Resourceprivate StorageService storageService;Resourceprivate AccountService accountService;OverrideGlobalTransactionalpublic void create(Order order) {log.info(-----开始新建订单);//1 新建订单orderDao.create(order);//2 扣减库存log.info(-----订单微服务开始调用库存做扣减Count);storageService.decrease(order.getProductId(),order.getCount());log.info(-----订单微服务开始调用库存做扣减end);//3 扣减账户log.info(-----订单微服务开始调用账户做扣减Money);accountService.decrease(order.getUserId(),order.getMoney());log.info(-----订单微服务开始调用账户做扣减end);//4 修改订单状态从零到1,1代表已经完成log.info(-----修改订单状态开始);orderDao.update(order.getUserId(),0);log.info(-----修改订单状态结束);}
}controller包 OrderSeataController
package com.atguigu.alibaba.seata.controller;import com.atguigu.alibaba.seata.domain.CommonResult;
import com.atguigu.alibaba.seata.domain.Order;
import com.atguigu.alibaba.seata.service.OrderService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月17日*/
RestController
public class OrderSeataController {Resourceprivate OrderService orderService;GetMapping(/order/create)public CommonResult create(Order order){orderService.create(order);return new CommonResult(200,订单创建成功);}
}config包
package com.atguigu.alibaba.seata.config;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月17日*/
Configuration
MapperScan({com.atguigu.alibaba.seata.dao})
public class MyBatisConfig {}主程序入口
package com.atguigu.alibaba.seata;import io.seata.spring.annotation.datasource.EnableAutoDataSourceProxy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;/*** author 强浩* version 1.0.0* Copyright(c) YTANG All Rights Reserved* className* project 管理系统* date 2022年10月17日*/
SpringBootApplication
EnableDiscoveryClient
EnableFeignClients
EnableAutoDataSourceProxy
public class OrderMain {public static void main(String[] args) {SpringApplication.run(OrderMain.class,args);}
}2.2.5. 集成Seata - Client
1. 添加seata依赖编写业务代码时已经添加完毕 2. 在所有需要进行全局事务管理的业务数据库下新建undo_log表、配置参数(仅AT模式)
-- the table to store seata xid data
-- 0.7.0 add context
-- you must to init this sql for you business databese. the seata server not need it.
-- 此脚本必须初始化在你当前的业务数据库中用于AT 模式XID记录。与server端无关注业务数据库
-- 注意此处0.3.0 增加唯一索引 ux_undo_log
drop table 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)
) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8;3. 数据源代理不支持自动和手动配置并存我这里使用的是seata-starter默认开启了自动数据源代理无需修改 4. 初始化GlobalTransactionScanner:自动引入seata-spring-boot-starter、spring-cloud-starter-alibaba-seata等jar无需修改 5. 实现xid跨服务传递自动 springCloud用户可以引入spring-cloud-starter-alibaba-seata内部已经实现xid传递无需修改 官方部署指南https://seata.io/zh-cn/docs/ops/deploy-guide-beginner.html
2.2.6. 业务使用
注解拦截全局事务 在需要进行全局事务管理的入口接口上标注 GlobalTransactional例
Service
Slf4j
public class OrderServiceImpl implements OrderService {Resourceprivate OrderDao orderDao;Resourceprivate StorageService storageService;Resourceprivate AccountService accountService;OverrideGlobalTransactionalpublic void create(Order order) {log.info(-----开始新建订单);//1 新建订单orderDao.create(order);//2 扣减库存log.info(-----订单微服务开始调用库存做扣减Count);storageService.decrease(order.getProductId(),order.getCount());log.info(-----订单微服务开始调用库存做扣减end);//3 扣减账户log.info(-----订单微服务开始调用账户做扣减Money);accountService.decrease(order.getUserId(),order.getMoney());log.info(-----订单微服务开始调用账户做扣减end);//4 修改订单状态从零到1,1代表已经完成log.info(-----修改订单状态开始);orderDao.update(order.getUserId(),0);log.info(-----修改订单状态结束);}
}2.2.7. 测试
1. 启动seata-server双击bin下的seata-server.bat 2. 启动三个微服务 发送请求这时应该可以正常创建数据并扣减数据 http://localhost:2001/order/create?userId1productId1count10money100 3. 先不添加GlobalTransactional注解 在关闭account账户服务的情况下发送请求这时数据库应该创建了订单信息和扣减了库存但账户没有扣减出现了数据的不一致 http://localhost:2001/order/create?userId1productId1count10money100 4. 添加GlobalTransactional注解在关闭account账户服务的情况下 发送请求这时数据库应该不会创建任何数据加粗样式