seata安装配置
下载
下载中心 | Seata
上传到linux
解压seata压缩包
tar -zxvf seata-server-1.6.1.tar.gz
nacos配置
创建seata的命名空间
id: seata-id
配置seata
备份application.yml
进入/usr/local/software/springcloud/seata/conf文件夹
备份application.yml
mv application.yml application.yml.bak
修改application.example.yml为application.yml
mv application.example.yml application.yml
修改application.yml
添加seata.security模块
seata:
#新添加内容,不加会报错
security:
secretKey: "securityKey"
tokenValidityInMilliseconds: 1000000000
配置seata.config模块
37 config:
38 # support: nacos 、 consul 、 apollo 、 zk 、 etcd3
39 type: nacos
40 nacos:
41 server-addr: 192.168.198.128:7777
42 namespace: seata-id
43 group: SEATA_GROUP
44 username:
45 password:
46 context-path:
47 ##if use MSE Nacos with auth, mutex with username/password attribute
48 #access-key:
49 #secret-key:
50 data-id: seataServer.properties
配置seata.registry模块
72 registry:
73 # support: nacos 、 eureka 、 redis 、 zk 、 consul 、 etcd3 、 sofa
74 type: nacos
75 # preferred-networks: 30.240.*
76 nacos:
77 application: seata-server
78 server-addr: 192.168.198.128:7777
79 group: SEATA_GROUP
80 namespace: seata-id
81 cluster: default
82 username:
83 password:
84 context-path:
85 ##if use MSE Nacos with auth, mutex with username/password attribute
86 #access-key:
87 #secret-key:
配置seata.store模块
使用redis存储
redis:
mode: single
database: 1
min-conn: 10
max-conn: 100
password:
max-total: 100
query-limit: 1000
single:
host: 192.168.198.128
port: 6379
sentinel:
master-name:
sentinel-hosts:
添加console模块
新版本中如果不添加此项会报错。
32 console:
33 user:
34 username: seata
35 password: 123
修改批处理文件
进入/usr/local/software/springcloud/seata/script/config-center/nacos, 修改nacos-config.sh文件
53 if [ -z ${tenant} ]; then
54 tenant="seata-id"
55 fi
启动脚本:
sh nacos-config.sh -h nacos服务器地址
sh nacos-config.sh -h 192.168.198.128
启动seata服务
进入/usr/local/software/springcloud/seata/bin文件夹
-rwxr-xr-x. 1 502 games 3779 12月 16 2022 seata-server.bat
-rwxr-xr-x. 1 502 games 5795 12月 16 2022 seata-server.sh
-rwxr-xr-x. 1 502 games 0 6月 28 2022 startup.sh
[root@localhost bin]# pwd
/usr/local/software/springcloud/seata/bin
./seata-server.sh
[root@localhost bin]# ./seata-server.sh
apm-skywalking not enabled
seata-server is starting, you can check the /usr/local/software/springcloud/seata/logs/start.out
[root@localhost bin]#
springcloud整合seata
数据库设计
创建undo表,放入要执行分布式事务的数据库
CREATE TABLE `undo_log` (
`branch_id` bigint(20) NOT NULL COMMENT 'branch transaction id',
`xid` varchar(128) NOT NULL COMMENT 'global transaction id',
`context` varchar(128) NOT NULL COMMENT 'undo_log context,such as serialization',
`rollback_info` longblob NOT NULL COMMENT 'rollback info',
`log_status` int(11) NOT NULL COMMENT '0:normal status,1:defense status',
`log_created` datetime(6) NOT NULL COMMENT 'create datetime',
`log_modified` datetime(6) NOT NULL COMMENT 'modify datetime',
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AT transaction mode undo table';
引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
</exclusion>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.6.1</version>
</dependency>
bootstrap.yml配置文件
seata:
enabled: true
tx-service-group: default_tx_group
service:
vgroup-mapping:
default_tx_group: default
grouplist:
default: 192.168.198.128:8091
#已经在nacos中配置了,不需要再次配置
# config:
# nacos:
# server-addr: ${spring.cloud.nacos.config.server-addr}
# namespace: seat-id
# group: SEATA_GROUP
# registry:
# nacos:
# application: seata-service
# server-addr: ${spring.cloud.nacos.config.server-addr}
# namespace: seat-id
# group: SEATA_GROUP
订单模块
订单模块添加分布式事务
启动订单模块
主从TM
2023-12-10 23:24:28.728 INFO 13176 --- [ main] i.s.core.rpc.netty.NettyPoolableFactory : NettyPool create channel to transactionRole:TMROLE,address:192.168.198.128:8091,msg:< RegisterTMRequest{applicationId='ssc-cloud-order', transactionServiceGroup='default_tx_group'} >
初始化资源管理(RM)
发起事务请求
使用@GlobalTransactional
package com.wnhz.ssc.cloud.order.service.impl;
import cn.hutool.core.lang.Snowflake;
import com.wnhz.ssc.cloud.order.IOrderDao;
import com.wnhz.ssc.cloud.order.service.IOrderService;
import com.wnhz.ssc.cloud.store.feign.IStoreFeign;
import com.wnhz.ssc.domain.entity.po.Order;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
@Slf4j
@Service
public class OrderServiceImpl implements IOrderService {
@Autowired
private IOrderDao orderDao;
@Autowired
private IStoreFeign storeFeign;
@GlobalTransactional
@Override
public Long createOrder(long productId, int num) {
Order order = new Order();
order.setProduct(productId);
order.setQuantity(num);
order.setCreateBy("test");
order.setCreateTime(new Date());
order.setUpdateTime(new Date());
log.debug("创建order对象成功:{},准备存入数据库....", order);
orderDao.insert(order);
log.debug("订单对象存入数据库成功,准备扣库存....");
storeFeign.decreaseStore(productId, num);
log.debug("库存更成功,商品号:{},扣库存:{}个", productId,num);
long orderId = new Snowflake().nextId();
order.setOrderNum(orderId);
orderDao.updateById(order);
log.debug("订单号更新完成:{}", orderId);
return orderId;
}
}
Begin new global transaction [172.18.1.1:8091:8269074957769797653]
:
:
rm handle branch rollback process:xid=172.18.1.1:8091:8269074957769797653,branchId=8269074957769797654,branchType=AT,resourceId=jdbc:mysql://192.168.198.128:3306/ssc_db,applicationData={"skipCheckLock":true}
Branch Rollbacking: 172.18.1.1:8091:8269074957769797653 8269074957769797654 jdbc:mysql://192.168.198.128:3306/ssc_db
Branch Rollbacked result: PhaseTwo_Rollbacked
Suspending current transaction, xid = 172.18.1.1:8091:8269074957769797653
[172.18.1.1:8091:8269074957769797653] rollback status: Rollbacked
[172.18.1.1:8091:8269074957769797653] rollback status: Finished
自定义异常捕获
由于分布式调用返回的异常可能为OpenFeign的异常,分布式事务异常捕获失败。
定义切面捕获分布式 事务异常
package com.wnhz.ssc.cloud.order.aop;
import io.seata.core.context.RootContext;
import io.seata.core.exception.TransactionException;
import io.seata.tm.api.GlobalTransactionContext;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@Aspect
@Component
@Slf4j
public class SeataExceptionAop {
@Pointcut("@annotation(io.seata.spring.annotation.GlobalTransactional)")
public void transactionPointCut(){}
@AfterThrowing(throwing = "e",pointcut = "transactionPointCut()")
public void globalTransactionalExceiton(Throwable e) throws TransactionException {
log.debug("分布式事务异常:{}", e.getMessage());
String xid = RootContext.getXID();
if(StringUtils.hasText(xid)){
log.debug("XID:{}执行回滚操作", xid);
GlobalTransactionContext.reload(xid).rollback();
log.debug("事务:{}回滚完成", xid);
throw new TransactionException("事务处理失败,回滚完成........");
}
}
}