springCloud使用seate框架实现跨服务调用方法的事务绑定(分布式事务管理)
原文地址:https://blog.csdn.net/xupengbo527/article/details/108533368
使用阿里的seate实现分布式事务的实现。
注册中心使用eureka.远程调用使用feign。请自行搭建分布式系统。
1. 下载seate项目。
下载地址:https://github.com/seata/seata/releases
最新版本是1.3.0
下载之后需要改动conf目录配置文件
registry.conf
file.conf文件我们采用的是默认配置,这个地方不需要修改。
在bin文件夹下启动seate服务
2. 配置数据库表
首先创建seate所需要的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=4 DEFAULT CHARSET=utf8;
下面的sql是我们业务实现的表结构(业务就是创建订单,扣减额度)
order库:
CREATE TABLE `user_order` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`user_id` varchar(22) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '用户ID',
`order_no` varchar(22) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '工单编号',
`money` int(11) DEFAULT NULL COMMENT '资金',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
user库
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` varchar(22) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '用户ID',
`quota` int(11) DEFAULT NULL COMMENT '额度',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
3. 项目配置
在涉及到order项目,user项目中添加阿里巴巴seate maven依赖
数据库相关依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<
把下载的seate项目中的file.conf, registry.conf复制到全部项目中resource目录下。
registry.conf文件我们刚才已经修改完毕,此处不需要再次修改。
file.conf文件中此处添加
service {
## vgroup_mapping.server-order-seata-service-group = "default"
vgroup_mapping.my-group = "default"
default.grouplist = "10.205.17.142:8091"
}
service是和store同级配置(mode=‘file’不需要修改)
vgroup_mapping.my-group = “default” 这个地方的my-group我们下面会在yml中配置。
default.grouplist = "127.0.0.1:8091"是我们seate刚才启动的地址和端口号(默认8091)
修改application.yml文件
需要加配置
spring:
application:
name: server-order
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/order
cloud:
alibaba:
seata:
tx-service-group: my-group
此处的my-group是需要和file.conf添加内容一样的。
其他项目同样需要配置。
配置数据库连接代理(此处使用的mybatis-plus)(涉及项目都需要配置)
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.MybatisXMLLanguageDriver;
import io.seata.rm.datasource.DataSourceProxy;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
public class DataSourceProxyConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
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);
//如果你使用的mybatis,下面隔开内容不需要配置
//------------------------------------------------------------------------------
//实体类所在包
sqlSessionFactoryBean.setTypeAliasesPackage("com.example.springbootorder.pojo");
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
configuration.setJdbcTypeForNull(JdbcType.NULL);
//-----------------------------------------------------------------------------
sqlSessionFactoryBean.setConfiguration(configuration);
return sqlSessionFactoryBean.getObject();
}
}
业务中使用只需要在事务发起的地方加一个@GlobalTransactional
/**
* 分布式调用
*/
@GetMapping(value = "seate")
@GlobalTransactional
public String createOrder(@RequestParam(value = "userId") String userId){
int i = ThreadLocalRandom.current().nextInt(9000000) + 1000000;
UserOrder userOrder = new UserOrder();
userOrder.setOrderNo(String.valueOf(i));
userOrder.setUserId(userId);
userOrder.setMoney(10);
userOrderDao.insert(userOrder);
String s = userFeign.reduceQuota(10, userId);
return s;
}