一.Seata简介

Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。在 Seata 开源之前,Seata 对应的内部版本在阿里经济体内部一直扮演着分布式一致性中间件的角色,帮助经济体平稳的度过历年的双 11,对各 BU 业务进行了有力的支撑。经过多年沉淀与积累,商业化产品先后在阿里云、金融云进行售卖。2019.1为了打造更加完善的技术生态和普惠技术成果,Seata 正式宣布对外开源,未来 Seata 将以社区共建的形式帮助其技术更加可靠与完备。

二.Seata安装(Windows安装)

1.下载地址:下载地址 博主这里使用的是v0.9.0
2.下载后需要对对应文件尽心修改
a.file.conf修改

transport {# tcp udt unix-domain-sockettype = "TCP"#NIO NATIVEserver = "NIO"#enable heartbeatheartbeat = true#thread factory for nettythread-factory {boss-thread-prefix = "NettyBoss"worker-thread-prefix = "NettyServerNIOWorker"server-executor-thread-prefix = "NettyServerBizHandler"share-boss-worker = falseclient-selector-thread-prefix = "NettyClientSelector"client-selector-thread-size = 1client-worker-thread-prefix = "NettyClientWorkerThread"# netty boss thread size,will not be used for UDTboss-thread-size = 1#auto default pin or 8worker-thread-size = 8}shutdown {# when destroy server, wait secondswait = 3}serialization = "seata"compressor = "none"
}
service {#vgroup->rgroupvgroup_mapping.my_test_tx_group = "fsp_ex_group"#only support single nodedefault.grouplist = "127.0.0.1:8091"#degrade current not supportenableDegrade = false#disabledisable = false#unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanentmax.commit.retry.timeout = "-1"max.rollback.retry.timeout = "-1"#若报配置异常则加上下面一句配置即可disableGlobalTransaction=false
}client {async.commit.buffer.limit = 10000lock {retry.internal = 10retry.times = 30}report.retry.count = 5tm.commit.retry.count = 1tm.rollback.retry.count = 1
}## transaction log store
store {## store mode: file、dbmode = "db"## file storefile {dir = "sessionStore"# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptionsmax-branch-session-size = 16384# globe session size , if exceeded throws exceptionsmax-global-session-size = 512# file buffer size , if exceeded allocate new bufferfile-write-buffer-cache-size = 16384# when recover batch read sizesession.reload.read_size = 100# async, syncflush-disk-mode = async}## database storedb {## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.datasource = "dbcp"## mysql/oracle/h2/oceanbase etc.db-type = "mysql"driver-class-name = "com.mysql.jdbc.Driver"url = "jdbc:mysql://localhost:3306/seata"user = "root"password = "123456"min-conn = 1max-conn = 3global.table = "global_table"branch.table = "branch_table"lock-table = "lock_table"query-limit = 100}
}
lock {## the lock store mode: local、remotemode = "remote"local {## store locks in user's database}remote {## store locks in the seata's server}
}
recovery {#schedule committing retry period in millisecondscommitting-retry-period = 1000#schedule asyn committing retry period in millisecondsasyn-committing-retry-period = 1000#schedule rollbacking retry period in millisecondsrollbacking-retry-period = 1000#schedule timeout retry period in millisecondstimeout-retry-period = 1000
}transaction {undo.data.validation = trueundo.log.serialization = "jackson"undo.log.save.days = 7#schedule delete expired undo_log in millisecondsundo.log.delete.period = 86400000undo.log.table = "undo_log"
}## metrics settings
metrics {enabled = falseregistry-type = "compact"# multi exporters use comma dividedexporter-list = "prometheus"exporter-prometheus-port = 9898
}support {## springspring {# auto proxy the DataSource beandatasource.autoproxy = false}
}

b.registry.conf修改

