前言
本文将介绍如何使用Seata实现分布式事务。将覆盖以下主题:
- seata下载与安装
- 如何配置和启动Seata服务器
- 如何编写应用程序以使用Seata
- 如何解决常见问题
本文只是我个人seata学习笔记,不是什么学习教程
如果你是一名Java开发人员,那么你一定听说过Seata。Seata是一个分布式事务解决方案,可以帮助开发人员在分布式系统中实现ACID事务,保证数据的一致性和可靠性。如果你还没有了解过Seata,那么建议你先去官方文档里看看,了解一下它的基本概念和用法。官方文档详细介绍了Seata的架构、设计原则和使用方法,对于想要深入学习Seata的开发人员来说是非常有帮助的。同时,我们也可以通过阅读其他开发人员的经验分享和案例分析,更好地掌握Seata在实际项目中的应用。
官方文档:seata中文文档
01 下载解压Seata
你要在Spring Cloud Alibaba中使用Seata,就一定要根据版本说明下载对应的Seata版本。因为不同版本的Spring Cloud Alibaba和Seata之间可能存在兼容性问题,如果使用不兼容的版本,就有可能会出现各种问题,如启动失败、事务不生效等。因此,在选择Seata版本时,一定要仔细查看官方文档中的版本说明和兼容性列表,确保所选择的版本与当前使用的Spring Cloud Alibaba版本兼容。这样才能保证Seata在Spring Cloud Alibaba中正常运行,发挥其应有的作用。
下载地址:Releases · seata/seata (github.com)
我下的版本:Release v1.5.2 · seata/seata (github.com)
下载到linux中并解压
你可以使用以下的命令来解压缩.tar.gz
文件
tar -zxvf seata-server-1.5.2.tar.gz
其中:
-z
表示解压缩gzip压缩的文件,-x
表示从压缩文件中提取文件,-v
表示详细输出提取的文件列表,-f
后面跟需要解压缩的文件名。
执行此命令后,你将在当前目录下得到一个新的目录 ‘seata
’。
02 修改配置文件
主要修改:事务日志存储模式修改为DB+数据库连接信息+注册中心
修改 seata\conf\application.yml 的内容主要有以下三部分:
第一步:添加存储方式
以下步骤按照DB存储为例:
store:
mode: db
db:
datasource: druid
db-type: mysql
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/seata-01?rewriteBatchedStatements=true
user: root
password: 123456
store指定了Seata事务日志存储模式为数据库模式,采用了Druid连接池,数据库类型为MySQL。
- 创建 seata-01 数据库 :
- 创建表:
点查新-新建查询-sql语句复制到查询中-点击运行
sql语句地址
-- -------------------------------- 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 = InnoDB
DEFAULT 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 = InnoDB
DEFAULT 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` (`xid`)
) ENGINE = InnoDB
DEFAULT 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 = InnoDB
DEFAULT 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);
第二步:修改注册中心
registry:
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace:
cluster: default
username:
password:
第三部:添加配置中心
seata:
config:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
namespace:
group: SEATA_GROUP
username:
password:
最终的application.yml文件内容:
server:
port: 7091
spring:
application:
name: seata-server
logging:
config: classpath:logback-spring.xml
file:
path: ${user.home}/logs/seata
extend:
logstash-appender:
destination: 127.0.0.1:4560
kafka-appender:
bootstrap-servers: 127.0.0.1:9092
topic: logback_to_logstash
console:
user:
username: seata
password: seata
seata:
config:
# support: nacos 、 consul 、 apollo 、 zk 、 etcd3
type: nacos
nacos:
server-addr: 127.0.0.1:8848
namespace:
group: SEATA_GROUP
username:
password:
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key: ""
#secret-key: ""
data-id: seataServer.properties
registry:
# support: nacos 、 eureka 、 redis 、 zk 、 consul 、 etcd3 、 sofa
type: nacos
#preferred-networks: 30.240.*
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace:
cluster: default
username:
password:
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key: ""
#secret-key: ""
server:
service-port: 8091 #If not configured, the default is '${server.port} + 1000'
max-commit-retry-timeout: -1
max-rollback-retry-timeout: -1
rollback-retry-timeout-unlock-enable: false
enable-check-auth: true
enable-parallel-request-handle: true
retry-dead-threshold: 130000
xaer-nota-retry-timeout: 60000
recovery:
handle-all-session-period: 1000
undo:
log-save-days: 7
log-delete-period: 86400000
session:
branch-async-queue-size: 5000 #branch async remove queue size
enable-branch-async-remove: false #enable to asynchronous remove branchSession
store:
# support: file 、 db 、 redis
mode: db
#session:
# mode: file
#lock:
# mode: file
db:
datasource: druid
db-type: mysql
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.90.137:3306/seata-01?rewriteBatchedStatements=true
user: root
password: 123456
min-conn: 5
max-conn: 100
global-table: global_table
branch-table: branch_table
lock-table: lock_table
distributed-lock-table: distributed_lock
query-limit: 100
max-wait: 5000
metrics:
enabled: false
registry-type: compact
exporter-list: prometheus
exporter-prometheus-port: 9898
transport:
rpc-tc-request-timeout: 30000
enable-tc-server-batch-send-response: false
shutdown:
wait: 3
thread-factory:
boss-thread-prefix: NettyBoss
worker-thread-prefix: NettyServerNIOWorker
boss-thread-size: 1
security:
secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
tokenValidityInMilliseconds: 1800000
ignore:
urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login
这个配置文件的内容可能会因为Seata版本的不同而略有不同,具体的配置项也可能会有所变化。因此,在使用Seata时,建议先查看官方文档中的配置说明,根据实际情况进行配置。另外,Seata还提供了多种配置方式,如通过配置文件、通过环境变量、通过命令行参数等,可以根据自己的习惯和需求选择合适的方式进行配置。
02 配置上传
上面的代码已经改为db模式,并且用nacos作为注册中心了,所以我们接下来要做的就是将配置上传到nacos进行存储
第一步:修改config.txt文件
onfig.txt提供的默认参数太多,所以去掉了我用不着的配置,我自己的最终config.txt文件如下:
编辑:seata\script\config-center\config.txt
文件,改成以下配置 :
#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
transport.serialization=seata
transport.compressor=none
#Transaction routing rules configuration, only for the client
service.vgroupMapping.default_tx_group=default
#If you use a registry, you can ignore it
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
#Transaction rule configuration, only for the client
#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h
#Log rule configuration, for client and server
log.exceptionRate=100
第二步:执行nacos-config.sh文件
进到:seata\script\config-center\nacos
使用以下的命令来给文件添加执行权限:
chmod +x nacos-config.sh
然后运行脚本
./nacos-config.sh
启动参数说明如下:
成功设置了28个参数。提示你 SEATA 的配置已完成,可以启动 SEATA 服务器了。
执行成功后可以打开Nacos的控制台,在配置列表中,可以看到初始化了很多Group为SEATA_GROUP的配置。
03: 启动seata服务
启动 SEATA 服务器方式:
- 使用 SEATA 官方提供的脚本启动
在安装完 SEATA 后,可以切换到 SEATA 安装目录下的 bin 目录,执行以下命令启动 SEATA 服务器:
sh seata-server.sh
是启动 SEATA 服务器时的一个命令。
参数具体含义如下:
-p
:指定 SEATA 服务器启动的端口号;-h
:指定 SEATA 服务器的 IP 地址;-m
:指定 SEATA 的事务日志存储模式:
启动 SEATA 服务器时需要用到这些参数,以指定 SEATA 服务器的启动配置,确保其能够正确地存储和管理分布式事务。
启动报错:
[root@localhost bin]# sh seata-server.sh -p 7091 -h 127.0.0.1 -m db
apm-skywalking not enabled
seata-server is starting, you can check the /download/seata/seata/logs/start.out
[root@localhost bin]# cat /download/seata/seata/logs/start.out
/download/jdks/jdk-11//bin/java -server -Dloader.path=../lib -Xmx2048m -Xms2048m -Xmn1024m -Xss512k -XX:SurvivorRatio=10 -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:MaxDirectMemorySize=1024m -XX:-OmitStackTraceInFastThrow -XX:-UseAdaptiveSizePolicy -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/download/seata/seata/logs/java_heapdump.hprof -XX:+DisableExplicitGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=75 -Xloggc:/download/seata/seata/logs/seata_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -Dio.netty.leakDetectionLevel=advanced -Dapp.name=seata-server -Dapp.pid=7277 -Dapp.home=/download/seata/seata -Dbasedir=/download/seata/seata -Dspring.config.location=/download/seata/seata/conf/application.yml -Dlogging.config=/download/seata/seata/conf/logback-spring.xml -jar /download/seata/seata/target/seata-server.jar -p 7091 -h 127.0.0.1 -m db
[0.000s][warning][gc] -Xloggc is deprecated. Will use -Xlog:gc:/download/seata/seata/logs/seata_gc.log instead.
Unrecognized VM option 'PrintGCDateStamps'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
报错信息:
- Error: Could not create the Java Virtual Machine.
- Error: A fatal exception has occurred. Program will exit.
原因:shell脚本获取jdk版本不对 解决:修改 seata-server.sh。 JAVA_MAJOR_VERSION= ( ( (JAVACMD -version 2>&1 | sed ‘1!d’ | sed -e ‘s/"//g’ | awk ‘{print $3}’ | awk -F ‘.’ ‘{print $1}’) print $2 改为 print $1。
最后再次启动 SEATA 服务器,启动后在 Nacos 的服务列表下面可以看到一个名为 seata-server的服务。
sh seata-server.sh
到这里,其实我们就完成了Seata服务端的注册和配置的统一管理了,这个做完之后,接下来的就是要结合微服框架进行整合,实现分布式事务场景了
04: 简单使用
下面是一个简单的 Spring Cloud Alibaba Seata 实例。
假设我们有一个微服务应用,其中包含两个服务:订单服务(order-server)和库存服务(inventory-server),需要使用 Seata 进行分布式事务处理。
创建两个订单服务(order-server)和库存服务(inventory-server) 并且注册到nacos中
第一步:添加依赖
在订单服务和库存服务的 pom.xml 中添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.11</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
=======================================================================================================
<!--nacos客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--seata的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
=============================================================================================================
第二步:配置文件
在订单服务和库存服务中分别添加 Seata 配置信息:
=============================================inventory-server==============================================
spring:
application:
name: inventory-server
datasource:
druid:
url: jdbc:mysql://localhost:3306/inventory-server?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
cloud:
nacos:
discovery:
server-addr: 192.168.157.130:8848
seata:
registry:
type: nacos
nacos:
application: seata-server
server-addr: 192.168.157.130:8848
group: SEATA_GROUP
config:
type: nacos
nacos:
server-addr: 192.168.157.130:8848
group: SEATA_GROUP
tx-service-group: default_tx_group
mybatis:
mapper-locations: classpath:/mapper/*.xml
server:
port: 9410
=============================================inventory-server==============================================
spring:
application:
name: order-server
datasource:
druid:
url: jdbc:mysql://localhost:3306/order-server?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
cloud:
nacos:
discovery:
server-addr: 192.168.157.130:8848
seata:
registry:
type: nacos
nacos:
application: seata-server
server-addr: 192.168.157.130:8848
group: SEATA_GROUP
config:
type: nacos
nacos:
server-addr: 192.168.157.130:8848
group: SEATA_GROUP
tx-service-group: default_tx_group #自定义组名称,需要与seata-server中配置的对应
mybatis:
mapper-locations: classpath:/mapper/*.xml
server:
port: 9412
在这个配置文件中,Seata使用了Nacos作为服务注册中心和配置中心。registry.type和config.type都被设为了nacos,同时指定了Nacos的相关配置如服务器地址和应用名。tx-service-group指定了Seata事务组名为default_tx_group。mybatis.mapper-locations指定了MyBatis的XML映射文件位置。此外,还有应用名、数据源等其他配置。
注意:
seata:
tx-service-group: default_tx_group
tx-service-group事务组名的值等于:seata\script\config-center\config.txt文件里面的:
service.vgroupMapping.default_tx_group=default 中的最后一段内容,default_tx_group
第三步:添加依赖
在订单服务和库存服务的 pom.xml 中添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.11</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
=======================================================================================================
<!--nacos客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--seata的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
=============================================================================================================
第三步:编写接口
order-server
order:Controller
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
OrderService orderService;
@GetMapping("updateById")
public Integer updateById(@RequestParam("id") Integer id,@RequestParam("name") String name){
return orderService.updateById(id,name);
}
}
order:mapper.xml
<update id="updateById" >
update ordertable set name = #{name} where id =#{id}
</update>
order: 启动类
@SpringBootApplication
@MapperScan("com.buba.mapper")
@EnableDiscoveryClient //启用服务注册与发现
@EnableFeignClients //开启Fegin
public class OrderServerApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServerApplication.class,args);
System.out.println("run");
}
}
inventory-server
inventory:controller:
@RestController
@RequestMapping("/inventory")
public class InventoryController {
@Autowired
InventoryService inventoryService;
@GetMapping("/updateById")
public Integer updateById(@RequestParam("id") Integer id, @RequestParam("name") String name){
return inventoryService.updateById(id,name);
}
}
inventory:mapper.xml
<update id="updateById">
update inventory set name = #{name} where id = #{id}
</update>
inventory: 启动类
@SpringBootApplication
@EnableDiscoveryClient //启用服务注册与发现
@EnableFeignClients //开启Fegin
public class InventoryServerApplication {
public static void main(String[] args) {
SpringApplication.run(InventoryServerApplication.class,args);
System.out.println("run");
}
}
inventory: OrderFeign接口
@FeignClient(name = "order-server",path = "/order")
public interface OrderFeign {
@GetMapping("updateById")
Integer updateById(@RequestParam("id") Integer id, @RequestParam("name") String name);
}
inventory: Service
@Service
public class InventoryServiceImpl implements InventoryService {
@Autowired
InventoryMapper inventoryMapper;
@Autowired
OrderFeign orderFeign;
@Override
@GlobalTransactional
public Integer updateById(Integer id, String name) {
Integer number = orderFeign.getNumber(id,name);
Integer num = inventoryMapper.updateById(id,name);
return num+number;
}
}
第四步:添加回滚日志表
两个库下都需要建各自的回滚日志表
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`)
) ENGINE = INNODB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8;
第五步:测试接口
nventory: Service
@Service
public class InventoryServiceImpl implements InventoryService {
@Autowired
InventoryMapper inventoryMapper;
@Autowired
OrderFeign orderFeign;
@Override
@GlobalTransactional
public Integer updateById(Integer id, String name) {
Integer number = orderFeign.getNumber(id,name);
int i = 5/0;
Integer num = inventoryMapper.updateById(id,name);
return num+number;
}
}
添加了一个运行时异常 java.lang.ArithmeticException: / by zero
,模拟数据修改过程中的异常情况
debug模式启动 inventory-server,并且给int i = 5/0;
打断点
访问inventory-server服务的http://localhost:9410/inventory/updateById
接口
打开idea
先不要恢复程序,打开数据库查看ordertable表和undo_log
最后放开debug恢复程序,接口返回500
打开数据库的表-右键刷新,发现数据改回去了
当程序执行到int i = 5/0时,会抛出一个异常并进入异常处理流程,此时事务会回滚。
05: 报错笔记
(1):启动报错:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘globalTransactionScanner’ defined in class path resource [io/seata/spring/boot/autoconfigure/SeataAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.seata.spring.annotation.GlobalTransactionScanner]: Factory method ‘globalTransactionScanner’ threw exception; nested exception is java.lang.ExceptionInInitializerError
解决方法:
首先,它是由Spring框架引起的,它尝试通过工厂方法创建bean时遇到了一个错误。具体来说,是由于全局事务扫描器(globalTransactionScanner
)的初始化失败导致的,这个扫描器又是在SeataAutoConfiguration类中定义的。
解决这个问题的方法非常简单,只需要将VM选项添加:–add-opens=java.base/java.lang=ALL-UNNAMED。这个命令会在JVM启动时添加指定的选项,让Java程序能够正确地使用某些类。如果您使用的是Java 9及以上版本,那么就需要使用这个命令才能避免出现这类错误。
VM选项添加:--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.lang=ALL-UNNAMED
(2):启动报错:
- io.seata.common.exception.FrameworkException: can not register RM,err:can not connect to services-server.
- 2023-05-30 19:34:04.257 ERROR 7508 — [ main] i.s.c.r.netty.NettyClientChannelManager : 0101 can not connect to 192.168.157.130:8091 cause:can not register RM,err:can not connect to services-server.
解决方法:
此次报错是由Seata分布式事务框架引起的。该错误是在尝试注册资源管理器(RM)时无法连接到注册中心引起的。以下可能是引起错误的原因:
-
Seata Server 没有正确启动或无法访问
-
注册中心配置不正确
-
业务应用程序与注册中心无法通信
-
Seata 配置文件配置不正确
要解决这个问题,您需要检查详细的错误日志,以了解更多关于错误的信息,以便更进一步地排查和解决问题。
但本次经过检查后发现问题原因是端口号没打开。
可以使用firewall-cmd --zone=public --list-ports
命令查看开放的防火墙端口。为确保Seata能够正常工作,可以使用以下命令打开Seata默认端口号8091:
firewall-cmd --zone=public --add-port=8091/tcp --permanent
最后,要记得刷新防火墙以重新加载端口号:
firewall-cmd --reload
(3):启动seata服务报错:
[root@localhost bin]# sh seata-server.sh -p 7091 -h 127.0.0.1 -m db
apm-skywalking not enabled
seata-server is starting, you can check the /download/seata/seata/logs/start.out
[root@localhost bin]# cat /download/seata/seata/logs/start.out
/download/jdks/jdk-11//bin/java -server -Dloader.path=../lib -Xmx2048m -Xms2048m -Xmn1024m -Xss512k -XX:SurvivorRatio=10 -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:MaxDirectMemorySize=1024m -XX:-OmitStackTraceInFastThrow -XX:-UseAdaptiveSizePolicy -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/download/seata/seata/logs/java_heapdump.hprof -XX:+DisableExplicitGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=75 -Xloggc:/download/seata/seata/logs/seata_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -Dio.netty.leakDetectionLevel=advanced -Dapp.name=seata-server -Dapp.pid=7277 -Dapp.home=/download/seata/seata -Dbasedir=/download/seata/seata -Dspring.config.location=/download/seata/seata/conf/application.yml -Dlogging.config=/download/seata/seata/conf/logback-spring.xml -jar /download/seata/seata/target/seata-server.jar -p 7091 -h 127.0.0.1 -m db
[0.000s][warning][gc] -Xloggc is deprecated. Will use -Xlog:gc:/download/seata/seata/logs/seata_gc.log instead.
Unrecognized VM option 'PrintGCDateStamps'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
报错信息:
- Error: Could not create the Java Virtual Machine.
- Error: A fatal exception has occurred. Program will exit.
提供的报错信息表明在启动Seata服务时无法创建虚拟机,并出现了致命异常。这可能是由于 shell脚本获取JDK版本的错误导致的。
你可以尝试修改seata-server.sh
文件。将以下行:
JAVA_MAJOR_VERSION=$($JAVACMD -version 2>&1 | sed '1!d' | sed -e 's/"//g' | awk '{print $3}' | awk -F '.' '{print $1}') print $2
修改为:
JAVA_MAJOR_VERSION=$($JAVACMD -version 2>&1 | sed '1!d' | sed -e 's/"//g' | awk '{print $3}' | awk -F '.' '{print $1}') print $1
这将修复该错误并允许Seata服务启动,最后再次启动 SEATA 服务器
希望这个解决方法能够解决你的问题。有其他问题在评论区讨论-或者私信我-收到会在第一时间回复