Spring Boot微服务如何集成seata解决分布式事务问题?
什么是fescar?
关于fescar的详细介绍,请参阅fescar wiki。
传统的2PC提交协议,会持有一个全局性的锁,所有局部事务预提交成功后一起提交,或有一个局部事务预提交失败后一起回滚,最后释放全局锁。锁持有的时间较长,会对并发造成较大的影响,死锁的风险也较高。
fescar的创新之处在于,每个局部事务执行完立即提交,释放本地锁;它会去解析你代码中的sql,从数据库中获得事务提交前的事务资源即数据,存放到undo_log中,全局事务协调器在回滚的时候直接使用undo_log中的数据覆盖你提交的数据。
Spring Boot如何集成fescar?
我们可以从官方代码库中看到,fescar目前提供的示例是针对使用dubbo的服务,那Spring Boot的项目如何集成fescar呢?
和很多2PC提交协议(如tx_lcn)的解决方案一样,fescar也是在数据源处做了代理,和事务协调器进行通信,来决定本地事务是否回滚。所以,第一步,在你的spring boot项目中,首先应使用fescar提供的代理数据源作为你的数据源,例如:
1 2 | DruidDataSource dataSource = initDataSource(dataSourceProps.get( "url" ).toString(), dataSourceProps.get( "username" ).toString(), dataSourceProps.get( "password" ).toString()); DataSourceProxy proxy = new DataSourceProxy(dataSource); |
然后,你需要创建一个Feign拦截器,把RootContext中的XID(XID用于标识一个局部事务属于哪个全局事务,需要在调用链路的上下文中传递)传递到上层调用链路。
1 2 3 4 5 6 7 8 9 10 | @Component public class RequestHeaderInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate template) { String xid = RootContext.getXID(); if (StringUtils.isNotBlank(xid)){ template.header( "Fescar-Xid" ,xid); } } } |
最后,你需要创建一个Http Rest请求拦截器,用于把当前上下文中获取到的XID放到RootContext。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | import com.alibaba.fescar.core.context.RootContext; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class FescarXidFilter extends OncePerRequestFilter { protected Logger logger = LoggerFactory.getLogger(FescarXidFilter. class ); @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String xid = RootContext.getXID(); String restXid = request.getHeader( "Fescar-Xid" ); boolean bind = false ; if (StringUtils.isBlank(xid)&&StringUtils.isNotBlank(restXid)){ RootContext.bind(restXid); bind = true ; if (logger.isDebugEnabled()) { logger.debug( "bind[" + restXid + "] to RootContext" ); } } try { filterChain.doFilter(request, response); } finally { if (bind) { String unbindXid = RootContext.unbind(); if (logger.isDebugEnabled()) { logger.debug( "unbind[" + unbindXid + "] from RootContext" ); } if (!restXid.equalsIgnoreCase(unbindXid)) { logger.warn( "xid in change during http rest from " + restXid + " to " + unbindXid); if (unbindXid != null ) { RootContext.bind(unbindXid); logger.warn( "bind [" + unbindXid + "] back to RootContext" ); } } } } } } |
这样就完成了fescar的集成。
开始使用吧!
首先在项目中初始化两个Bean:
1 2 3 4 5 6 7 8 9 10 | @Bean public FescarXidFilter fescarXidFilter(){ return new FescarXidFilter(); } @Bean public GlobalTransactionScanner scanner(){ GlobalTransactionScanner scanner = new GlobalTransactionScanner( "fescar-test" , "my_test_tx_group" ); return scanner; } |
然后写两个服务,服务A调用服务B,并在A服务的调用方法上打上@GlobalTransactional标签:
1 2 3 4 5 6 7 8 9 10 11 12 | @GlobalTransactional (timeoutMills = 300000 , name = "fescar-test-tx" ) public void testFescar() throws BusinessException { DictionVO dictionVO = new DictionVO(); dictionVO.setCode( "simidatest" ); dictionVO.setValue( "1" ); dictionVO.setDesc( "simidatest" ); dictionVO.setAppId( "sso" ); commonService.createDiction(dictionVO); //远程调用服务B areaMapper.deleteAreaBySysNo( 2 ); //本地事务 throw new BusinessException( "主动报错" ); } |
最后,两个项目中添加application.conf文件,用于告诉客户端如何与分布式协调器通信,官方示例中有这个文件,就不在此贴代码啦,application.conf传送门
启动事务协调器,sh fescar-server.sh 8091 ~/dksl/git/fescar/data,启动你的项目,开始测试吧!
demo地址:https://github.com/dk-lockdown/seata-demo
集成代码:dk-foundation seata分支(https://github.com/dk-lockdown/dk-foundation/tree/dev-seata)
last thing
分布式事务作为微服务应用中的老大难问题,在现有的解决方案中,个人认为fescar是目前最轻量并且代价最小的一种解决方案。目前的版本,事务协调器还不能分布式部署,官方给出的路线图是在三月底会有第一个生产可用版本。让我们一起参与到fescar的社区中,共同推动fescar生态建设,让落地微服务不必再担心分布式事务的问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?