registry {# file 、nacos 、eureka、redis、zk、consul、etcd3、sofatype = "file"nacos {serverAddr = "localhost"namespace = ""cluster = "default"}eureka {serviceUrl = "http://localhost:8761/eureka"application = "default"weight = "1"}redis {serverAddr = "localhost:6379"db = "0"}zk {cluster = "default"serverAddr = "127.0.0.1:2181"session.timeout = 6000connect.timeout = 2000}consul {cluster = "default"serverAddr = "127.0.0.1:8500"}etcd3 {cluster = "default"serverAddr = "http://localhost:2379"}sofa {serverAddr = "127.0.0.1:9603"application = "default"region = "DEFAULT_ZONE"datacenter = "DefaultDataCenter"cluster = "default"group = "SEATA_GROUP"addressWaitTime = "3000"}file {name = "file.conf"}
}config {# file、nacos 、apollo、zk、consul、etcd3type = "file"nacos {serverAddr = "localhost"namespace = ""}consul {serverAddr = "127.0.0.1:8500"}apollo {app.id = "seata-server"apollo.meta = "http://192.168.1.204:8801"}zk {serverAddr = "127.0.0.1:2181"session.timeout = 6000connect.timeout = 2000}etcd3 {serverAddr = "http://localhost:2379"}file {name = "file.conf"}
}

3.创建seata数据库(mysql) 将seata->conf->db_store.sql放到数据库中运行即可
4.到bin目录下找到seata-server.bat运行即可 如下即为成功运行:

三.nacos安装

a.下载地址:https://github.com/alibaba/nacos/releases
b.修改application.properties文件(将数据库对应配置注释打开即可)

c.找到startup.cmd编辑里面的将set MODE="cluster"一行改成set MODE=“standalone”
d.点击startup.cmd运行即可,如下即为成功:

e.访问localhost:8848即可 默认账号密码都是:nacos

四.项目案例

1.项目结构


account-service:负责对用户余扣减
business-service:负责完成下单的逻辑,包含 2 个主要的步骤,就是对库存服务和订单服务的远程调用
order-service:负责完成保存用户订单的操作
storage-service:负责完成对库存的扣减

2.各模块主要代码展示:

account-service

@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountTblMapper accountTblMapper ;private static Logger logger = LoggerFactory.getLogger(AccountServiceImpl.class) ;@Transactional@Overridepublic void debit(String userId, int money) {logger.info("开始扣减用户:{}的余额,数量为:{}",userId ,money);//1 查询数据库里面的账户AccountTbl accountTbl = accountTblMapper.selectOne(new LambdaQueryWrapper<AccountTbl>().eq(AccountTbl::getUserId, userId));if(accountTbl==null){throw new IllegalArgumentException("此账号不存在")  ;}//2 扣减的操作int idleMoney = accountTbl.getMoney() - money ;// 3 库存的校验if(idleMoney<0){throw new RuntimeException("库存不足") ;}//4 设置到账户里面accountTbl.setMoney(idleMoney);//5 保存到数据库里里面accountTblMapper.updateById(accountTbl) ;if("SXT_USER_2".equals(userId)){throw new RuntimeException("不想成功") ;}}
}

####Pom文件

<dependencies><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.0</version></dependency><!--MySQL依赖 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency></dependencies>

business-service

