SpringBoot单体应用到分布式下的数据库锁、事务、Redis事务、分布式锁、分布式事务协调

文章目录

很多开发同学工作久了,心里一直有个疑问:

现在都是SpringBoot开发、微服务分布式架构,还用上了Redis缓存。

传统的数据库事务、数据库行锁还有必要用吗?

再加上市面上概念太多:数据库事务、数据库锁、Redis事务、分布式锁、分布式事务......

一堆东西堆在一起,压根不知道什么时候用谁、谁套谁、谁跟谁搭配干活。

今天这篇完全按照成熟互联网公司生产实操标准,把单体到分布式全部讲清楚,谁必须留、谁早就淘汰、谁和谁搭配用、一套成熟业务链路怎么协调。

一、先给结论:SpringBoot单体开发,数据库事务和数据库锁必须用

先说最核心的大前提,不用猜、不用纠结:

只要你操作MySQL写数据,数据库事务永远不能丢,数据库锁根据业务冲突按需用,绝不会被Redis替代。

很多人误以为:有Redis了,数据库锁就不用了。

这是典型新手误区。

1.1 为什么数据库事务必须保留?

SpringBoot的@Transactional底层就是MySQL数据库事务。

它解决的核心问题只有一个:单库单次业务多表操作,要么全成功,要么全回滚。

比如下单业务:

创建订单记录、扣减库存、生成流水记录。

这三步必须捆绑,失败必须回滚。

这件事Redis管不了,框架管不了,只能靠数据库原生事务。

1.2 数据库锁还要不要用?

分场景:

  • 普通低并发业务:不用手动加锁,默认RR隔离级别+MVCC足够;

  • 高并发抢库存、扣余额、秒杀热点数据:必须用数据库悲观锁/乐观锁兜底。

数据库锁兜底的是:最后落地写库那一刻的数据安全,防止超卖、数据覆盖。

Redis再快,也替代不了数据库落盘的最终一致性。

二、关键认知:Redis能干啥?Redis事务能干啥?不能干啥?

很多人搞混,就是把Redis当数据库用。

记住一句话定乾坤:

Redis是缓存+高性能计数器+分布式协调工具,不是数据库,扛不住最终数据一致性。

2.1 Redis在生产核心就干三件事

  • 扛高并发查询,减轻MySQL压力(缓存热点数据);

  • 做分布式锁,控制跨服务同一时间只有一个线程执行业务;

  • 做限流、计数、秒杀削峰,扛住瞬时流量。

2.2 Redis事务,生产几乎没人用

重点说清楚:Redis事务不支持回滚,不满足ACID,没有原子性保障。

它只能保证命令批量连续执行,报错不回滚,没啥事务一致性能力。

生产实操规范:Redis事务一律不用,不要踩坑。

Redis只用来做:分布式锁、缓存、计数

数据一致性写库,全权交给MySQL事务。

三、分布式架构最大痛点:为什么不能只用数据库锁和数据库事务了?

单体项目:一个服务、一个库

只用两个东西就够:

  1. MySQL数据库事务(@Transactional)

  2. MySQL行锁/乐观锁

分布式微服务项目:订单服务、库存服务、支付服务,分开部署、分开数据库。

这时候问题来了:

3.1 数据库锁失效了

数据库锁只能锁住当前本机数据库

跨服务、跨机器、跨库,数据库锁压根看不见对方,锁不住。

3.2 数据库事务失效了

MySQL事务只能管同一个库

跨服务调用,A服务库成功、B服务库失败,本地事务管不了全局,出现数据不一致。

所以分布式必须新增两套东西

  1. 分布式锁(Redis实现):解决跨服务并发争抢问题;

  2. 分布式事务(Seata等):解决跨服务多库数据一致性问题。

四、终极核心:四类锁和事务,生产分工怎么协调?(最关键)

我把四个东西,给你按层级分工讲死,以后永远不会乱:

