Spring Cloud:Seata分布式事务实例

快速开始

用例

用户购买商品的业务逻辑。整个业务逻辑由3个微服务提供支持:
  • 仓储服务:对给定的商品扣除仓储数量。
  • 订单服务:根据采购需求创建订单。
  • 帐户服务:从用户帐户中扣除余额。

架构图

仓储服务

public interface StorageService {

/**
* 扣除存储数量
*/
void deduct(String commodityCode, int count);
}

订单服务

public interface OrderService {

/**
* 创建订单
*/
Order create(String userId, String commodityCode, int orderCount);
}

帐户服务

public interface AccountService {

/**
* 从用户账户中借出
*/
void debit(String userId, int money);
}

主要业务逻辑

public class BusinessServiceImpl implements BusinessService {

private StorageService storageService;

private OrderService orderService;

/**
* 采购
*/
public void purchase(String userId, String commodityCode, int orderCount) {

storageService.deduct(commodityCode, orderCount);

orderService.create(userId, commodityCode, orderCount);
}
}


public class OrderServiceImpl implements OrderService {

private OrderDAO orderDAO;

private AccountService accountService;

public Order create(String userId, String commodityCode, int orderCount) {

int orderMoney = calculate(commodityCode, orderCount);

accountService.debit(userId, orderMoney);

Order order = new Order();
order.userId = userId;
order.commodityCode = commodityCode;
order.count = orderCount;
order.money = orderMoney;

// INSERT INTO orders ...
return orderDAO.insert(order);
}
}

SEATA 的分布式交易解决方案

  我们只需要使用一个  @GlobalTransactional  注解在业务方法上:
 

@GlobalTransactional
public void purchase(String userId, String commodityCode, int orderCount) {
......
}

由Dubbo + SEATA提供支持的示例

步骤 1:建立数据库

  • 要求:具有InnoDB引擎的MySQL。
注意:  实际上,在示例用例中,这3个服务应该有3个数据库。 但是,为了简单起见,我们只能创建一个数据库并配置3个数据源。
使用您刚创建的数据库 URL/username/password 修改Spring XML。
dubbo-account-service.xml dubbo-order-service.xml dubbo-storage-service.xml
<property name="url" value="jdbc:mysql://x.x.x.x:3306/xxx" />
<property name="username" value="xxx" />
<property name="password" value="xxx" />

步骤 2:创建 UNDO_LOG 表

SEATA AT 模式需要  UNDO_LOG 
-- 注意此处0.3.0+ 增加唯一索引 ux_undo_logCREATE 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;

步骤 3:为示例业务创建表

DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
`money` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


DROP TABLE IF EXISTS `account_tbl`;
CREATE TABLE `account_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`money` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

步骤 4: 启动服务

Usage: sh seata-server.sh(for linux and mac) or cmd seata-server.bat(for windows) [options]
Options:
--host, -h
The host to bind.
Default: 0.0.0.0
--port, -p
The port to listen.
Default: 8091
--storeMode, -m
log store mode : file、db
Default: file
--help

e.g.

sh seata-server.sh -p 8091 -h 127.0.0.1 -m file

步骤 5: 运行示例

示例仓库:  seata-samples
  • 启动 DubboAccountServiceStarter
  • 启动 DubboStorageServiceStarter
  • 启动 DubboOrderServiceStarter
  • 运行 DubboBusinessTester for demo test
注意事项
1、必须使用代理数据源,有 3 种形式可以代理数据源:
  • 依赖 seata-spring-boot-starter 时,自动代理数据源,无需额外处理。
  • 依赖 seata-all 时,使用 @EnableAutoDataSourceProxy (since 1.1.0) 注解,注解参数可选择 jdk 代理或者 cglib 代理。
  • 依赖 seata-all 时,也可以手动使用 DatasourceProxy 来包装 DataSource。
2、配置 GlobalTransactionScanner,使用 seata-all 时需要手动配置,使用 seata-spring-boot-starter 时无需额外处理。
3、业务表中必须包含单列主键,若存在复合主键,请参考问题 13 。
4、每个业务库中必须包含 undo_log 表,若与分库分表组件联用,分库不分表。
5、跨微服务链路的事务需要对相应 RPC 框架支持,目前 seata-all 中已经支持:Apache Dubbo、Alibaba Dubbo、sofa-RPC、Motan、gRpc、httpClient,对于 Spring Cloud 的支持,请大家引用 spring-cloud-alibaba-seata。其他自研框架、异步模型、消息消费事务模型请结合 API 自行支持。
6、目前AT模式支持的数据库有:MySQL、Oracle、PostgreSQL和 TiDB。
7、使用注解开启分布式事务时,若默认服务 provider 端加入 consumer 端的事务,provider 可不标注注解。但是,provider 同样需要相应的依赖和配置,仅可省略注解。
8、使用注解开启分布式事务时,若要求事务回滚,必须将异常抛出到事务的发起方,被事务发起方的 @GlobalTransactional 注解感知到。provide 直接抛出异常 或 定义错误码由 consumer 判断再抛出异常。
9、使用seata-all默认使用file.conf和registry.conf文件配置,使用seata-spring-boot-starter则默认使用yml或properties文件配置。
1.3 框架支持情况
Seata 目前提供了对主流的微服务框架的支持:
* Dubbo
通过 seata-dubbo 集成
* SOFA-RPC
通过 seata-sofa-rpc 集成
* Motan
通过 seata-motan 集成
* gRPC
通过 seata-grpc 集成
* Apache HttpClient
通过 seata-http 集成
* Spring Cloud OpenFeign
通过 spring-cloud-starter-alibaba-seata 的 feign 模块
* Spring RestTemplate
通过 spring-cloud-starter-alibaba-seata 的 rest 模块
同时方便我们集成到 Java 项目当中,Seata 也提供了相应的 Starter 库:
* seata-spring-boot-starter
* spring-cloud-starter-alibaba-seata
因为 Seata 是基于 DataSource 数据源进行代理来拓展,所以天然对主流的 ORM 框架提供了非常好的支持:
* MyBatis、MyBatis-Plus
* JPA、Hibernate
一定要根据使用的不同微服务框架应用不同的包,不然可能存在不可预知问题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值