上篇文章学习了如何安装seata,先学习如何使用
事务的4个特性ACID
事务特性
at模式详解
AT模式运行机制
AT模式的特点就是对业务无入侵式,整体机制分二阶段提交
两阶段提交协议的演变:
Seata具体实现步骤
RM实现
-- 库存服务DB执行
CREATE TABLE `tab_storage` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`product_id` bigint(11) DEFAULT NULL COMMENT '产品id',
`total` int(11) DEFAULT NULL COMMENT '总库存',
`used` int(11) DEFAULT NULL COMMENT '已用库存',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO `tab_storage` (`product_id`, `total`,`used`)VALUES ('1', '96', '4');
INSERT INTO `tab_storage` (`product_id`, `total`,`used`)VALUES ('2', '100','0');
-- 订单服务DB执行
CREATE TABLE `tab_order` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`user_id` bigint(11) DEFAULT NULL COMMENT '用户id',
`product_id` bigint(11) DEFAULT NULL COMMENT '产品id',
`count` int(11) DEFAULT NULL COMMENT '数量',
`money` decimal(11,0) DEFAULT NULL COMMENT '金额',
`status` int(1) DEFAULT NULL COMMENT '订单状态:0:创建中;1:已完成',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
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;
库存代码
package com.seata.storage;
import com.seata.storage.model.Storage;
import com.seata.storage.service.StorageService;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
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.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
@MapperScan("com.seata.storage.mapper")
@EnableDiscoveryClient
@EnableFeignClients
public class StorageApplication {
@Autowired
private StorageService storageService;
@GetMapping("storage/change")
public Boolean change(long used , long productId){
Storage storage = new Storage();
storage.setTotal(100)
.setProductId(productId)
.setUsed(3);
return storageService.create(storage);
}
public static void main(String[] args) {
SpringApplication.run(StorageApplication.class, args);
}
}
订单代码
package com.seata.order;
import com.seata.order.model.Order;
import com.seata.order.service.OrderService;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
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.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
@RestController
@SpringBootApplication
@MapperScan("com.seata.order.mapper")
@EnableDiscoveryClient
@EnableFeignClients
public class OrderApplication {
@Autowired
private OrderService orderService;
@GetMapping("order/create")
public Boolean create(long userId , long productId){
Order order = new Order();
order.setCount(1)
.setMoney(BigDecimal.valueOf(88))
.setProductId(productId)
.setUserId(userId)
.setStatus(0);
return orderService.create(order);
}
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
@FeignClient(value = "storage-service")
@Component
public interface StorageClient {
@GetMapping("api/storage/change")
Boolean changeStorage(@RequestParam("productId") long productId , @RequestParam("used") int used);
}
@FeignClient(value = "order-service")
@Component
public interface OrderClient {
@GetMapping("api/order/create")
Boolean create(@RequestParam("userId") long userId , @RequestParam("productId") long productId);
}
调用层代码编写
package com.seata.business;
import com.seata.business.feign.OrderClient;
import com.seata.business.feign.StorageClient;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
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.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
@EnableFeignClients
@EnableDiscoveryClient
public class BusinessApplication {
@Autowired
private OrderClient orderClient;
@Autowired
private StorageClient storageClient;
@GetMapping("buy")
@GlobalTransactional
public String buy(long userId , long productId){
orderClient.create(userId , productId);
storageClient.changeStorage(userId , 1);
return "ok";
}
public static void main(String[] args) {
SpringApplication.run(BusinessApplication.class, args);
}
}