在搭建Seata分布式事务中遇到各种报错的解决方式
在成为项目负责人以后,前几个月一直忙于开发公司平台1.0,没有更新博客了。如今1.0的开发工作已经完成得七七八八,接下来需要搭建微服务的架构了。架构设计还是本人,接下来由这篇文章开始,记录我在搭建2.0平台微服务架构所踩的雷。
1. 服务端搭建
seata服务端的难点在于,需要配置的东西比较多,改各类的配置文件,接下来我给大家说说是哪些地方,关于seata服务端的搭建,由于使用了微服务,我们可以把Seata Server注册到nacos做配置统一管理,具体步骤如下:
首先我们要修改一下registry.conf:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| registry { # seata Server端启动时会先加载type,根据type 去找对应的配置 #file 、nacos 、eureka、redis、zk、consul、etcd3、sofa type = "nacos"
nacos { application = "seata-server" serverAddr = "注册中心ip:8848" group = "SEATA_GROUP" namespace = "" cluster = "default" username = "" password = "" } eureka { serviceUrl = "http://localhost:8761/eureka" application = "default" weight = "1" } redis { serverAddr = "localhost:6379" db = 0 password = "" cluster = "default" timeout = 0 } zk { cluster = "default" serverAddr = "127.0.0.1:2181" sessionTimeout = 6000 connectTimeout = 2000 username = "" password = "" } consul { cluster = "default" serverAddr = "127.0.0.1:8500" aclToken = "" } 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" } # 会根据 type = file 找到这里,然后再去读取"file.conf" file { name = "file.conf" } }
config { # file、nacos 、apollo、zk、consul、etcd3 type = "nacos"
nacos { serverAddr = "注册中心ip:8848" namespace = "" group = "SEATA_GROUP" username = "" password = "" } consul { serverAddr = "127.0.0.1:8500" aclToken = "" } apollo { appId = "seata-server" ## apolloConfigService will cover apolloMeta apolloMeta = "http://192.168.1.204:8801" apolloConfigService = "http://192.168.1.204:8080" namespace = "application" apolloAccesskeySecret = "" cluster = "seata" } zk { serverAddr = "127.0.0.1:2181" sessionTimeout = 6000 connectTimeout = 2000 username = "" password = "" nodePath = "/seata/seata.properties" } etcd3 { serverAddr = "http://localhost:2379" } file { name = "file.conf" } }
|
其实没用的配置可以把它删掉,这里不多演示。
接下来是最关键的,获取/seata源码/script/config-center/config.txt,修改config.txt配置信息:
1 2 3 4 5 6 7 8
| store.mode=db store.db.datasource=druid store.db.dbType=mysql store.db.driverClassName=com.mysql.cj.jdbc.Driver store.db.url=jdbc:mysql://xxx:3306/seata?useUnicode=true&rewriteBatchedStatements=true store.db.user=nacos store.db.password=Springbootv2 service.vgroupMapping.guangzhou=default
|
⭐⭐⭐上面给出的都是我们需要改的,这里注意的是,配置事务分组, 要与客户端配置的事务分组一致,这个非常重要,如果不对应的话,客户端会找不到服务端服务。
服务端最后一步就是,在cmd窗口中执行shell脚本,会自动把config.txt文件的配置信息推送到nacos对应的namespace下,这边给出一个例子:
1
| sh ${SEATAPATH}/script/config-center/nacos/nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t 5a3c7d6c-f497-4d68-a71a-2e5e3340b3ca
|
⭐参数说明:
-h: IP地址:默认值 localhost
-p: 端口号:默认值 8848
-g: 配置分组:默认值为 ‘SEATA_GROUP’
-t: 租户信息:对应 Nacos 的命名空间ID字段, 默认值为空
大功告成!可以烧个小烟花,因为脏活搞完了。
2. 客户端搭建
相比于服务端搭建,客户端就显得so easy了,只需要在原有的依赖上加入seata依赖就好了,由于我们父maven定义了版本控制,所以也不需要搞版本了。
1 2 3 4 5
| <dependency> <groupId>io.seata</groupId> <artifactId>seata-all</artifactId> </dependency>
|
接下来,要为每一个服务的数据库创建undo_log表,这个表示用来记录回滚的,这里的sql文件在seata的源代码文件里面有,这里就不唠叨了。
最后配置一下yml,启动类上需要排除DataSourceAutoConfiguration,否则会出现循环依赖的问题,业务代码上面加个 @GlobalTransactional的注解就能用分布式事务了,这边比较简单不再细讲,然后贴一下yml里面改什么:
1 2 3 4 5 6 7 8 9 10 11
| spring: application: name: order-service cloud: nacos: discovery: server-addr: 注册中心ip:8848 alibaba: seata: tx-service-group: my_test_tx_group
|
3. 序列化问题
这个问题出现的也是比较常见,但是我看网上很少解决方式,因此我在这边说一下我的解决方式。

当报这个错误的时候,如报错信息所示,是因为我们没有引入一个叫kryo的依赖,那么为什么会这样呢?上网一查,原因是这样的:
在Spring Boot 1.5x 版本中原始引入的Jackson版本过低,会导致Seata依赖Jackson的新特性找不到,Seata要求Jackson版本2.9.9+,但是使用Jackson 2.9.9+版本会导致Spring Boot中使用的Jackson API找不到,也就是Jackson本身的向钱兼容性存在问题。因此,建议大家将Seata的序列化方式切换到非Jackson序列化方式,比如kryo。
好了,说了那么多,其实也很好理解,其实就加个依赖嘛,那就直接干。
1 2 3 4 5
| <dependency> <groupId>com.esotericsoftware</groupId> <artifactId>kryo</artifactId> <version>4.0.2</version> </dependency>
|
引入完以后,项目重启,依然报错:

由报错信息很容易看出(NoClassDefFoundErrer),还缺了依赖,那么我们继续引入依赖
1 2 3 4 5
| <dependency> <groupId>de.javakaffee</groupId> <artifactId>kryo-serializers</artifactId> <version>0.44</version> </dependency>
|
重启后验证功能,功能正常,成功解决!
4. AT模式回滚问题
关于这个回滚的问题,很多新手会说:“咦,seata数据库里面的global_table、branch_table 、lock_table、undo_log表里面怎么没有数据?”
别着急,因为回滚得太快了,你要打个断点debug运行一下就可以看到数据库表里面有插入和删除操作的了。