@Service
public class BusinessServiceImpl implements BusinessService {private static Logger logger = LoggerFactory.getLogger(BusinessServiceImpl.class) ;@Autowiredprivate StorageServiceApi storageServiceApi ;@Autowiredprivate OrderServiceApi orderServiceApi ;@Overridepublic void purchase(String userId, String productNo, int count) {logger.info("准备下单,用户{},商品{},数量{}",userId ,productNo ,count);// 1 远程调用库存服务--> 库存的扣减fstorageServiceApi.deduct(productNo, count);// 2 远程调用订单服务-->订单的新增orderServiceApi.create(userId, productNo, count);logger.info("下单成功");}
}

####通过feign调用 代码:
OrderServiceApi

@Service
public class OrderServiceApi {private static Logger logger = LoggerFactory.getLogger(OrderServiceApi.class) ;//    @Autowired
//    private RestTemplate restTemplate ;@Autowiredprivate OrderServiceFeign orderServiceFeign ;public void create(String userId ,String productNo ,int count){//        ResponseEntity<Void> responseEntity = restTemplate.getForEntity(
//                "http://order-service/create/{userId}/{productNo}/{count}",
//                Void.class,
//                userId,
//                productNo,
//                count
//        );ResponseEntity<Void> responseEntity = orderServiceFeign.create(userId, productNo, count);if(responseEntity.getStatusCode()== HttpStatus.OK){logger.info("远程调用订单服务成功");return;}throw new RuntimeException("远程调用订单服务失败") ;}}

StorageServiceApi

@Service
public class StorageServiceApi {private static Logger logger = LoggerFactory.getLogger(StorageServiceApi.class) ;//    @Autowired
//    private RestTemplate restTemplate ; //ribbon@Autowiredprivate StorageServiceFeign storageServiceFeign ;public void deduct(String productNo ,int count){//        ResponseEntity<Void> responseEntity = restTemplate.getForEntity(
//                "http://storage-service/deduct/{productNo}/{count}",
//                Void.class,
//                productNo,
//                count
//        );ResponseEntity<Void> responseEntity = storageServiceFeign.deduct(productNo, count);if(responseEntity.getStatusCode()== HttpStatus.OK){logger.info("远程调用库存服务成功");return;}throw new RuntimeException("远程调用库存服务失败");}
}

###order-service

@Service
public class OrderServiceImpl implements OrderService {@Autowiredprivate OrderTblMapper orderTblMapper ;@Autowiredprivate AccountServiceApi accountServiceApi ;private static Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class) ;@Transactional@Overridepublic OrderTbl createOrder(String userId, String productNo, int count) {logger.info("开始创建一个订单,用户为{},商品为{},数量为{}",userId,productNo,count);// 1 扣减用户的余额 account-service - >rpcint money = cal(productNo,count) ;ResponseEntity<Void> responseEntity = accountServiceApi.debit(userId, money);if(responseEntity.getStatusCode()!= HttpStatus.OK){throw new RuntimeException("远程扣减用户的余额失败") ;}//2 写本地的订单表OrderTbl orderTbl = new OrderTbl();orderTbl.setUserId(userId);orderTbl.setCommodityCode(productNo);orderTbl.setCount(count);orderTblMapper.insert(orderTbl) ;logger.info("创建订单成功,用户为{},商品为{},数量{}",userId,productNo,count);return orderTbl;}/*** 计算商品的总价格* @param productNo* @param count* @return*/private int cal(String productNo, int count) {//我们的数据库里面非常简单,没有商品的表int money = 0  ;if("HUAWEI_0001".equals(productNo)){money = 2000 ;}else if("XIAOMI_002".equals("productNo")){money = 1000 ;}else {money = 9999 ;}return money * count ;}
}

###storage-service

@Service
public class StorageServiceImpl implements StorageService {@Autowiredprivate StorageTblMapper storageTblMapper ;private static Logger logger = LoggerFactory.getLogger(StorageServiceImpl.class) ;@Transactional@Overridepublic void deduct(String productNo, int count) {logger.info("开始扣减商品{}的库存,数量为{}",productNo,count);//1 查询数据库里面该商品的库存StorageTbl storageTbl = storageTblMapper.selectOne(new LambdaQueryWrapper<StorageTbl>().eq(StorageTbl::getCommodityCode, productNo));if(storageTbl==null){throw new IllegalArgumentException("商品不存在") ;}// 2 扣减操作int idleCount = storageTbl.getCount() - count ;if(idleCount< 0 ){throw  new RuntimeException("库存不足") ;}//3 设置到商品的库存里面storageTbl.setCount(idleCount);// 4 保存到数据库里面storageTblMapper.updateById(storageTbl) ;logger.info("扣减商品{}的库存成功,剩余的库存为{}" ,productNo, idleCount);}
}

五.测试(其中的数据表在项目下seata.sql 放到之前安装seata时创建的seata数据库运行即可)

1.启动四个服务(若有改动后重启只需重启order-service ,business-service)
2.还原数据库数据


3.正常测试:



4.异常回滚测试:



**

至此Seata测试成功 需要源码或软件安装包可私信或评论 看到会发

**

SpringCloud+Seata+nacos案例(包含源码 Seata及nacos安装教程)相关推荐

  1. 2022苹果CMS 全新绿豆二开影视源码app源码完整版带安装教程

    (1条消息) 2022全新绿豆二开影视源码苹果CMSapp源码完整版带安装教程-小程序文档类资源-CSDN文库https://download.csdn.net/download/weixin_740 ...

  2. discuz3.4安装php,Discuz!X3.4论坛源码下载 及 全新安装教程

