0%

Seata使用

Seata使用

使用seata进行分布式事务非常的简单,只是依赖于一个seata server服务,首先将服务启动,然后对微服务进行配置

依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- seata 依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 排除掉原本的依赖,选择和使用的seata server版本相同的 -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>1.1.0</version>
</dependency>

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件
type-aliases-package: com.zhanghe.study.springcloudalibaba.model #Entity所在包
mapper-locations:
- classpath:mybatis/mapper/**/*.xml #mapper文件

spring:
application:
name: springcloudalibaba-seata-order
cloud:
sentinel:
transport:
dashboard: localhost:8080 #sentinel dashboard 地址
port: 8719 #默认是8719,如果被占用,则会自动从8719开始依次+1扫描,直至找到未被占用的端口
alibaba:
seata:
tx-service-group: my_test_tx_group # 事务组名称,要与seata server中file.conf中配置的service中vgroupMapping一致
nacos:
discovery:
server-addr: localhost:8848
datasource:
druid:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/seata_order
driver-class-name: com.mysql.jdbc.Driver
feign:
sentinel:
enabled: true

将seata server中配置好的file.conf和registry.conf也要拷贝到项目的资源路径下

启动类

启动类要排除掉DataSourceAutoConfiguration,因为需要修改数据源,不使用默认的配置

1
2
3
4
5
6
7
8
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 
@EnableDiscoveryClient
@EnableFeignClients
public class OrderApp {
public static void main(String[] args) {
SpringApplication.run(OrderApp.class,args);
}
}

数据源配置

这里要使用Seata的数据源进行代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 使用seata数据源进行代理
@Configuration
@EnableConfigurationProperties({MybatisProperties.class})
public class DataSourceConfiguration {


@Bean
@ConfigurationProperties(prefix = "spring.datasource.druid")
public DataSource dataSource() {
return new DruidDataSource();
}

@Bean
public DataSourceProxy dataSourceProxy(DataSource dataSource) {
return new DataSourceProxy(dataSource);
}

@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSourceProxy dataSourceProxy,
MybatisProperties mybatisProperties) {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSourceProxy);

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
Resource[] mapperLocaltions = resolver.getResources(mybatisProperties.getMapperLocations()[0]);
bean.setMapperLocations(mapperLocaltions);

if (StringUtils.isNotBlank(mybatisProperties.getConfigLocation())) {
Resource[] resources = resolver.getResources(mybatisProperties.getConfigLocation());
bean.setConfigLocation(resources[0]);
}
} catch (IOException e) {
e.printStackTrace();
}
return bean;
}
}

在业务方法上使用@GlobalTransactional注解进行标注全局事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@GlobalTransactional(name = "create-order",rollbackFor = Exception.class)
public void create(Order order){
System.out.println("创建订单");
orderDao.addOrder(order);

System.out.println("扣减库存");
storageClient.decrease(order.getProductId(),order.getCount());

System.out.println("账户余额扣减");
accountClient.decrease(order.getUserId(),order.getMoney());

System.out.println("订单状态修改");
orderDao.updateStatus(order.getId(),order.getStatus());
}