4.1 第一层:Redis分布式锁(管并发争抢)

作用:跨服务限流抢资源,同一时间全世界只有一个线程能干活。

场景:秒杀下单、修改同一热点数据、防止重复下单。

一句话:分布式锁管"谁能进来执行业务"。

4.2 第二层:SpringBoot本地数据库事务(管单库操作原子性)

作用:当前服务写自己的数据库,要么全成功,要么全回滚。

所有微服务内部,一律标配@Transactional

一句话:本地事务管"自己库的数据不崩"。

4.3 第三层:MySQL数据库锁(管最后落地写库防超卖)

作用:哪怕分布式锁出问题、并发穿透,数据库最后一道防线兜底,不准数据错乱。

用乐观锁version或者悲观锁for update。

一句话:数据库锁管"最后写库数据绝对安全"。

4.4 第四层:分布式事务Seata(管跨服务数据一致)

作用:订单、库存、支付多服务联动,要么全部成功,要么全部回滚。

一句话:分布式事务管"多服务整体业务不崩"。

五、额外关键答疑:分布式架构下,还要不要分库分表?分库分表后锁和事务怎么算?

很多开发搞完分布式、微服务、锁和事务,还会卡最后两个关键点:

1、都已经做微服务分布式了,为啥还要再搞分库分表?分布式能不能替代分库分表?

2、数据库分库分表之后,原来的数据库事务、行锁全都失效了,业务数据怎么保证安全?

5.1 第一个问题:分布式微服务,能替代分库分表吗?

一句话结论:完全不能替代,两者干的事压根不一样,各司其职。

微服务分布式:拆「业务模块」

比如订单、库存、支付拆成不同服务、不同数据库。

解决的是:业务耦合、团队开发协作、服务扩容宕机隔离的问题。

但有个致命问题:就算拆了微服务,订单表数据量越来越大,单表上千万、上亿数据,查询照样慢,单库读写压力照样扛不住。

分库分表:拆「数据容量」

不管你是不是微服务,只要单表数据量太大、单库压力太高,就必须分库分表。

解决的是:单表数据量大、查询慢、单库性能瓶颈的问题。

生产标准搭配:微服务做业务拆分 + 分库分表做数据拆分,两者同时用,互不冲突。

微服务管业务架构,分库分表管数据存储压力。

5.2 第二个问题:分库分表后,数据库事务和数据库锁还有用吗?

先说残酷真相:分库分表后,原生MySQL跨库、跨表事务失效,原生行锁也跨分片锁不住。

分库分表常见场景:比如用户订单按用户ID分片,不同用户订单落在不同分片库、不同数据表。

  • 本地MySQL事务:只能保证同一个分片内操作一致,跨分片事务管不了;

  • MySQL行锁:只能锁当前分片数据,跨分片并发争抢锁不住;

  • 普通单机逻辑完全废掉,必须升级适配。

5.3 分库分表环境下,生产锁和事务怎么协调兜底?

遵循就近兜底、层级不变原则,之前四层协调逻辑不变,只是底层适配升级:

① 第一层:Redis分布式锁(不变,照样第一层扛)

不管分多少库多少表,并发抢资源、防重复下单、防并发争抢,统一还是用Redis分布式锁。
分布式锁和分库分表无关,全局统一拦截并发。

② 第二层:单分片本地事务(保留,只管控同一个分片)

同一个分片库内的多表操作,照样加@Transactional本地事务。

只保证同一个分片内部数据原子性,跨分片不管。

③ 第三层:数据库乐观锁兜底(不变,单分片最后防线)

同一个分片内扣库存、改数据,照样用version乐观锁防超卖。

哪怕分片再多,单条数据写库最终还是单库单表落地,乐观锁照样生效兜底。

④ 第四层:分库分表+跨服务统一用Seata分布式事务(兜底全局一致性)

跨分片、跨库、跨服务的数据不一致问题,全部交给Seata搞定。

