当前位置: 首页 > news >正文

Seata分布式事物案例及详解

spring cloud alibaba Seata分布式事物 详解

安装seata

官网: https://seata.apache.org/zh-cn/download/seata-server
下载后直接解压 进到bin目录 输入cmd
启动命令:seata-server.bat
进入localhost:7091 默认账户跟密码都为seata

seate分布式事务案例

在这里插入图片描述

  1. 创建数据库
CREATE DATABASE IF NOT EXISTS `storage_db`;
USE `storage_db`;
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;
INSERT INTO storage_tbl (commodity_code, count) VALUES ('P0001', 100);
INSERT INTO storage_tbl (commodity_code, count) VALUES ('B1234', 10);
DROP TABLE IF EXISTS `undo_log`;
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,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE DATABASE IF NOT EXISTS `order_db`;
USE `order_db`;
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 `undo_log`;
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,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE DATABASE IF NOT EXISTS `account_db`;
USE `account_db`;
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;
INSERT INTO account_tbl (user_id, money) VALUES ('1', 10000);
DROP TABLE IF EXISTS `undo_log`;
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,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  1. 导入依赖
 <dependencies><dependency><groupId>com.nie</groupId><artifactId>model</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId><version>2023.0.3.2</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>annotationProcessor</scope></dependency></dependencies>
  1. 创建四个微服务项目

seata-account

启动类

package com.nie.account;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.transaction.annotation.EnableTransactionManagement;@EnableTransactionManagement
@MapperScan("com.nie.account.mapper")
@EnableDiscoveryClient
@SpringBootApplication
public class SeataAccountMainApplication {public static void main(String[] args) {SpringApplication.run(SeataAccountMainApplication.class, args);}
}

实体类

package com.nie.account.bean;import lombok.Data;import java.io.Serializable;/*** * @TableName account_tbl*/
@Data
public class AccountTbl implements Serializable {private Integer id;private String userId;private Integer money;}

控制层

package com.nie.account.controller;import com.nie.account.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class AccountRestController {@AutowiredAccountService accountService;/*** 扣减账户余额* @return*/@GetMapping("/debit")public String debit(@RequestParam("userId") String userId,@RequestParam("money") int money){accountService.debit(userId, money);return "account debit success";}
}

持久层

