一、服务端安装配置
1、下载seata docker镜像
docker pull seataio/seata-server
2、运行镜像
docker run --name seata-server -p 8091:8091 -d seataio/seata-server
3、复制配置文件到主机方便修改
docker cp seata-server:/seata-server /home/dockerdata/seata
4、停止服务
docker stop seata-server
5、删除服务
docker rm seata-server
6、启动SeaTa指定挂载文件
docker run -d --restart always --name seata-server -p 8091:8091 -v /home/dockerdata/seata/seata-server:/seata-server imageId
7、切换到seata配置目录
cd /home/dockerdata/seata/seata-server/resources
8、修改file.conf(本次使用的是db存贮)
#这里手动加入service模块
service {
#transaction service group mapping
#修改,可不改,my_test_tx_group随便起名字。
vgroup_mapping.my_test_tx_group = "default"
#only support when registry.type=file, please don't set multiple addresses
# 此服务的地址
default.grouplist = "127.0.0.1:8091"
#disable seata
disableGlobalTransaction = false
}
## transaction log store, only used in seata-server
store {
## store mode: file db redis
mode = "db"
## file store property
file {
## store location dir
dir = "sessionStore"
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
maxBranchSessionSize = 16384
# globe session size , if exceeded throws exceptions
maxGlobalSessionSize = 512
# file buffer size , if exceeded allocate new buffer
fileWriteBufferCacheSize = 16384
# when recover batch read size
sessionReloadReadSize = 100
# async, sync
flushDiskMode = async
}
## database store property
db {
## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
datasource = "druid"
## mysql/oracle/postgresql/h2/oceanbase etc.
dbType = "mysql"
driverClassName = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://192.168.1.11:3306/seata"
user = "seata"
password = "123456"
minConn = 5
maxConn = 100
globalTable = "global_table"
branchTable = "branch_table"
lockTable = "lock_table"
queryLimit = 100
maxWait = 5000
}
## redis store property
redis {
host = "127.0.0.1"
port = "6379"
password = ""
database = "0"
minConn = 1
maxConn = 10
queryLimit = 100
}
}
9、配置数据库
https://github.com/seata/seata/tree/1.3.0/script/server/db
10、修改registry.conf 我这里使用的是type=eureka作为注册中心
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "eureka"
nacos {
application = "seata-server"
serverAddr = "127.0.0.1:8848"
group = "SEATA_GROUP"
namespace = ""
cluster = "default"
username = ""
password = ""
}
eureka {
serviceUrl = "http://192.168.1.232:8260/eureka"
application = "seate-server"
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"
}
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、etcd3
type = "file"
nacos {
serverAddr = "127.0.0.1:8848"
namespace = ""
group = "SEATA_GROUP"
username = ""
password = ""
}
consul {
serverAddr = "127.0.0.1:8500"
}
apollo {
appId = "seata-server"
apolloMeta = "http://192.168.1.204:8801"
namespace = "application"
}
zk {
serverAddr = "127.0.0.1:2181"
sessionTimeout = 6000
connectTimeout = 2000
username = ""
password = ""
}
etcd3 {
serverAddr = "http://localhost:2379"
}
file {
name = "file.conf"
}
}
二、springboot集成
1、准备工作
- 这里使用的版本是
- spring-boot-starter-parent-2.3.2.RELEASE
- spring-cloud-dependencies-Hoxton.SR6
- spring-cloud-starter-alibaba-seata-2.2.1.RELEASE
具体的pom
<!--springboot-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!--seata-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
<!--spring-cloud-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- netflix-ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!-- netflix-hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2、在你的业务库增加表(选择你适用的sql)
https://github.com/seata/seata/tree/1.3.0/script/client/at/db
3、配置application.properties 复制到你的各个应用中改一下application-id
##############################[seata配置]###################################################
#是否使用分布式事物
seata.enabled=true
seata.application-id=cloud-producer
seata.tx-service-group=my_test_tx_group
seata.enable-auto-data-source-proxy=true
seata.service.vgroup-mapping.my_test_tx_group=default
seata.service.grouplist.default=192.168.1.232:8091
##############################[seata配置]###################################################
4、配置一个切面(解决多路调用数据不一致,各个应用中增加此配置)
@Aspect
@Component
public class SeataTransactionalAspect {
private final static Log logger=Log.get(SeataTransactionalAspect.class);
@Before("execution(* com.jx.producer.impl.*.*(..))")
public void before(JoinPoint joinPoint) throws TransactionException {
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
if(method.isAnnotationPresent(GlobalTransactional.class)) {
logger.info("拦截到需要分布式事务的方法," + method.getName());
// 此处可用redis或者定时任务来获取一个key判断是否需要关闭分布式事务
GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
tx.begin();
logger.info("创建分布式事务完毕" + tx.getXid());
}
}
@AfterThrowing(throwing = "e", pointcut = "execution(* com.jx.producer.impl.*.*(..))")
public void doRecoveryActions(Throwable e) throws TransactionException {
logger.info("方法执行异常:{}", e.getMessage());
if (!StringUtils.isBlank(RootContext.getXID())) {
GlobalTransactionContext.reload(RootContext.getXID()).rollback();
}
}
}
5、全局异常捕获(回滚提示异常消息)
@RestControllerAdvice
public class ExceptionHandle {
private final static Logger LOGGER = LoggerFactory.getLogger(ExceptionHandle.class);
/**
* 全局异常捕捉处理,判断错误是否是已定义的已知错误,不是则由未知错误代替,同时记录在log中
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
public Result exceptionGet(Exception e) {
LOGGER.error("全局异常捕获",e);
if(e instanceof TransactionSystemException) {
return Result.fail("调用异常");
}
return Result.fail(e.getMessage());
}
}
6、使用示例
@Override
@Transactional
//分布式事物注解
@GlobalTransactional
public Result addSeataTest() throws Exception{
Product product=new Product();
product.setItemCode(UID.generateID());
product.setBandName("测试");
product.setName("测试");
product.setPrice(new BigDecimal(20));
productMapper.insertSelective(product);
Result result=consumerFeignClient.stataTest(new SeataTest());
logger.info("处理结果: {}", result.getMsg());
// int i=1/0;
logger.info("当前 XID: {}", RootContext.getXID());
return Result.SUCCESS;
}