    Discuz!X3.4论坛源码下载 及 全新安装教程 一.下载 Discuz! X3.4 到本地或者服务器上 简体GBK.简体UTF8.繁体UTF8的打包版下载: 二.解压并上传 Discuz! X3 ...

  3. ptcms需要php版本,PTCMS小说最新版4.28源码完美功能更新安装教程

    下面解释一下安装教程: 一.服务器环境得要求 推荐linux环境,win得也支持,不过没去测试搭建,自行按照下面得教程测试 nginx1.15 MySQL5.5 php7.3 安装php拓展 file ...

  4. 蓝色版PTCMS仿蜻蜓听书小说站源码+带采集规则/安装教程

    正文: 下方是程序的一些介绍啥的,有兴趣自己查看: 1.后台自带了可用的小说采集规则和小说下载规则,配置完成即可自动采集.自动采集. ​2.模板整合百度语音,实现在线听书. ​3.模板带有下载采集规则 ...

  5. SpringCloudAlibaba注册中心与配置中心之利器Nacos实战与源码分析(上)

    Python微信订餐小程序课程视频 https://blog.csdn.net/m0_56069948/article/details/122285951 Python实战量化交易理财系统 https ...

  6. java springcloud微服务航班管理系统源码+课程报告

    下载地址:https://download.csdn.net/download/qq_31293575/10728702 项目介绍 java springcloud微服务航班管理系统源码+课程报告 主 ...

  7. maven 上传jar 包含源码

    2019独角兽企业重金招聘Python工程师标准>>> maven 上传jar 包含源码 1.pom配置如下 <build><plugins><!-- ...

  8. 单元测试Struts2Spring项目的Action和Service(包含源码)

    最近,认真实践了单元测试Struts2.Spring等Java项目,今天特意写的是单元测试Struts2Spring项目的Action和Service. 由于已经写过不少Web开发框架单元测试的代码, ...

  9. H5音乐播放器(包含源码与示例)

    H5音乐播放器(包含源码与示例) 基于Angular+ionic的H5音乐播放器,源码:https://gitee.com/CrimsonHu/h5-music-player 示例地址 建议使用原版c ...

  10. 视频教程-经典Vue从入门到案例到源码分析教程(含资料)-Vue

    经典Vue从入门到案例到源码分析教程(含资料) 张长志技术全才.擅长领域:区块链.大数据.Java等.10余年软件研发及企业培训经验,曾为多家大型企业提供企业内训如中石化,中国联通,中国移动等知名企业 ...

最新文章

  1. JavaScript继承的多种方式和优缺点
  2. FAT32文件系统结构分析
  3. 检测IIS应用程序池对象 回收
  4. oracle 中表示字符串使用单引号
  5. c 和php 加密,加载由blenc加密的页面时出错(C和PHP代码)
  6. http服务器异步响应,python – 具有异步响应的Twisted http服务器,其中请求必须等待数据变为可用或超时...
  7. plsql查询乱码问题解决
  8. java 装饰器_装饰器模式(Java)
  9. Laravel入门:MVC框架
  10. 算法模板java_我的Java设计模式-模板方法模式
  11. oracle中trim,ltrim,rtrim函数用法
  12. HDU 1325 Is It A Tree?(并查集)
  13. html5拼音显示,HTML5:给汉字加拼音?收起展开组件?
  14. Ueditor编辑器修改字体和字号?
  15. amaze ui教程
  16. 高等数学基础03:函数的连续性
  17. HFSS仿真结果输出
  18. assert.equal()
  19. 【分享】性能比肩美拍秒拍的Android视频录制编辑特效解决方案【1】
  20. 关于open3d的入门到放弃

热门文章

  1. 有关onpropertychange事件
  2. servlet无法自动在web.xml中配置
  3. nginx 为什么要反向代理 影藏后端 高效连接(给nginx,他自己返回) 端口冲突解决 多个服务...
  4. [C#]使用Costura.Fody将源DLL合并到目标EXE
  5. 避免内存泄露及内存的规范化使用
  6. Symantec Backup Exec 2014 备份Exchange 2013之四设备初始化
  7. Data crossstore between Mongo and JPA
  8. RK30SDK开发板驱动分析(一):platform device 的概念与注册
  9. J2EE项目架构最佳实践
  10. 58. 网络驱动器设备: iSCSI 服务器