2PC分布式事务参考
https://blog.csdn.net/hfmbook/article/details/120173076
Seata 分布式事务
和2PC的区别,2PC在最后提交阶段可能失败,失败了 其他服务事务执行成功,可能存在数据不一致情况。Seata在这里做了一个反向补偿。当某个服务提交失败,其他都提交成功情况,seata会提交一个执行新的sql将数据 回滚到原来的样子。
AT 模式
一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。
TCC模式
一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
二阶段 commit 行为:调用 自定义 的 commit 逻辑。
二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。
SEAGA
Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。
seata server
# registry.conf
registry {
type = "file"
}
config {
type = "file"
file {
name = "file.conf"
}
}
#file.conf
## transaction log store, only used in seata-server
store {
mode = "file"
publicKey = ""
file {
## store location dir
dir = "sessionStore"
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
maxBranchSessionSize = 16384
# globe session size , if exceeded throws exceptions
maxGlobalSessionSize = 512
# file buffer size , if exceeded allocate new buffer
fileWriteBufferCacheSize = 16384
# when recover batch read size
sessionReloadReadSize = 100
# async, sync
flushDiskMode = async
}
}
启动seata
windows seata-server.bat
linux seata-server.sh
java实现定义Filter
获取前面一个服务传递过来的XID,
package io.app.filter;
import io.seata.core.context.RootContext;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class SeataFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest ;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String xid = request.getHeader(RootContext.KEY_XID) ;
if(StringUtils.isNoneBlank(xid)){
/*将这个xid绑定到,seata上下文中。当新的事务使用当前这个xid*/
RootContext.bind(xid);
}
try {
filterChain.doFilter(request , response);
}finally {
RootContext.unbind();
}
}
}
RestTemplate
如果多个Rest的化,都需要进行传递。
@Bean
public RestTemplate restTemplate() {
RestTemplate rest = new RestTemplate();
List<ClientHttpRequestInterceptor>
interceptors = new ArrayList<>();
interceptors.add((request,bytes,execution) -> {
String xid = RootContext.getXID();
/*这里将xid通过header传递给下一个服务。*/
request.getHeaders().add(RootContext.KEY_XID, xid);
return execution.execute(request, bytes);
});
rest.setInterceptors(interceptors);
return rest;
}
java 配置文件
##file.conf
service {
vgroupMapping.my_group = "default"
default.grouplist = "127.0.0.1:8091"
}
##registry.conf
registry {
type = "file"
}
config {
type = "file"
file {
name = "file.conf"
}
}
##application.properties 新增一个配置
# key是固定不变的,value要和 file.conf的 key vgroupMapping.my_group 中的 my_group一致
spring.cloud.alibaba.seata.tx-service-group=my_group
这里建议使用阿里巴巴的连接池,其他连接池可能会因为版本冲突,导致报错。