VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Java教程 >
  • 分布式事务seata

在我面试招行外包的时候,与三位面试官进行了半个多小时的交锋,从java基础到框架,其中让我记忆深刻的有一个问题。我说到我们系统采用了微服务架构,是根据不同岗位划分成几个服务,服务之间的调用是用openFeign。A服务减库存并调用B服务增加相应库存,使用事务管理防止操作失败。

面试官:等一下,你说一下事务有什么特性?

我:事务有四个特性,原子性、一致性、隔离性、额还有一个忘了(我太紧张了)

面试官:那你大概解释一下每个特性

我:原子性就是事务要么全部成功要么全部失败,一致性就是事务执行前和执行后是一致的,假设A和B共100块钱,无论怎么相互转账,总共还是100块钱,

隔离性就是每个事务之间是相互隔离不影响的,(补充:持久性就是事务一旦提交了,对数据库的改变就是永久性的)

面试官: 事务的隔离级别有几种

我:巴拉巴拉。。。

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

面试官: 你是怎么保证数据不出错的

我:通过事务管理(我指的是spring本地事务,我还不知道分布式事务),如果有异常则数据回滚,B服务的方法执行完之后,校验数据是否插入成功,如果没有插入成功则手动抛出异常。

面试官:如果网络延迟B服务没有及时插入,或者其他原因导致你校验的时候B数据库并没有插入数据,但是随后又插入成功了,这种情况你是如何解决的

我:。。。(我就此被KO了)

 

  过后我才了解到分布式事务这种东西,一个很经典的场景,在微服务架构中,订单服务下订单,就要调用库存服务减库存,如果库存不足,就下单失败。常见的分布式事务类型有 2PC、3PC、TCC、本地消息表、消息事务、最大努力通知,对于这几种我在此先不讲了,给大家推荐一篇我很喜欢的博主(敖丙)的文章,他写的很好,我经常看他的文章,https://zhuanlan.zhihu.com/p/183753774,我今天就只谈一下阿里开源的分布式事务框架Seata,Seata 是 Simple Extensible Autonomous Transaction Architecture 的简写,详细介绍可参考官网https://seata.io/zh-cn/还有在码云上的仓库https://gitee.com/itCjb/spring-cloud-alibaba-seata-demo里面有示例代码和相关文档。这些东西我觉得没必要写了,我写的不一定有大佬和官方写的好,所以我就分享一下我在安装部署使用中碰到的一些坑:

1、安装seata服务端并注册到nacos(我是放在阿里云ECS上面)

  简单粗暴的方法就是到seata的gitbub上去下载linux版本的压缩包,我就是是这样的,或者其他途径也行,然后通过工具上传到服务器,解压,启动就完事了,但是这样是不行的,需要改配置才能成功连接数据库和注册到nacos

file.conf (在conf文件夹里)

 

复制代码
 1 ## transaction log store, only used in seata-server
 2 store {
 3   ## store mode: file、db、redis
 4   mode = "db"
 5 
 6   ## database store property
 7   db {
 8     ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
 9     datasource = "druid"
10     ## mysql/oracle/postgresql/h2/oceanbase etc.
11     dbType = "mysql"
12     driverClassName = "com.mysql.jdbc.Driver"
13     url = "jdbc:mysql://127.0.0.1:3306/seata"
14     user = "root"
15     password = "123456"
16     minConn = 5
17     maxConn = 30
18     globalTable = "global_table"
19     branchTable = "branch_table"
20     lockTable = "lock_table"
21     queryLimit = 100
22     maxWait = 5000
23   }
24 }
复制代码

这是我的配置,默认配置里还有redis和file模式的默认配置,我没用到就删掉了,这个文件只需要修改几个地方,其余的用默认的就行,如果有兴趣可以自行研究。

 

复制代码
1 # 这个改成自己的数据库类型,注意是seata要连接的数据库,不是业务数据库
2 dbType = "mysql"
3 # 数据库驱动,根据自己的数据库及版本选择
4 driverClassName = "com.mysql.jdbc.Driver"
5 # 数据源配置(懂的都懂),需要自己先建这个库,然后导入官方提供的sql脚本
6 url = "jdbc:mysql://127.0.0.1:3306/seata"
7 user = "root"
8 password = "123456"
复制代码

相关sql脚本,可以到看官方文档,我就不贴了,如果以后更新了贴了可能还会误导,我尽量避免版本更新了我这篇文章就白写了。然后还需要在每个参与全局事务的数据库中加入undo_log表,这是用来存储事务回滚所需的一些数据。

第二步就是修改config.txt文件并添加到nacos

 

复制代码
 1 # my_test_tx_group 可以根据自定义,多个服务可以配置多个
 2 service.vgroupMapping.my_test_tx_group=default
 3 # 因为我的数据库也是在ECS上,所以IP是127.0.0.1,这里与上一步几乎一样
 4 store.mode=db
 5 store.db.datasource=druid
 6 store.db.dbType=mysql
 7 store.db.driverClassName=com.mysql.jdbc.Driver
 8 store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true
 9 store.db.user=root
