分布式相关知识:
事务:原子性,一致性,隔离性,持久性。
不同的服务,操作不同的库。
1:分布式事务CAP定理:
-
Consistency 一致性 :数据应该是完全一样的。集群越少越好!
-
Availability 可用性 :可用性讲的是同一份数据,有多份部署。集群越多越好!
-
Partition tolerance 分区容错 :多个数据库之前在同步数据的时候,有个时间差,这个时间范围就是容错范围。容错性必然存在。
2:BASE理论:
Basically Available(基本可用),Soft state(软状态),和 Eventually consistent(最终一致性)三个短语的缩写
基本可用 - 说的是不要集群太多,可用就可以了。
软状态 - 本地事务,要么都成功,要么都失败。分布式事务允许部分成功。
最终一致性 - 最后的最后,要么都成功,要么都失败。
分布式解决方案:
3:两阶段提交:
第一阶段:TM(事务管理器)收集RM(我们的微服务)事务信息,进行注册。
第二阶段:微服务操作数据库的时候,把操作的结果通知给TM,TM就返回是成功或失败。
4:TCC 其实就是采用的补偿机制 :
- Try 阶段主要是做业务逻辑
- Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。
- Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。
**5:消息最终一致性 **:
主要业务一定要完成,次要业务可以通过别的方式最终完成。
一般情况下,最终一致性要保障的是最终都成功!
6:Seata 解决分布式事务:
2019年1月份开源。非常适合解决微服务分布式事务 。性能高 。使用简单。
使用seata
1.开启数据库的 binlog日志
2.创建表(存储数据表的事务日志)
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;
3.下载软件
https://github.com/seata/seata/releases
修改conf下面的file.conf mode=" file "
seate集成到工程里面
1.导包
因为有多个工程都需要引入seata,所以新建一个工程seata的微服务模块来专门来处理分布式事务
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2.1.0.RELEASE</version>
<!--排除-->
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>0.9.0</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
</dependencies>
2: 创建代理数据源
(1)因为多个工程都需要依赖与seata,所以在seata模块下创建seata的配置类
package com.ding.seata.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import io.seata.rm.datasource.DataSourceProxy;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
@Configuration
@EnableConfigurationProperties({MybatisPlusProperties.class})
public class DataSourcesProxyConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource() {
return new DruidDataSource();
}
//创建代理数据源
@Primary//@Primary标识必须配置在代码数据源上,否则本地事务失效
@Bean
public DataSourceProxy dataSourceProxy(DataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
private MybatisPlusProperties properties;
public DataSourcesProxyConfig(MybatisPlusProperties properties) {
this.properties = properties;
}
//替换SqlSessionFactory的DataSource
@Bean
public MybatisSqlSessionFactoryBean sqlSessionFactory(DataSourceProxy dataSourceProxy, PaginationInterceptor paginationInterceptor) throws Exception {
// 这里必须用 MybatisSqlSessionFactoryBean 代替了 SqlSessionFactoryBean,否则 MyBatisPlus 不会生效
MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
mybatisSqlSessionFactoryBean.setDataSource(dataSourceProxy);
mybatisSqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
mybatisSqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath*:/mapper/*.xml"));
MybatisConfiguration configuration = this.properties.getConfiguration();
if(configuration == null){
configuration = new MybatisConfiguration();
}
mybatisSqlSessionFactoryBean.setConfiguration(configuration);
//设置分页
Interceptor[] plugins = {paginationInterceptor};
mybatisSqlSessionFactoryBean.setPlugins(plugins);
return mybatisSqlSessionFactoryBean;
}
}
(2)分别在 需要进行分布式事务控制的模块 引入 seata工程的坐标 ,并且添加一下配置类 config :
@Configuration
@ComponentScan(“com.ding.seata.config”)
public class SeataConfig {
}
3 配置seata-server链接和注册中心信息
3.1配置
将配置文件file.conf和配置文件register.conf 放到 每个需要参与分布式事务项目的resources中
修改文件file.conf :vgroup_mapping. " 模块名 " _tx_group = “default”
把user_tx_group换成本项目的名称就可以了。
3.2.修改application.yml
spring:
cloud:
alibaba:
seata:
tx-service-group: 模块名_tx_group