准备阶段(Prepare phase): 事务管理器给每个参与者发送Prepare消息,每个数据库参与者在本地执行事务,并写本地的Undo/Redo日志,此时事务没有提交。 ( Undo日志是记录修改前的数据,用于数据库回滚, Redo日志是记录修改后的数据,用于提交事务后写入数 据文件) 提交阶段(commit phase): 如果事务管理器收到了参与者的执行失败或者超时消息时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的锁资源。注意:必须在最后阶段释放锁资源。
#创建数据库 create database mydemo1; use mydemo1; create table orders(id int primary key not null auto_increment,orderdate date,shopid int not null,buynum int not null);
package com.kgc.mynacos02.ordermodule;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
public class GeneratorCode {
public static void main(String[] args) {
AutoGenerator ag = new AutoGenerator();
// //开启连接数据库
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://192.168.64.135:3306/mydemo1");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("3090_Cmok");
ag.setDataSource(dsc);
//设置全局配置
GlobalConfig gc = new GlobalConfig();
gc.setOutputDir(System.getProperty("user.dir")+"/mynacos02-ordermodule/src/main/java");
gc.setAuthor("js");
gc.setFileOverride(true);
gc.setOpen(false);
gc.setMapperName("%sMapper");//OrderMapper
gc.setXmlName("%sMapper");//OrderMapper.xml
gc.setServiceName("%sService");//Service
gc.setServiceImplName("%sServiceImpl");
gc.setControllerName("%sCtrl");
ag.setGlobalConfig(gc);
//设置包名
PackageConfig pc = new PackageConfig();
pc.setParent("com.kgc.mynacos02.ordermodule");
pc.setMapper("mapper");
pc.setEntity("domain");
pc.setController("controller");
pc.setService("services");
pc.setServiceImpl("services.impl");
//设置每个类的主键方式
gc.setIdType(IdType.AUTO);
//设置日期类型
gc.setDateType(DateType.ONLY_DATE);
ag.setPackageInfo(pc);
//设置策略
StrategyConfig sc = new StrategyConfig();
sc.setEntityLombokModel(true);
sc.setRestControllerStyle(true);
sc.setColumnNaming(NamingStrategy.underline_to_camel);
sc.setNaming(NamingStrategy.underline_to_camel);
ag.setStrategy(sc);
ag.execute();
}
}
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- //导入mybaitis核心--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.1</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.9</version> </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> </dependencies>
@FeignClient(value = "stockmodule",path = "stock")
public interface StockFeignService {
@GetMapping(value = "/deduct/{shopid}/{num}")
public String deduct(@PathVariable("shopid")Integer shopid, @PathVariable("num") Integer num);
}
#domain
@Data
@Builder
@EqualsAndHashCode(callSuper = false)
public class Orders implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Date orderdate;
private Integer shopid;
private Integer buynum;
}
#service接口
public interface OrdersService extends IService<Orders> {
void ordHndler(Orders ord);
}
#service接口实现类
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements OrdersService {
@Resource
private StockFeignService stockFeignService;
@Override
@Transactional
public void ordHndler(Orders ord){
//把订单存放到mydemo1数据库的orders表中
save(ord);
stockFeignService.deduct(ord.getShopid(),ord.getBuynum());
}
}
#controller
@RestController
@RequestMapping("/orders")
public class OrdersCtrl {
@Resource
private OrdersService os;
@RequestMapping(value = "/addOrder",method = RequestMethod.GET)
public String addOrder(@RequestParam("shopid") int shopid,@RequestParam("buynum") int buynum){
Orders ord = Orders.builder().orderdate(new Date()).shopid(shopid).buynum(buynum).build();
os.ordHndler(ord);
return "SUCCESS";
}
}
#application配置注解
@SpringBootApplication
@EnableFeignClients
@MapperScan("com.kgc.mynacos02.ordermodule.mapper")
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
启动订单 和库存2个服务!!!
postman远程调用接口
准备一下2个jar包 放到opt目录下

cd /opt/ ls tar -zxf seata-server-1.3.0.tar.gz mv seata soft/seata cd soft/seata/conf vim file.conf #修改4个数据 mode="db" serverAddr 自己的地址 账号密码 cd /opt/ mkdir sta mv seata-1.3.0.zip sta/ cd sta/ yum install -y unzip zip unzip seata-1.3.0.zip cd seata-1.3.0 ls mysql -uroot -p3090_Cmok create database seata; use seata; source /opt/sta/seata-1.3.0/script/server/db/mysql.sql exit; cd /opt/soft/seata/conf vim registry.conf #修改type = "nacos" serverAddr你的地址 账号nacos密码nacos #修改config type = "nacos" 账号nacos密码nacos #一共改7个 :wq cd /opt ls cd sta/seata-1.3.0/script/config-center/ vim config.txt #service.vgroupMapping.my_test_tx_group=default #my_test_tx_group这个为真实机房地址 可以改成nanjing ##事务分组 异地机房停电可以切换 在后期client调用时候使用 seata.service.vgroup- mapping.projectA=自己 #修改4个地方 service.vgroupMapping.nanjing=default store.db.url=jdbc:mysql://192.168.64.135:3306/ store.db.user=root store.db.password=3090_Comk #保存退出 :wq cd nacos/ ls ll #将config.txt文件上传到配置中心 sh nacos-config.sh -h 192.168.64.135 -p 8848 -g SEATA_GROUP cd /opt/soft/seata/bin/ ls #启动seata server ./seata-server.sh -p 9009 -n 1

打开浏览器!
192.168.64.135:8848/nacos

出现以上界面表明安装成功!!
第一步配置微服务整合seata
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> </dependency>
第二步: 各微服务对应数据库中添加undo_log表
mysql -uroot -p3090_Cmok use mydemo; #执行下面建表 #==================================== 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, PRIMARY KEY (`id`), UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; #==================================== use mydemo1; #同理
第三步:修改application.yml配置(2边都加)
server: port: 8003 spring: application: name: ordermodule datasource: druid: url: jdbc:mysql://192.168.64.135:3306/mydemo1?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf-8&autoReconnect=true username: root password: 3090_Cmok initial-size: 3 max-active: 30 min-idle: 3 max-wait: 60000 time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 validation-query: select 1 test-on-borrow: true test-while-idle: false test-on-return: false pool-prepared-statements: true max-pool-prepared-statement-per-connection-size: 30 filter: stat,wall connection-properties: druid.stat.mergeSql=true;druid.stat.slowSq1Millis=500 use-global-data-source-stat: true cloud: nacos: discovery: server-addr: 192.168.64.135:8848 username: nacos password: nacos namespace: public alibaba: seata: tx-service-group: nanjing mybatis-plus: mapper-locations: mapper/*.xml seata: registry: type: nacos nacos: server-addr: 192.168.64.135:8848 username: nacos password: nacos application: seata-server config: type: nacos nacos: server-addr: 192.168.64.135:8848 username: nacos password: nacos group: SEATA_GROUP namespace: public

postman测试(需要在service实现类中 自定义异常)

查询数据库(库存没减回滚成功!!!)
