尽管世界和人生是坏透了,其中却有一件东西永远是好,那便是青春——显克维奇
首先是下载seata1.4.1
然后解压
先修改conf
下的registry.conf
把type
改为nacos
进入bin
打开控制台运行seata-server.bat
然后在项目中引入依赖,记得需要分布式式事务的服务都要配置
1 2 3 4 5 |
<!-- seata 分布式事务 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> </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 30 31 32 33 34 35 |
package com.ruben.config; import com.alibaba.druid.pool.DruidDataSource; import com.zaxxer.hikari.HikariDataSource; import io.seata.rm.datasource.DataSourceProxy; import org.apache.commons.lang3.StringUtils; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.annotation.Resource; import javax.sql.DataSource; import java.util.Optional; /** * @ClassName: SeataConfig * @Description: 我还没有写描述 * @Date: 2021/3/14 0014 16:53 * * * @author: <achao1441470436@gmail.com> * @version: 1.0 * @since: JDK 1.8 */ @Configuration publicclassSeataConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource druidDataSource(){ returnnewDruidDataSource(); } } |
然后是项目中的配置文件
1 2 3 4 5 6 7 8 9 10 |
seata: enabled:true application-id:${spring.application.name} tx-service-group:ruben config: type:file file: name:file.conf service: disable-global-transaction:false |
如果之后启动一直报没配置disableGlobalTransaction
就需要新建一个file.conf
到resources
目录下
内容为
1 2 3 |
service{ disableGlobalTransaction = false } |
接下来是编写两个接口
首先是调用方
controller
1 2 3 4 5 6 7 8 9 10 11 |
@RestController @RequestMapping("user") publicclassUserController { @Resource private UserService userService; @GetMapping("order") public AjaxJson order() { return userService.order(); } } |
service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@Slf4j @Service publicclassUserServiceImplimplementsUserService { @Resource private MpOrderMapper mpOrderMapper; @Resource private ConsumerService consumerService; @Override @Transactional @GlobalTransactional public AjaxJson order() { consumerService.dropWare(); mpOrderMapper.insert(OrderPO.builder().id(1L).build()); return AjaxJson.success(); } } |
ConsumerService
是使用feign
远程调用另一个接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package com.ruben.feign; import com.ruben.pojo.dto.PageDTO; import com.ruben.utils.AjaxJson; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestBody; @FeignClient("ruben-consumer") publicinterfaceConsumerService { @GetMapping("ware") AjaxJson dropWare(); } |
MpOrderMapper
是mybatis-plus
调用数据库的方法
1 2 3 4 5 6 7 8 9 |
package com.ruben.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruben.pojo.po.OrderPO; import org.apache.ibatis.annotations.Mapper; @Mapper publicinterfaceMpOrderMapperextendsBaseMapper<OrderPO> { } |
然后是调用的ruben-consumer
首先也是引入依赖
其次是配置
1 2 3 4 5 6 7 8 9 10 |
seata: enabled: true application-id: ${spring.application.name} tx-service-group: SEATA_GROUP config: type: file file: name: file.conf service: disable-global-transaction: false |
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 |
package com.ruben.rubenproducerdemo.config; import com.alibaba.druid.pool.DruidDataSource; import com.zaxxer.hikari.HikariDataSource; import io.seata.rm.datasource.DataSourceProxy; import org.apache.commons.lang3.StringUtils; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.annotation.Resource; import javax.sql.DataSource; import java.util.Optional; /** * @ClassName: SeataConfig * @Description: 我还没有写描述 * @Date: 2021/3/14 0014 16:53 * * * @author: <achao1441470436@gmail.com> * @version: 1.0 * @since: JDK 1.8 */ @Configuration publicclassSeataConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource druidDataSource(){ returnnewDruidDataSource(); } } |
然后是接口
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 |
package com.ruben.rubenproducerdemo.controller; import com.ruben.rubenproducerdemo.service.WareService; import com.ruben.rubenproducerdemo.utils.AjaxJson; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @ClassName: WareController * @Description: 我还没有写描述 * @Date: 2021/3/13 0013 22:10 * * * @author: <achao1441470436@gmail.com> * @version: 1.0 * @since: JDK 1.8 */ @RestController @RequestMapping("ware") publicclassWareController { @Resource private WareService wareService; @GetMapping public AjaxJson dropWare() { return wareService.dropWare(); } } |
service
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 |
package com.ruben.rubenproducerdemo.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruben.dao.WareMapper; import com.ruben.rubenproducerdemo.pojo.po.WarePO; import com.ruben.rubenproducerdemo.service.WareService; import com.ruben.rubenproducerdemo.utils.AjaxJson; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Optional; /** * @ClassName: WareServiceImpl * @Description: 我还没有写描述 * @Date: 2021/3/13 0013 22:14 * * * @author: <achao1441470436@gmail.com> * @version: 1.0 * @since: JDK 1.8 */ @Service publicclassWareServiceImplextendsServiceImpl<WareMapper, WarePO> implementsWareService { @Override @Transactional public AjaxJson dropWare() { WarePOware=this.getById("1"); Optional.ofNullable(ware).map(WarePO::getWare).filter(w -> w <= 0).ifPresent(wi -> { thrownewRuntimeException("卖光啦!"); }); Optional.ofNullable(ware).ifPresent(w -> this.updateById(WarePO.builder().id("1").ware(w.getWare() - 1).build())); return AjaxJson.success("成功"); } } |
我们开始测试
往数据库放条数据
首次调用接口时可以看到订单生成并且库存成功扣减
第二次调用发现抛出异常并成功回滚库存服务
至此,成功使用了seata
实现了分布式事务