分库分表只是多了一层数据拆分,全局数据一致性还是靠分布式事务兜底。

5.4 分库分表核心避坑(生产最重要)

  • 能不分就不分:不是上来就分库分表,单表千万级以内、性能扛得住就别折腾,分库分表复杂度极高;

  • 分片键设计一定要合理 :核心业务尽量让同一组操作落在同一个分片,少跨分片,少用分布式事务;

  • 不要依赖MySQL跨分片事务:原生不支持,不要硬写,一律走Seata兜底;

  • 锁永远两层兜底:Redis分布式锁拦并发,单分片数据库乐观锁兜底写库。

六、成熟生产标准示例:秒杀下单完整链路(四种机制完美配合实战)

我给你拿互联网标准秒杀下单举例,这就是企业成熟写法,直接对标生产。

业务场景

高并发秒杀下单,要做到:

  • 不准超卖;

  • 不准重复下单;

  • 订单、库存数据一致;

  • 扛高并发不压垮MySQL。

第一步:Redis分布式锁拦截(第一层拦并发)

用户秒杀进来,先抢Redis分布式锁。
同一个用户同一时间只能下一单,同一商品同一时间控制争抢线程。

抢锁失败直接返回:排队中/请勿重复操作。

作用:挡住大部分并发,不让请求直接打数据库。

第二步:Redis做库存预减、限流削峰

秒杀库存先放Redis,预扣减,Redis没库存直接返回秒杀结束。

作用:保护MySQL,不扛瞬时大流量。

第三步:进入微服务,开启本地数据库事务

订单服务新增订单记录,扣减本地订单数据,加@Transactional

作用:当前服务内部操作,要么全成要么全回滚。

第四步:数据库乐观锁/悲观锁兜底防超卖

真正落库扣库存时,数据库用乐观锁version机制更新:

sql 复制代码
update stock set count=count-1,version=version+1 where id=1 and version=oldVersion

作用:哪怕前面所有锁都失效,数据库最后一关绝不超卖。

第五步:跨服务调用,用Seata分布式事务保证最终一致

订单服务、库存服务、支付服务跨库操作,通过Seata保证:

任何一个环节失败,所有服务全部回滚,数据不乱。

六、生产最终总结:谁保留、谁不用、谁配合谁

1、必须永远保留的

  • MySQL本地事务:单库操作必加@Transactional;

  • MySQL数据库锁(乐观/悲观):数据落地最后兜底防线。

2、分布式架构必须新增的

  • Redis分布式锁:跨服务抢资源、防并发、防重复操作;

  • Seata分布式事务:跨服务多库数据一致性。

3、生产坚决不用的

  • Redis事务:没用、不回滚、不保一致性,直接废弃。

七、一句话终极口诀,记完永不乱

Redis分布式锁拦并发,本地事务管单库,数据库锁兜底防超卖,分布式事务管跨服务。Redis只管缓存和抢锁,数据落地永远靠MySQL事务+锁兜底。

相关推荐
Dylan的码园2 小时前
springBoot与Web后端基础
前端·spring boot·后端
fengxin_rou2 小时前
黑马点评项目万字总结:从redis基础到实战应用详解
java·开发语言·分布式·后端·黑马点评
skiy2 小时前
SpringBoot项目中读取resource目录下的文件(六种方法)
spring boot·python·pycharm
xmjd msup2 小时前
mysql的分区表
数据库·mysql
Lyyaoo.2 小时前
【JAVA Spring面经】Spring 事务失效情况
java·数据库·spring
MeAT ITEM2 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
salipopl2 小时前
Spring Boot 整合 Druid 并开启监控
java·spring boot·后端
dovens2 小时前
PostgreSQL 中进行数据导入和导出
大数据·数据库·postgresql
IOT.FIVE.NO.12 小时前
claude code desktop cowork报错解决和记录Workspace..The isolated Linux environment ...
linux·服务器·数据库