发布于2021-05-29 22:29 阅读(654) 评论(0) 点赞(8) 收藏(3)
目录
(1)备份配置文件file.conf,registry.conf,并修改
单体应用被拆分成微服务应用,原本三个模块被拆分成三个独立的应用,分别使用三个独立的数据源。
业务操作需要调用3个服务来完成,此时每个服务内部的数据一致性由本地保证,但是全局的数据一致性没法保证。
Seata是一款开源的分布式解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。
官网:http://seata.io/zh-cn/
维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚
控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议
控制分支事务,负责分支注册、状态汇报,并接受事务协调器的指令,驱动分支(本地)事务的提交和回滚
(1)TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID
(2)XID在微服务调用链路的上下文中传播
(3)RM向TC注册分支事务,将其纳入XID对应全局事务的管辖
(4)TM向TC发起针对XID的全局提交或回滚决议
(5)TC调度XID下管辖的全部分支事务完成提交或回滚请求
整个项目可以在码云上down:https://gitee.com/cxy-xupeng/spring-cloud.git
下载地址:http://seata.io/zh-cn/blog/download.html
我下载的是0.9版本的,新版本的没走通。。。
安装好后找到file.conf配置文件,做一个备份先(养成好习惯):
修改file.conf:
注意,驱动的话,mysql5保持原来的不变,mysql8需要加一个cj:
registry.conf:
建表语句在sb_store.sql里有:
因为是分布式服务,所以我们三个微服务会调用三个数据库,我们需要先来新建一下业务数据库:
再来建立对应的表:
订单库:
- CREATE TABLE `t_order` (
- `id` bigint NOT NULL AUTO_INCREMENT,
- `user_id` bigint DEFAULT NULL COMMENT '用户id',
- `product_id` bigint DEFAULT NULL COMMENT '产品id',
- `count` int DEFAULT NULL COMMENT '数量',
- `money` decimal(11,0) DEFAULT NULL COMMENT '金额',
- `status` int DEFAULT NULL COMMENT '订单状态,0:创建中,1:已完结',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
仓储库:
- CREATE TABLE `t_storage` (
- `id` bigint NOT NULL AUTO_INCREMENT,
- `product_id` bigint DEFAULT NULL COMMENT '产品id',
- `total` int DEFAULT NULL COMMENT '总库存',
- `used` int DEFAULT NULL COMMENT '已用库存',
- `residue` int DEFAULT NULL COMMENT '剩余库存',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
账号库:
- CREATE TABLE `t_account` (
- `id` bigint NOT NULL AUTO_INCREMENT,
- `user_id` bigint DEFAULT NULL COMMENT '用户id',
- `total` decimal(10,0) DEFAULT NULL COMMENT '总额度',
- `used` decimal(10,0) DEFAULT NULL COMMENT '已用额度',
- `residue` decimal(10,0) DEFAULT NULL COMMENT '剩余额度',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
新建的三个库,每个库都需要回滚日志的表,该表我们也有:
执行好后,查看一下我们的库以及对应的表:
双击批处理文件:
如果你是mysql5,应该可以直接启动成功。
如果你是mysql8,会报错的,我们还需要修改一些东西:
来到lib目录下,找到mysql-connector-java的jar包,它自带的是5.X的,我们用8.X的替换
、
然后重新双击seata-server.bat即可:
seata启动成功:
注:如果你有闪退的情况,创建一个logs目录
先来看一下目录结构:
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>cloud</artifactId>
- <groupId>com.xupeng.springcloud</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>seata-order-service2001</artifactId>
-
- <dependencies>
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
- <exclusions>
- <exclusion>
- <artifactId>seata-all</artifactId>
- <groupId>io.seata</groupId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>io.seata</groupId>
- <artifactId>seata-all</artifactId>
- <version>0.9.0</version>
- </dependency>
- <!--feign-->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-openfeign</artifactId>
- </dependency>
- <!--alibaba nacos-->
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
- </dependency>
- <dependency>
- <groupId>com.xupeng.springcloud</groupId>
- <artifactId>cloud-api-commons</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>8.0.22</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-actuator</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-devtools</artifactId>
- <scope>runtime</scope>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>2.0.1</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis</artifactId>
- <version>3.4.6</version>
- </dependency>
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis-spring</artifactId>
- <version>1.3.2</version>
- </dependency>
- </dependencies>
- </project>
如果你是mysql5的话,驱动需要改一下。
注意:tx-service-group属性对应的值就是我们seata中file.conf里面配置的,要保持对应
- server:
- port: 2001
-
- spring:
- application:
- name: seata-order-service
- cloud:
- alibaba:
- seata:
- tx-service-group: xupeng_tx_group
- nacos:
- discovery:
- server-addr: localhost:8848
- datasource:
- driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://localhost:3306/seata_order?serverTimezone=UTC
- username: root
- password: xp880000
-
- feign:
- hystrix:
- enabled: false
-
- logging:
- level:
- io:
- seata: info
-
- mybatis:
- mapperLocations: classpath:mapper/*.xml
我们把seata中的file.conf复制过来,此处需要修改一个地方:
标记的xupeng_tx_group,要和application.yml以及seata中的file.conf保持一致(这个值就是我们自定义的)
- registry {
- # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
- type = "nacos"
-
- nacos {
- serverAddr = "localhost:8848"
- namespace = ""
- cluster = "default"
- }
- eureka {
- serviceUrl = "http://localhost:8761/eureka"
- application = "default"
- weight = "1"
- }
- redis {
- serverAddr = "localhost:6379"
- db = "0"
- }
- zk {
- cluster = "default"
- serverAddr = "127.0.0.1:2181"
- session.timeout = 6000
- connect.timeout = 2000
- }
- 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
- type = "file"
-
- nacos {
- serverAddr = "localhost:8848"
- namespace = ""
- }
- consul {
- serverAddr = "127.0.0.1:8500"
- }
- apollo {
- app.id = "seata-server"
- apollo.meta = "http://192.168.1.204:8801"
- }
- zk {
- serverAddr = "127.0.0.1:2181"
- session.timeout = 6000
- connect.timeout = 2000
- }
- etcd3 {
- serverAddr = "http://localhost:2379"
- }
- file {
- name = "file.conf"
- }
- }
- @EnableDiscoveryClient
- @EnableFeignClients
- @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//取消数据源自动配置
- public class SeataOrderMain2001 {
- public static void main(String[] args) {
- SpringApplication.run(SeataOrderMain2001.class, args);
- }
- }
Order:
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class Order {
- private Long id;
- private Long userId;
- private Long productId;
- private Integer count;
- private BigDecimal money;
- //订单状态:0-创建中,1-已完结
- private Integer status;
- }
CommonResult:
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class CommonResult<T> {
- private Integer code;
- private String message;
- private T data;
-
- public CommonResult(Integer code,String message){
- this(code,message,null);
- }
-
- }
OrderDao:
- @Mapper
- public interface OrderDao {
- //新建订单
- void create(Order order);
-
- //修改订单状态
- void update(@Param("userId") Long userId, @Param("status") Integer status);
- }
OrderMapper.xml:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="com.xupeng.springcloud.dao.OrderDao">
- <resultMap id="BaseResultMap" type="com.xupeng.springcloud.domain.Order">
- <id column="id" property="id" jdbcType="BIGINT"></id>
- <result column="user_id" property="userId" jdbcType="BIGINT"></result>
- <result column="product_id" property="productId" jdbcType="BIGINT"></result>
- <result column="count" property="count" jdbcType="INTEGER"></result>
- <result column="money" property="money" jdbcType="DECIMAL"></result>
- <result column="status" property="status" jdbcType="INTEGER"></result>
- </resultMap>
-
- <insert id="create">
- insert into t_order (id,user_id,product_id,count,money,status) values
- (null,#{user_id},#{product_id},#{count},#{money},0);
- </insert>
-
- <update id="update">
- update t_order set status = 1 where user_id=#{user_id} and status = #{status};
- </update>
- </mapper>
AccountService:
- @FeignClient(value = "seata-account-service")
- public interface AccountService {
- @PostMapping(value = "/account/decrease")
- CommonResult decrease(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money);
- }
OrderService:
- public interface OrderService {
- void create(Order order);
- }
StorageService:
- @FeignClient(value = "seata-storage-service")
- public interface StorageService {
- @PostMapping(value = "/storage/decrease")
- CommonResult decrease(@RequestParam("productId") Long productId, @RequestParam("count") Integer count);
- }
OrderServiceImpl:
- @Service
- @Slf4j
- public class OrderServiceImpl implements OrderService {
- @Resource
- private OrderDao orderDao;
- @Resource
- private AccountService accountService;
- @Resource
- private StorageService storageService;
-
- @Override
- @GlobalTransactional(name = "xupeng-create-order",rollbackFor = Exception.class)
- public void create(Order order) {
- log.info("---------开始新建订单");
- orderDao.create(order);
-
- log.info("---------订单微服务调用库存,做减法");
- storageService.decrease(order.getProductId(),order.getCount());
- log.info("---------订单微服务调用库存,做减法结束");
-
- log.info("---------订单微服务调用账户,做扣减");
- accountService.decrease(order.getUserId(),order.getMoney());
- log.info("---------订单微服务调用账户,做扣减结束");
-
- log.info("---------修改订单状态开始");
- orderDao.update(order.getUserId(),0);
- log.info("---------修改订单状态结束");
-
- log.info("---------开始新建订单结束");
- }
- }
OrderController:
- @RestController
- public class OrderController {
- @Resource
- private OrderService orderService;
-
- @GetMapping("/order/create")
- public CommonResult create(Order order) {
- orderService.create(order);
- return new CommonResult(200, "订单创建成功");
- }
- }
MyBatisConfig:
- @Configuration
- @MapperScan({"com.xupeng.springcloud.dao"})
- public class MyBatisConfig {
- }
DataSourceProxyConfig:
- @Configuration
- public class DataSourceProxyConfig {
- @Value("${mybatis.mapperLocations}")
- private String mapperLocations;
-
- @Bean
- @ConfigurationProperties(prefix = "spring.datasource")
- public DataSource druidDataSource() {
- return new DruidDataSource();
- }
-
- @Bean
- public DataSourceProxy dataSourceProxy(DataSource dataSource) {
- return new DataSourceProxy(dataSource);
- }
-
- @Bean
- public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception {
- SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
- sqlSessionFactoryBean.setDataSource(dataSourceProxy);
- sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
- sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
- return sqlSessionFactoryBean.getObject();
- }
- }
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>cloud</artifactId>
- <groupId>com.xupeng.springcloud</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>seata-storage-service2002</artifactId>
-
- <dependencies>
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
- <exclusions>
- <exclusion>
- <artifactId>seata-all</artifactId>
- <groupId>io.seata</groupId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>io.seata</groupId>
- <artifactId>seata-all</artifactId>
- <version>0.9.0</version>
- </dependency>
- <!--feign-->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-openfeign</artifactId>
- </dependency>
- <!--alibaba nacos-->
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
- </dependency>
- <dependency>
- <groupId>com.xupeng.springcloud</groupId>
- <artifactId>cloud-api-commons</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>8.0.22</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-actuator</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-devtools</artifactId>
- <scope>runtime</scope>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>2.0.1</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis</artifactId>
- <version>3.4.6</version>
- </dependency>
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis-spring</artifactId>
- <version>1.3.2</version>
- </dependency>
- </dependencies>
-
- </project>
- server:
- port: 2002
-
- spring:
- application:
- name: seata-storage-service
- cloud:
- alibaba:
- seata:
- tx-service-group: xupeng_tx_group
- nacos:
- discovery:
- server-addr: localhost:8848
- datasource:
- driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://localhost:3306/seata_storage?serverTimezone=UTC
- username: root
- password: xp880000
-
- feign:
- hystrix:
- enabled: false
-
- logging:
- level:
- io:
- seata: info
-
- mybatis:
- mapperLocations: classpath:mapper/*.xml
同订单模块
SeataStorageServiceApplication2002:
- @EnableDiscoveryClient
- @EnableFeignClients
- @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//取消数据源自动配置
- public class SeataStorageServiceApplication2002 {
- public static void main(String[] args) {
- SpringApplication.run(SeataStorageServiceApplication2002.class, args);
- }
- }
CommonResult:
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class CommonResult<T> {
- private Integer code;
- private String message;
- private T data;
-
- public CommonResult(Integer code,String message){
- this(code,message,null);
- }
-
- }
Storage:
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class Storage {
- private Long id;
- private Long productId;
- private Integer total;
- private Integer used;
- private Integer residue;
- }
StorageDao:
- @Mapper
- public interface StorageDao {
- void decrease(@Param("productId") Long productId,@Param("count") Integer count);
- }
StorageMapper.xml:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="com.xupeng.springcloud.dao.StorageDao">
-
- <resultMap id="BaseResultMap" type="com.xupeng.springcloud.domain.Storage">
- <id column="id" property="id" jdbcType="BIGINT"></id>
- <result column="product_id" property="productId" jdbcType="BIGINT"></result>
- <result column="total" property="total" jdbcType="INTEGER"></result>
- <result column="used" property="used" jdbcType="INTEGER"></result>
- <result column="residue" property="residue" jdbcType="INTEGER"></result>
- </resultMap>
-
- <update id="decrease">
- update t_storage set used = used + #{count},residue = residue - #{count} where product_id = #{productId}
- </update>
- </mapper>
StorageService:
- public interface StorageService {
- void decrease(Long productId, Integer count);
- }
StorageServiceImpl:
- @Service
- public class StorageServiceImpl implements StorageService {
- private static final Logger LOGGER = LoggerFactory.getLogger(StorageServiceImpl.class);
-
- @Resource
- private StorageDao storageDao;
-
- /**
- * 扣减库存
- * @param productId
- * @param count
- */
- @Override
- public void decrease(Long productId, Integer count) {
- LOGGER.info("---------开始扣减库存");
- storageDao.decrease(productId,count);
- LOGGER.info("---------扣减库存结束");
- }
- }
StorageController:
- @RestController
- public class StorageController {
- @Autowired
- private StorageService storageService;
-
- /**
- * 扣减库存
- */
- @RequestMapping("/storage/decrease")
- public CommonResult decrease(@RequestParam("productId") Long productId, @RequestParam("count")Integer count){
- storageService.decrease(productId, count);
- return new CommonResult(200,"扣减库存成功");
- }
- }
MyBatisConfig和DataSourceProxyConfig同订单模块
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>cloud</artifactId>
- <groupId>com.xupeng.springcloud</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>seata-account-service2003</artifactId>
-
- <dependencies>
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
- <exclusions>
- <exclusion>
- <artifactId>seata-all</artifactId>
- <groupId>io.seata</groupId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>io.seata</groupId>
- <artifactId>seata-all</artifactId>
- <version>0.9.0</version>
- </dependency>
- <!--feign-->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-openfeign</artifactId>
- </dependency>
- <!--alibaba nacos-->
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
- </dependency>
- <dependency>
- <groupId>com.xupeng.springcloud</groupId>
- <artifactId>cloud-api-commons</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>8.0.22</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-actuator</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-devtools</artifactId>
- <scope>runtime</scope>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>2.0.1</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis</artifactId>
- <version>3.4.6</version>
- </dependency>
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis-spring</artifactId>
- <version>1.3.2</version>
- </dependency>
- </dependencies>
- </project>
需要修改一下数据库名
- server:
- port: 2003
-
- spring:
- application:
- name: seata-account-service
- cloud:
- alibaba:
- seata:
- tx-service-group: xupeng_tx_group
- nacos:
- discovery:
- server-addr: localhost:8848
- datasource:
- driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://localhost:3306/seata_account?serverTimezone=UTC
- username: root
- password: xp880000
-
- feign:
- hystrix:
- enabled: false
-
- logging:
- level:
- io:
- seata: info
-
- mybatis:
- mapperLocations: classpath:mapper/*.xml
同订单模块
Account:
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class Account {
- private Long id;
- private Long userId;
- private BigDecimal total;
- private BigDecimal used;
- private BigDecimal residue;
- }
CommonResult:
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class CommonResult<T> {
- private Integer code;
- private String message;
- private T data;
-
- public CommonResult(Integer code,String message){
- this(code,message,null);
- }
-
- }
AccountDao:
- @Mapper
- public interface AccountDao {
- /**
- * 扣减账户余额
- */
- void decrease(@Param("userId") Long userId, @Param("money") BigDecimal money);
- }
AccountMapper.xml:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="com.xupeng.springcloud.dao.AccountDao">
-
- <resultMap id="BaseResultMap" type="com.xupeng.springcloud.domain.Account">
- <id column="id" property="id" jdbcType="BIGINT"></id>
- <result column="user_id" property="userId" jdbcType="BIGINT"></result>
- <result column="total" property="total" jdbcType="DECIMAL"></result>
- <result column="used" property="used" jdbcType="DECIMAL"></result>
- <result column="residue" property="residue" jdbcType="DECIMAL"></result>
- </resultMap>
-
- <update id="decrease">
- update t_account set residue = residue - #{money},used = used + #{money} where user_id = #{userId}
- </update>
- </mapper>
AccountService:
- public interface AccountService {
- void decrease(Long userId, BigDecimal money);
- }
AccountServiceImpl:
- @Service
- public class AccountServiceImpl implements AccountService {
- private static final Logger LOGGER = LoggerFactory.getLogger(AccountServiceImpl.class);
-
- @Resource
- private AccountDao accountDao;
-
- /**
- * 扣减账户余额
- */
- @Override
- public void decrease(Long userId, BigDecimal money) {
- LOGGER.info("---------开始扣减账户余额");
- // try {
- // TimeUnit.SECONDS.sleep(20);
- // } catch (InterruptedException e) {
- // e.printStackTrace();
- // }
- accountDao.decrease(userId, money);
- LOGGER.info("---------扣减库存账户余额");
- }
- }
- @RestController
- public class AccountController {
- @Autowired
- private AccountService accountService;
-
- /**
- * 扣减账户余额
- */
- @RequestMapping("/account/decrease")
- public CommonResult decrease(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money) {
- accountService.decrease(userId, money);
- return new CommonResult(200, "扣减账户余额成功");
- }
- }
DataSourceProxyConfig和MyBatisConfig同上
SeataAccountServiceApplication2003:
- @EnableDiscoveryClient
- @EnableFeignClients
- @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//取消数据源自动配置
- public class SeataAccountServiceApplication2003 {
- public static void main(String[] args) {
- SpringApplication.run(SeataAccountServiceApplication2003.class, args);
- }
- }
这里的关键是:@GlobalTransactional
@GlobalTransactional注解,开启了全局事务,如果有哪一个模块出错,就会全部回滚
TC相当于seata服务器,TM就是我们@GlobalTransactional注解的地方,RM就是那三个模块
在第一阶段,seata会拦截“业务sql”,
*1)解析sql语义,找到业务sql要更新的业务数据,在业务数据被新更新之前,将其保存成“before image”
*2)执行业务sql,更新业务数据
*3)在业务数据更新后,将其保存成“after image”,最后生成行锁
以上操作都是在一个数据库事务内发生,保证了一阶段操作的原子性
第二阶段,如果“before image”和“after image”都正常,可以直接提交。
第二阶段,如果需要回滚:
seata需要回滚一阶段已经执行的业务sql,还原业务数据(即将第一阶段第二步的数据还原)
回滚方式是用“before image”还原业务数据,但在还原数据前首先要校验脏写,对比“数据库当前业务数据”和“after image”,如果两份数据完全一致,表示没有脏写,可以还原。如果不一致,代表有脏写,需要人工处理。
如果本篇博客对您有所帮助,打赏一点呗,谢谢了呢~
原文链接:https://blog.csdn.net/qq_40594696/article/details/117228564
作者:小光头吃饭不用愁
链接:http://www.javaheidong.com/blog/article/207907/3d18d9112d3e0ceddad7/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!