seata服务端和spring源码项目地址(很详细的资源-包括建表等等):完整项目地址
服务调用关系图:
那么现在开始搭建分布式事务吧,本文章是和上面项目地址里面的项目所进行对应的,建议读者对seata有所了解,这样跟着步骤走,不仅能加深对分布式事务的理解,同时也能体会到分布式事务的简单与强大!!!
1:搭建seata服务端:
2:启动eureka,并启动seata-server(window 在/bin/seata-server.bat)
3:建立数据库
需要建立4个微服务的数据库和一个seata-server数据库,并且每个rm微服务参与者的数据库里面都必须有undo_log表用来存当前事务的回滚数据,,建数据库的sql在项目里面有
4:在原有项目基础上改造微服务
transport {
# tcp udt unix-domain-socket
type = "TCP"
#NIO NATIVE
server = "NIO"
#enable heartbeat
heartbeat = true
# the client batch send request enable
enableClientBatchSendRequest = true
#thread factory for netty
threadFactory {
bossThreadPrefix = "NettyBoss"
workerThreadPrefix = "NettyServerNIOWorker"
serverExecutorThread-prefix = "NettyServerBizHandler"
shareBossWorker = false
clientSelectorThreadPrefix = "NettyClientSelector"
clientSelectorThreadSize = 1
clientWorkerThreadPrefix = "NettyClientWorkerThread"
# netty boss thread size,will not be used for UDT
bossThreadSize = 1
#auto default pin or 8
workerThreadSize = "default"
}
shutdown {
# when destroy server, wait seconds
wait = 3
}
serialization = "seata"
compressor = "none"
}
service {
#transaction service group mapping
vgroup_mapping.seata-test-server = "seata-test-server" #修改事务组名称为:fsp_tx_group,和客户端自定义的名称对应
#only support when registry.type=file, please don't set multiple addresses
seata-test-server.grouplist = "127.0.0.1:8091"
#degrade, current not support
enableDegrade = false
#disable seata
disableGlobalTransaction = false
}
client {
rm {
asyncCommitBufferLimit = 10000
lock {
retryInterval = 10
retryTimes = 30
retryPolicyBranchRollbackOnConflict = true
}
reportRetryCount = 5
tableMetaCheckEnable = false
reportSuccessEnable = false
}
tm {
commitRetryCount = 5
rollbackRetryCount = 5
}
undo {
dataValidation = true
logSerialization = "jackson"
logTable = "undo_log"
}
log {
exceptionRate = 100
}
}
-registry.conf
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "eureka"
nacos {
serverAddr = "localhost"
namespace = ""
cluster = "default"
}
eureka {
serviceUrl = "http://127.0.0.1:7001/eureka"
application = "seata-test-server"
weight = "1"
}
redis {
serverAddr = "localhost:6379"
db = "0"
password = ""
cluster = "default"
timeout = "0"
}
zk {
cluster = "default"
serverAddr = "127.0.0.1:2181"
session.timeout = 6000
connect.timeout = 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、springCloudConfig
type = "file"
nacos {
serverAddr = "localhost"
namespace = ""
group = "SEATA_GROUP"
}
consul {
serverAddr = "127.0.0.1:8500"
}
apollo {
app.id = "seata-server"
apollo.meta = "http://192.168.1.204:8801"
namespace = "application"
}
zk {
serverAddr = "127.0.0.1:2181"
session.timeout = 6000
connect.timeout = 2000
username = ""
password = ""
}
etcd3 {
serverAddr = "http://localhost:2379"
}
file {
name = "file.conf"
}
}
-添加代理数据源
package com.atguigu.springcloud.config;
import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.web.client.RestTemplate;
import javax.sql.DataSource;
/**
* 数据源代理
* @author wangzhongxiang
*/
@Configuration
public class DataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
@Primary
@Bean("dataSource")
public DataSourceProxy dataSource(DataSource druidDataSource){
return new DataSourceProxy(druidDataSource);
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSourceProxy dataSourceProxy)throws Exception{
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSourceProxy);
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath*:/mapper/*.xml"));
sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
return sqlSessionFactoryBean.getObject();
}
}
spring:
application:
name: cloud-payment-service8004
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://127.0.0.1:3306/my_data8004?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: daibin
#分布式事务
cloud:
alibaba:
seata:
tx-service-group: seata-test-server
5:在触发点加一个全局分布式事务注解
我这里的触发点是8001的这个微服务
package com.atguigu.springcloud.service.impl;
import com.atguigu.springcloud.dao.PaymentDao;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentService;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@Service
public class PaymentServiceImpl implements PaymentService {
@Resource
private PaymentDao paymentDao;
@Autowired
private RestTemplate restTemplate;
@Override
//全局事务注解
@GlobalTransactional(name = "seata-test-server", rollbackFor = Exception.class)
public int create(Payment payment) {
int id=paymentDao.create(payment);
if(payment.getSerial().equals("第8001调")){
int i=1/0;
}
if(payment.getSerial().equals("第8001调延时")){
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String url8002="http://127.0.0.1:8002/payment/create";
String url8004="http://127.0.0.1:8004/payment/create";
restTemplate.postForObject(url8002,payment,Object.class);
restTemplate.postForObject(url8004,payment,Object.class);
return id;
}
@Override
public Payment getPaymentById(Integer id) {
return paymentDao.getPaymentById(id);
}
}
6:启动项目测试