铿然架构 | 作者 / 铿然一叶 这是 铿然架构 的第 109 篇原创文章
1. 安装Server
1.下载软件 github.com/seata/seata...
2.本地目录解压 D:\MyApp\seata\seataserver1.7.1
3.启动server seata-server.bat
注意:配置文件在D:\MyApp\seata\seataserver1.7.1\conf\application.yml,默认使用文件方式,不需要修改
2. 运行Demo
2.1 克隆代码到本地
demo架构图:
2.2 打开Seata-xa的例子
注:XA和AT模式的demo是同一个,只需要修改下使用的数据库代理类。
2.3 创建数据库和用户
该例子只使用一个数据库。
sql
CREATE DATABASE businessdb;
create user business@'%' IDENTIFIED BY 'business123';
GRANT ALL PRIVILEGES ON businessdb.* TO business@'%';
2.4 创建表
执行业务脚本:
AT模式undo log脚本:
r
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,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
2.5 修改数据库配置
修改每个module的数据库配置
2.6 修改代码使用AT模式
修改module下的xxxxxDataSourceConfiguration文件
2.7 启动各个module
注:每次启动bussiness-xa module都会初始化数据库里的数据。
3. 测试
发送HTTP请求:
http://127.0.0.1:8084/purchase?rollback=false&count=1
通过浏览器,curl命令,postman都可以。
参数说明:
参数 | 说明 |
---|---|
rollback | 是否回退,如果回退,代码中抛出异常触发回退操作 |
count | 订单数量,扣减库存,如果不传入,默认每次是30 |
初始化库存总量为:100,账户余额为:1000。
3.1 测试场景
3.1.1 正常测试
订购数量小于库存,账户余额足够:
http://127.0.0.1:8084/purchase?rollback=false&count=1
3.1.2 账户余额不足
订购数量大于库存,所需购买金额大于账户余额:
http://127.0.0.1:8084/purchase?rollback=false&count=10000
3.1.3 手动触发回退
设置rollback为true:
http://127.0.0.1:8084/purchase?rollback=true&count=1
3.2 AT模式支持
1.添加maven依赖:
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-seata</artifactId>
<version>2.0.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>${seata.version}</version>
</dependency>
2.业务入口增加GlobalTransactional注解
注:GlobalTransactional可加在类上或者方法上
typescript
// BusinessService.java
@GlobalTransactional
public void purchase(String userId, String commodityCode, int orderCount, boolean rollback) {
String xid = RootContext.getXID();
LOGGER.info("New Transaction Begins: " + xid);
String result = stockFeignClient.deduct(commodityCode, orderCount);
if (!SUCCESS.equals(result)) {
throw new RuntimeException("库存服务调用失败,事务回滚!");
}
result = orderFeignClient.create(userId, commodityCode, orderCount);
if (!SUCCESS.equals(result)) {
throw new RuntimeException("订单服务调用失败,事务回滚!");
}
if (rollback) {
throw new RuntimeException("Force rollback ... ");
}
}
3.使用DataSourceProxy
kotlin
package io.seata.sample;
import javax.sql.DataSource;
import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
@Configuration
public class BusinessXADataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource dataSource() {
return new DruidDataSource();
}
@Bean("dataSourceProxy")
public DataSource dataSource(DruidDataSource druidDataSource) {
// DataSourceProxy for AT mode
return new DataSourceProxy(druidDataSource);
// DataSourceProxyXA for XA mode
// return new DataSourceProxyXA(druidDataSource);
}
@Bean("jdbcTemplate")
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
其他阅读:
萌新快速成长之路
如何编写软件设计文档
JAVA编程思想(一)通过依赖注入增加扩展性
JAVA编程思想(二)如何面向接口编程
JAVA编程思想(三)去掉别扭的if,自注册策略模式优雅满足开闭原则
JAVA编程思想(四)Builder模式经典范式以及和工厂模式如何选?
Java编程思想(七)使用组合和继承的场景
JAVA基础(一)简单、透彻理解内部类和静态内部类
JAVA基础(二)内存优化-使用Java引用做缓存
JAVA基础(三)ClassLoader实现热加载
JAVA基础(四)枚举(enum)和常量定义,工厂类使用对比
JAVA基础(五)函数式接口-复用,解耦之利刃