package com.nie.account.mapper;import com.nie.account.bean.AccountTbl;public interface AccountTblMapper {int deleteByPrimaryKey(Long id);int insert(AccountTbl record);int insertSelective(AccountTbl record);AccountTbl selectByPrimaryKey(Long id);int updateByPrimaryKeySelective(AccountTbl record);int updateByPrimaryKey(AccountTbl record);void debit(String userId, int money);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nie.account.mapper.AccountTblMapper"><resultMap id="BaseResultMap" type="com.nie.account.bean.AccountTbl"><id property="id" column="id" jdbcType="INTEGER"/><result property="userId" column="user_id" jdbcType="VARCHAR"/><result property="money" column="money" jdbcType="INTEGER"/></resultMap><sql id="Base_Column_List">id,user_id,money</sql><select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">select<include refid="Base_Column_List" />from account_tblwhere  id = #{id,jdbcType=INTEGER} </select><delete id="deleteByPrimaryKey" parameterType="java.lang.Long">delete from account_tblwhere  id = #{id,jdbcType=INTEGER} </delete><insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.nie.account.bean.AccountTbl" useGeneratedKeys="true">insert into account_tbl( id,user_id,money)values (#{id,jdbcType=INTEGER},#{userId,jdbcType=VARCHAR},#{money,jdbcType=INTEGER})</insert><insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.nie.account.bean.AccountTbl" useGeneratedKeys="true">insert into account_tbl<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null">id,</if><if test="userId != null">user_id,</if><if test="money != null">money,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null">#{id,jdbcType=INTEGER},</if><if test="userId != null">#{userId,jdbcType=VARCHAR},</if><if test="money != null">#{money,jdbcType=INTEGER},</if></trim></insert><update id="updateByPrimaryKeySelective" parameterType="com.nie.account.bean.AccountTbl">update account_tbl<set><if test="userId != null">user_id = #{userId,jdbcType=VARCHAR},</if><if test="money != null">money = #{money,jdbcType=INTEGER},</if></set>where   id = #{id,jdbcType=INTEGER} </update><update id="updateByPrimaryKey" parameterType="com.nie.account.bean.AccountTbl">update account_tblset user_id =  #{userId,jdbcType=VARCHAR},money =  #{money,jdbcType=INTEGER}where   id = #{id,jdbcType=INTEGER} </update><update id="debit">update account_tblset money = money - #{money,jdbcType=INTEGER}where user_id = #{userId,jdbcType=VARCHAR}</update>
</mapper>

业务层

package com.nie.account.service;public interface AccountService {/*** 从用户账户中扣减* @param userId  用户id* @param money   扣减金额*/void debit(String userId, int money);
}
package com.nie.account.service.impl;import com.nie.account.mapper.AccountTblMapper;
import com.nie.account.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class AccountServiceImpl implements AccountService {@AutowiredAccountTblMapper accountTblMapper;@Transactional  //本地事务@Overridepublic void debit(String userId, int money) {// 扣减账户余额accountTblMapper.debit(userId,money);}
}

配置application.yml

spring:application:name: seata-accountdatasource:url: jdbc:mysql://localhost:3306/account_db?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Drivercloud:nacos:server-addr: 127.0.0.1:8848config:import-check:enabled: false
server:port: 10010mybatis:mapper-locations: classpath:mapper/*.xml
#seata:
#  data-source-proxy-mode: XA

配置seata地址

 service {#transaction service group mappingvgroupMapping.default_tx_group = "default"#only support when registry.type=file, please don't set multiple addressesdefault.grouplist = "127.0.0.1:8091"#degrade, current not supportenableDegrade = false#disable seatadisableGlobalTransaction = false}

seata-business

启动类

package com.nie.business;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;@EnableFeignClients(basePackages = "com.nie.business.feign")
@EnableDiscoveryClient
@SpringBootApplication
public class SeataBusinessMainApplication {public static void main(String[] args) {SpringApplication.run(SeataBusinessMainApplication.class, args);}
}

控制层

package com.nie.business.controller;import com.nie.business.service.BusinessService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class PurchaseRestController {@AutowiredBusinessService businessService;/*** 购买* @param userId 用户ID* @param commodityCode 商品编码* @param orderCount 数量* @return*/@GetMapping("/purchase")public String purchase(@RequestParam("userId") String userId,@RequestParam("commodityCode") String commodityCode,@RequestParam("count") int orderCount){businessService.purchase(userId, commodityCode, orderCount);return "business purchase success";}
}

远程调用

package com.nie.business.feign;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;@FeignClient(value = "seata-order")
public interface OrderFeignClient {/*** 创建订单* @param userId* @param commodityCode* @param orderCount* @return*/@GetMapping("/create")String create(@RequestParam("userId") String userId,@RequestParam("commodityCode") String commodityCode,@RequestParam("count") int orderCount);
}
package com.nie.business.feign;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;@FeignClient(value = "seata-storage")
public interface StorageFeignClient {/*** 扣减库存* @param commodityCode* @param count* @return*/@GetMapping("/deduct")String deduct(@RequestParam("commodityCode") String commodityCode,@RequestParam("count") Integer count);
}

业务层