10 store.db.password=123456
11 # 以下配置我没动,采用默认配置 you can you do
12 store.db.minConn=5
13 store.db.maxConn=30
14 store.db.globalTable=global_table
15 store.db.branchTable=branch_table
16 store.db.queryLimit=100
17 store.db.lockTable=lock_table
18 store.db.maxWait=5000
复制代码

改完之后可以用官方提供的脚本nacos-config.sh将配置添加到nacos配置中心,如果无聊也可以自己一个一个添加

第三步,修改registry.conf

 

复制代码
 1 registry {
 2   # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
 3   # 类型选nacos
 4   type = "nacos"
 5   nacos {
 6     # 应用名默认
 7     application = "seata-server"
 8     # IP 我改成我服务器IP
 9     serverAddr = "127.0.0.1:8848"
10     # 分组就默认,注意:需要参与全局事务的服务都要跟seata-server在同一个命名空间同一个分组
11     group = "SEATA_GROUP"
12     # 我是全部放在自己建的test空间,若没有配置新的命名空间则默认就行
13     namespace = ""
14     cluster = "default"
15     username = "nacos"
16     password = "nacos"
17   }
18 }
19 # 下面配置也一样的,不然无法读取在nacos配置中心的配置
20 config {
21   # file、nacos 、apollo、zk、consul、etcd3
22   # 类型选nacos
23   type = "nacos"
24   nacos {
25     serverAddr = "127.0.0.1:8848"
26     namespace = ""
27     group = "SEATA_GROUP"
28     username = "nacos"
29     password = "nacos"
30   }
31 }
复制代码

  到此seata服务端就安装成功,然后就可以启动seata-server,但是直接使用下面第一个命令启动的话,会有2个问题,一个是关闭终端服务及关闭,二是本地服务会连接不上服务端,因为没有指定IP的话,默认是内网IP,需要改成服务器IP,最好也定一下端口,然后加上其他命令后台启动+后台运行

注意:阿里云服务器的话需要在安全组新增策略开放8091端口,并在内部防火墙开通8091端口或者关闭内部防火墙

 

1 # 12 ./seata-server.sh
3 # 2、将日志输出到nohup.out文件中
4 sudo nohup ./seata-server.sh  -p 8091 -h xxxxxxxxx >nohup.out 2>1 &

然后就可以登录nacos查看seata-server是否启动并注册成功

 

 

2、配置seata客户端

客户端就简单了,只需三步,添加依赖,添加配置,添加注解

添加依赖(至于版本可以根据官方推荐自行选择)

 

复制代码
 1         <dependency>
 2             <groupId>com.alibaba.cloud</groupId>
 3             <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
 4             <version>2.2.2.RELEASE</version>
 5             <exclusions>
 6                 <exclusion>
 7                     <groupId>io.seata</groupId>
 8                     <artifactId>seata-spring-boot-starter</artifactId>
 9                 </exclusion>
10             </exclusions>
11         </dependency>
12         <dependency>
13             <groupId>io.seata</groupId>
14             <artifactId>seata-spring-boot-starter</artifactId>
15             <version>1.3.0</version>
16         </dependency>    
复制代码

添加配置

 

复制代码
 1 seata:
 2   enabled: true
 3   # 我直接用服务名
 4   application-id: user-service
 5   # 这个就是 service.vgroupMapping.my_test_tx_group=default 中的my_test_tx_group 我也用服务名,这2个要一致
 6   tx-service-group: user-service
 7   enable-auto-data-source-proxy: true
 8   config:
 9     type: nacos
10     nacos:
11       namespace: ""
12       serverAddr: 127.0.0.1:8848
13       group: SEATA_GROUP
14       username: "nacos"
15       password: "nacos"
16   registry:
17     type: nacos
18     nacos:
19       application: seata-server
20       server-addr: 127.0.0.1:8848
21       group: SEATA_GROUP
22       namespace: “”
23       username: "nacos"
24       password: "nacos"
复制代码

添加注解

复制代码
1     @GlobalTransactional
2     @Override
3     public Result publish(Article article) {
4 
5         articleMapper.insert(article);
6         userFeign.updatePublishNum(article.getAuthor());
7         return null;
8     }
复制代码
注意:如果采用本地事务@Transactional,insert方法执行成功,调用user-service有问题的话,article是没法回滚的,这就需要使用分布式事务

  seata目前官方提供四种模式,我使用的是最便捷的AT模式,TCC、Saga、XA模式,you can you do,还有所有的服务,包括seata-server一定要在nacos的同一个空间同一个分组

    最后,码字不容易,用你发财的小手点个赞吧,欢迎志同道合的同志,有什么问题或者意见,可以评论私信或者加我的企鹅群876083754(海绵宝宝的菠萝屋)

 
出处:https://www.cnblogs.com/hellohmbb/p/15175062.html


相关教程