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

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模式是一种长事务解决方案,它将一个长事务拆分为多个本地事务,并通过事件驱动的方式进行协调。
http://www.xdnf.cn/news/8307.html

相关文章:

  • R语言开始绘图--柱状图
  • 业务场景中使用 SQL 实现快速数据更新与插入
  • MyBatis-Plus 中 QueryWrapper 的 Limit 实现
  • ceph osd 磁盘分区对齐
  • TCP与UDP区别及应用场景详解
  • 力扣HOT100之图论:200. 岛屿数量
  • 【LangChain大模型应用与多智能体开发 ① 初识LangChain 】
  • 用户意图识别模块
  • 跟Gemini学做PPT:字号选择
  • MyBatisPlus使用教程
  • Ubuntu 上进行树莓派交叉编译
  • hadoop 无法存储数据到hbase里面 已经解决
  • 鸿蒙仓颉开发语言实战教程:实现商城应用详情页
  • SpringBoot Day_03|数据校验|异常处理|日志级别|定时器
  • Java使用CollectionUtils集合工具类
  • 大模型相关数据格式及训练器接收的数据格式
  • 云南安全员考试报名需要具备哪些条件?
  • 【深度学习-Day 15】告别“盲猜”:一文读懂深度学习损失函数
  • VSCode C/C++ 开发环境完整配置及一些扩展用途(自用)update:2025/3/31
  • 英语学习5.21
  • 【项目记录】部门增删改及日志技术
  • 超声仿真乳腺体模的主要声学参数
  • 3 PID控制学习指南
  • el-form elform 对齐方式调整
  • mysql安全管理
  • 【C/C++】虚拟内存空间问题整理_可用于验证掌握情况
  • WebTransport 低延迟通信
  • 解决SQL Server SQL语句性能问题(9)——创建和更新统计对象
  • Spring的事务传播行为
  • PCB设计教程【入门篇】——电路分析基础-电路定理