package com.nie.business.service;public interface BusinessService {/*** 采购* @param userId            用户id* @param commodityCode     商品编号* @param orderCount        购买数量*/void purchase(String userId, String commodityCode, int orderCount);
}
package com.nie.business.service.impl;import com.nie.business.feign.OrderFeignClient;
import com.nie.business.feign.StorageFeignClient;
import com.nie.business.service.BusinessService;
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class BusinessServiceImpl implements BusinessService {@AutowiredStorageFeignClient storageFeignClient;@AutowiredOrderFeignClient orderFeignClient;@GlobalTransactional@Overridepublic void purchase(String userId, String commodityCode, int orderCount) {//1. 扣减库存storageFeignClient.deduct(commodityCode, orderCount);//2. 创建订单orderFeignClient.create(userId, commodityCode, orderCount);}
}

配置application.yml

spring:application:name: seata-businesscloud:nacos:server-addr: 127.0.0.1:8848config:import-check:enabled: false
server:port: 11000

配置seata地址

 service {#transaction service group mappingvgroupMapping.default_tx_group = "default"#only support when registry.type=file, please don't set multiple addressesdefault.grouplist = "127.0.0.1:8091"#degrade, current not supportenableDegrade = false#disable seatadisableGlobalTransaction = false}

seata-order

启动类

package com.nie.order;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.transaction.annotation.EnableTransactionManagement;@EnableFeignClients(basePackages = "com.nie.order.feign")
@EnableTransactionManagement
@MapperScan("com.nie.order.mapper")
@EnableDiscoveryClient
@SpringBootApplication
public class SeataOrderMainApplication {public static void main(String[] args) {SpringApplication.run(SeataOrderMainApplication.class, args);}}

实体类

package com.nie.order.bean;import java.io.Serializable;
import lombok.Data;/*** @TableName order_tbl*/
@Data
public class OrderTbl implements Serializable {private Integer id;private String userId;private String commodityCode;private Integer count;private Integer money;private static final long serialVersionUID = 1L;
}

控制层

package com.nie.order.controller;import com.nie.order.bean.OrderTbl;
import com.nie.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class OrderRestController {@AutowiredOrderService orderService;/*** 创建订单* @param userId* @param commodityCode* @param orderCount* @return*/@GetMapping("/create")public String create(@RequestParam("userId") String userId,@RequestParam("commodityCode") String commodityCode,@RequestParam("count") int orderCount){OrderTbl tbl = orderService.create(userId, commodityCode, orderCount);return "order create success = 订单id:【"+tbl.getId()+"】";}}

业务层

package com.nie.order.service;import com.nie.order.bean.OrderTbl;public interface OrderService {/*** 创建订单* @param userId    用户id* @param commodityCode  商品编码* @param orderCount  商品数量*/OrderTbl create(String userId, String commodityCode, int orderCount);
}
package com.nie.order.service.impl;import com.nie.order.bean.OrderTbl;
import com.nie.order.feign.AccountFeignClient;
import com.nie.order.mapper.OrderTblMapper;
import com.nie.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class OrderServiceImpl implements OrderService {@AutowiredOrderTblMapper orderTblMapper;@AutowiredAccountFeignClient accountFeignClient;@Transactional@Overridepublic OrderTbl create(String userId, String commodityCode, int orderCount) {//1、计算订单价格int orderMoney = calculate(commodityCode, orderCount);//2、扣减账户余额accountFeignClient.debit(userId, orderMoney);//3、保存订单OrderTbl orderTbl = new OrderTbl();orderTbl.setUserId(userId);orderTbl.setCommodityCode(commodityCode);orderTbl.setCount(orderCount);orderTbl.setMoney(orderMoney);//3、保存订单orderTblMapper.insert(orderTbl);return orderTbl;}// 计算价格private int calculate(String commodityCode, int orderCount) {return 9*orderCount;}
}

持久层

package com.nie.order.mapper;import com.nie.order.bean.OrderTbl;/**
* @author lfy
* @description 针对表【order_tbl】的数据库操作Mapper
* @createDate 2025-01-08 18:34:18
* @Entity com.atguigu.order.bean.OrderTbl
*/
public interface OrderTblMapper {int deleteByPrimaryKey(Long id);int insert(OrderTbl record);int insertSelective(OrderTbl record);OrderTbl selectByPrimaryKey(Long id);int updateByPrimaryKeySelective(OrderTbl record);int updateByPrimaryKey(OrderTbl record);}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nie.order.mapper.OrderTblMapper"><resultMap id="BaseResultMap" type="com.nie.order.bean.OrderTbl"><id property="id" column="id" jdbcType="INTEGER"/><result property="userId" column="user_id" jdbcType="VARCHAR"/><result property="commodityCode" column="commodity_code" jdbcType="VARCHAR"/><result property="count" column="count" jdbcType="INTEGER"/><result property="money" column="money" jdbcType="INTEGER"/></resultMap><sql id="Base_Column_List">id,user_id,commodity_code,count,money</sql><select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">select<include refid="Base_Column_List" />from order_tblwhere  id = #{id,jdbcType=INTEGER} </select><delete id="deleteByPrimaryKey" parameterType="java.lang.Long">delete from order_tblwhere  id = #{id,jdbcType=INTEGER} </delete><insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.nie.order.bean.OrderTbl"useGeneratedKeys="true">insert into order_tbl( id,user_id,commodity_code,count,money)values (#{id,jdbcType=INTEGER},#{userId,jdbcType=VARCHAR},#{commodityCode,jdbcType=VARCHAR},#{count,jdbcType=INTEGER},#{money,jdbcType=INTEGER})</insert><insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.nie.order.bean.OrderTbl" useGeneratedKeys="true">insert into order_tbl<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null">id,</if><if test="userId != null">user_id,</if><if test="commodityCode != null">commodity_code,</if><if test="count != null">count,</if><if test="money != null">money,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null">#{id,jdbcType=INTEGER},</if><if test="userId != null">#{userId,jdbcType=VARCHAR},</if><if test="commodityCode != null">#{commodityCode,jdbcType=VARCHAR},</if><if test="count != null">#{count,jdbcType=INTEGER},</if><if test="money != null">#{money,jdbcType=INTEGER},</if></trim></insert><update id="updateByPrimaryKeySelective" parameterType="com.nie.order.bean.OrderTbl">update order_tbl<set><if test="userId != null">user_id = #{userId,jdbcType=VARCHAR},</if><if test="commodityCode != null">commodity_code = #{commodityCode,jdbcType=VARCHAR},</if><if test="count != null">count = #{count,jdbcType=INTEGER},</if><if test="money != null">money = #{money,jdbcType=INTEGER},</if></set>where   id = #{id,jdbcType=INTEGER} </update><update id="updateByPrimaryKey" parameterType="com.nie.order.bean.OrderTbl">update order_tblset user_id =  #{userId,jdbcType=VARCHAR},commodity_code =  #{commodityCode,jdbcType=VARCHAR},count =  #{count,jdbcType=INTEGER},money =  #{money,jdbcType=INTEGER}where   id = #{id,jdbcType=INTEGER} </update>
</mapper>

配置application.yml

spring:application:name: seata-orderdatasource:url: jdbc:mysql://localhost:3306/order_db?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Drivercloud:nacos:server-addr: 127.0.0.1:8848config:import-check:enabled: falseserver:port: 12000
mybatis:mapper-locations: classpath:mapper/*.xml

配置seata地址

 service {#transaction service group mappingvgroupMapping.default_tx_group = "default"#only support when registry.type=file, please don't set multiple addressesdefault.grouplist = "127.0.0.1:8091"#degrade, current not supportenableDegrade = false#disable seatadisableGlobalTransaction = false}

seata-storage

启动类

package com.nie.storage;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.transaction.annotation.EnableTransactionManagement;@EnableTransactionManagement
@MapperScan("com.nie.storage.mapper")
@EnableDiscoveryClient
@SpringBootApplication
public class SeataStorageMainApplication {public static void main(String[] args) {SpringApplication.run(SeataStorageMainApplication.class, args);}
}

实体类

package com.nie.storage.bean;import java.io.Serializable;
import lombok.Data;/*** @TableName storage_tbl*/
@Data
public class StorageTbl implements Serializable {private Integer id;private String commodityCode;private Integer count;private static final long serialVersionUID = 1L;
}

控制层

package com.nie.storage.controller;import com.nie.storage.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class StorageRestController {@AutowiredStorageService  storageService;@GetMapping("/deduct")public String deduct(@RequestParam("commodityCode") String commodityCode,@RequestParam("count") Integer count) {storageService.deduct(commodityCode, count);return "storage deduct success";}
}

业务层

package com.nie.storage.service;public interface StorageService {/*** 扣除存储数量* @param commodityCode 商品编码* @param count 数量*/void deduct(String commodityCode, int count);
}
package com.nie.storage.service.impl;import com.nie.storage.mapper.StorageTblMapper;
import com.nie.storage.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class StorageServiceImpl implements StorageService {@AutowiredStorageTblMapper storageTblMapper;@Transactional@Overridepublic void deduct(String commodityCode, int count) {storageTblMapper.deduct(commodityCode, count);if (count == 5) {throw new RuntimeException("库存不足");}}
}

持久层

package com.nie.storage.mapper;import com.nie.storage.bean.StorageTbl;/**
* @author lfy
* @description 针对表【storage_tbl】的数据库操作Mapper
* @Entity com.atguigu.storage.bean.StorageTbl
*/
public interface StorageTblMapper {int deleteByPrimaryKey(Long id);int insert(StorageTbl record);int insertSelective(StorageTbl record);StorageTbl selectByPrimaryKey(Long id);int updateByPrimaryKeySelective(StorageTbl record);int updateByPrimaryKey(StorageTbl record);void deduct(String commodityCode, int count);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nie.storage.mapper.StorageTblMapper"><resultMap id="BaseResultMap" type="com.nie.storage.bean.StorageTbl"><id property="id" column="id" jdbcType="INTEGER"/><result property="commodityCode" column="commodity_code" jdbcType="VARCHAR"/><result property="count" column="count" jdbcType="INTEGER"/></resultMap><sql id="Base_Column_List">id,commodity_code,count</sql><select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">select<include refid="Base_Column_List" />from storage_tblwhere  id = #{id,jdbcType=INTEGER} </select><delete id="deleteByPrimaryKey" parameterType="java.lang.Long">delete from storage_tblwhere  id = #{id,jdbcType=INTEGER} </delete><insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.nie.storage.bean.StorageTbl" useGeneratedKeys="true">insert into storage_tbl( id,commodity_code,count)values (#{id,jdbcType=INTEGER},#{commodityCode,jdbcType=VARCHAR},#{count,jdbcType=INTEGER})</insert><insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.nie.storage.bean.StorageTbl" useGeneratedKeys="true">insert into storage_tbl<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null">id,</if><if test="commodityCode != null">commodity_code,</if><if test="count != null">count,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null">#{id,jdbcType=INTEGER},</if><if test="commodityCode != null">#{commodityCode,jdbcType=VARCHAR},</if><if test="count != null">#{count,jdbcType=INTEGER},</if></trim></insert><update id="updateByPrimaryKeySelective" parameterType="com.nie.storage.bean.StorageTbl">update storage_tbl<set><if test="commodityCode != null">commodity_code = #{commodityCode,jdbcType=VARCHAR},</if><if test="count != null">count = #{count,jdbcType=INTEGER},</if></set>where   id = #{id,jdbcType=INTEGER} </update><update id="updateByPrimaryKey" parameterType="com.nie.storage.bean.StorageTbl">update storage_tblset commodity_code =  #{commodityCode,jdbcType=VARCHAR},count =  #{count,jdbcType=INTEGER}where   id = #{id,jdbcType=INTEGER} </update><update id="deduct">update storage_tblset count = count - #{count}where commodity_code = #{commodityCode}</update>
</mapper>

配置application.yml

spring:application:name: seata-storagedatasource:url: jdbc:mysql://localhost:3306/storage_db?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Drivercloud:nacos:server-addr: 127.0.0.1:8848config:import-check:enabled: false
server:port: 13000mybatis:mapper-locations: classpath:mapper/*.xml

配置seata地址

 service {#transaction service group mappingvgroupMapping.default_tx_group = "default"#only support when registry.type=file, please don't set multiple addressesdefault.grouplist = "127.0.0.1:8091"#degrade, current not supportenableDegrade = false#disable seatadisableGlobalTransaction = false}

二阶提交协议

  • 一阶:本地事物提交
    (业务数据+undo_log)
    会添加一个全局锁(数据级别)
  • 二阶事物:成功或者失败:
    成功:所有微服务删除undo_log
    失败:所有人拿到自己的前镜像(数据没做更改之前的数据),恢复到之前的数据,删除undo_log

当我们发送一个全局事物的时候
在这里插入图片描述
我们可以看到他添加了全局锁

在这里插入图片描述
我们的数据库发生了改变
在这里插入图片描述
我们的undo_log也有记录
在这里插入图片描述
但是当某一个事物出错时 那么发生回滚 数据恢复到之前没有修改的时候
在这里插入图片描述
undo_log被删除
在这里插入图片描述

四种事物模式

  1. AT模式
    AT模式是Seata框架的默认事务模式,它通过记录SQL执行前后的数据快照(undo log),在需要回滚时,根据这些数据快照进行反向补偿,从而实现事务的原子性和一致性。
  2. XA模式
    XA模式基于X/Open XA规范实现,依赖于数据库对XA协议的支持。它通过两阶段提交(2PC)来保证分布式事务的原子性和一致性。
  3. TCC模式
    TCC模式是一种基于业务逻辑的分布式事务解决方案,它将事务分为三个阶段:尝试(Try)、确认(Confirm)和取消(Cancel)。
  4. Sage模式
    SAGA模式是一种长事务解决方案,它将一个长事务拆分为多个本地事务,并通过事件驱动的方式进行协调。

相关文章:

  • 如何配置jmeter做分布式压测
  • Spring Boot + MyBatis-Plus实现操作日志记录
  • oracle数据库生成awr报告,排查数据库服务器CPU100%,系统卡顿,慢sql,根据sqlid查询关键信息,如会话SID,客户端机器名
  • MySQL 8.0 OCP 1Z0-908 题目解析(11)
  • MySQL 8.0 OCP 1Z0-908 题目解析(13)
  • 游戏引擎学习第307天:排序组可视化
  • 计算机网络学习(三)——HTTP
  • C++——STL——封装红黑树实现mymap与myset
  • LinkedList 与 ArrayList 的区别及使用场景
  • I-CON: A UNIFYING FRAMEWORK FOR REPRESENTATION LEARNING
  • Android 网络全栈攻略(四)—— 从 OkHttp 拦截器来看 HTTP 协议一
  • 光子计算落地里程碑:实验级OSS芯片实现MNIST高效分类,登顶《Nature》子刊
  • 精益数据分析(81/126):从Timehop案例看病毒性增长的黑客式策略
  • 原创|查询大数据级数据表的AI实现思路(Excel2SQL,Text2SQL)
  • NFS服务小实验
  • 电子电气架构 --- 下一代汽车电子电气架构中的连接性
  • Llamaindex Rag 报错
  • 利用Qt绘图随机生成带多种干扰信息的数字图片
  • 编译原理 期末速成
  • JMeter 教程:监控性能指标 - 第三方插件安装(PerfMon)
  • 做外贸有哪些好的免费b2b网站/网络营销logo
  • 广州模板建站平台/石家庄疫情最新消息
  • 网站优化外包/一篇好的营销软文
  • 个人网站网页制作/下载百度网盘
  • 涪城移动网站建设/深圳关键词优化软件
  • 提供网站制作公司电话/教育培训机构十大排名