96SEO 2026-08-13 12:21 0
其实,
上篇文章讲了同一个类里方法调方法不走代理导致 @Transactional 不生效——这是“代理绕过”的问题。这篇我们更进一步:就算走了代理、@Transactional 正常触发了它到底管了多少?
你以为 @Transactional 会管所有数据源?它只管理了一个 JD娱乐 Connection 的 begin/commit/rollback。同一个 DataSource 上开的新 Connection 它也不管。不是配置错了——是 Annotation 本身的设计边界。
三年前接到的那个工单,让我第一次把这个边界看清楚。
使用者痛点:下单失败、钱已扣却订单未生成,投诉激增。程序响应时间从 200ms 飙升至 0.2s,日志全是 Connection is not available,request timed out。
第一反应是连接池不够,但 HikariCP 监控显示:
active: 。max:
所有连接都被占满,没有释放。
业务 QPS 本应只需要
-- :: INFO o.x.ServiceA - outer: order_id=ORD20260627001 created
-- :: INFO o.x.ServiceB - inner: inventory locked for ORD20260627001
-- :: ERROR o.x.ServiceA - outer failed: payment timeout,rolling back...
-- :: INFO o.x.ServiceA - outer rolled back: order_id=ORD20260627001
订单回滚了库存锁仍在。外层方法标记了 @Transactional内层使用了 @Transactional。两个注解,一个回滚,一个提交。
痛点再现:"有 @Transactional 罩着,怎么会只回滚一半?"
更大的痛点:"成百上千的连接被挂起。却一直不归还池子"
Spring 声明式事务通过 AOP 拦截带有 @Transactional 的方法,并在内部自动管理 JD娱乐 Connection 的事务生命周期。说起来,下面分三层来解释它到底能管什么、不能管什么。
TransactionInterceptor 拦截后委托 DataSourceTransactionManager 执行实际事务操作。其实,说到其主要实现是,
// TransactionInterceptor -> DataSourceTransactionManager.doBegin
Connection con = dataSource.getConnection;con.setAutoCommit;// 此后@Transactional 管理的仅是该 Connection 的 begin / commit / rollback
关键细节:
TransactionSynchronizationManager 保存一个映射:
ConnectionHolderA 与 B 两个服务的调用过程示意:
ServiceA.createOrder # @Transactional
-> doBegin on Connection_A
-> ServiceB.lockInventory # @Transactional
-> 挂起 Connection_A
-> 从池子拿 Connection_B
-> doBegin on Connection_B
-> commit
-> 恢复 Connection_A
-> outer rollback
Pain point:"同一次请求出现两个物理连接。外层回滚并未影响内层已提交的数据"
Propagation.REQUIRES_NEW 的实现逻辑如下:
This explains *** “外层回滚不影响内层”。因为它们根本使用的是不同的物理数据库连接。
If you have multiple DataSources,each typically has its own DataSourceTransactionManager. When you omit @Transactional。Spring picks one marked @Primary. Any operation using a non‑primary DataSource will be completely invisible to chosen transaction manager.
This is *** many multi‑DB projects encounter “半改” bugs when only one DB is wrapped by a transaction.
The problem isn’t a bug in Spring;不过,it’s an assumption that annotation can magically manage *all* connections. Once you know its limits。pick right tool for each scenario.
| 边界类型 | 问题表现 | 推荐方法 |
|---|---|---|
| 单数据源、默认传播 | - 数据库操作偶尔出现“未提交”异常 - 事务漏掉导致库存与订单不一致 | @Transactional 已足够 |
| - 高并发下出现“Connection is not available” | - 考虑 REQUIRES_NEW 是否必要;若不需要,改用 REQUIRED 让内层参与外层事务 | |
| 多数据源 | - 主库成功,副库回滚或相反 - 跨库业务出现 “只提交了一半” 的脏数据 | - 显式指定 transactionManager - 使用 ChainedTransactionManager 实现跨库统一提交/回滚 |
| - 跨资源需要最终一致性 | - @Transactional 无法感知。需要 TCC、消息事务或 Saga 等方案 |
// ❌ 错误:未指定,默认取 @Primary。
只管主库
@Transactional
public void createOrderAndDeduct {…}
// ✅ 正确:显式指定链式事务管理器,统一跨库提交/回滚
@Transactional
public void createOrderAndDeduct { …}
// 链式管理器配置
@Configuration
public class ChainedTxConfig {
@Bean
public PlatformTransactionManager chainedTxManager(
@Qualifier PlatformTransactionManager orderTx,@Qualifier PlatformTransactionManager accountTx) {
return new ChainedTransactionManager;}
}
// 多数据源项目中,每次写 @Transactional 前都要问: // “这个注解到底管理的是哪个 DataSource?” // 不加参数默认使用 @Primary,可能不是业务想要的那个。@Transactional public void foo{ …}
You can use Arthas to inspect thread‑local resources stored in TransactionSynchronizationManager.resources.
vmtool --action getInstances \ --className org.springframework.transaction.support.TransactionSynchronizationManager \ --express 'instances.{resources.get.toString}' -x 动手验证这方面,最小复现 Demo
@SpringBootTest class TransactionBoundaryTest { @Autowired private JdbcTemplate jdbc;@Autowired private PlatformTransactionManager txMgr;@Test void testRequiresNewUsesSeparateConnection { // 外层事务 TransactionStatus outer = txMgr.getTransaction);jdbc.execute");// 内层 REQUIRES_NEW DefaultTransactionDefinition def = new DefaultTransactionDefinition;def.setPropagationBehavior;TransactionStatus inner = txMgr.getTransaction;jdbc.execute");txMgr.commit;// inner 提交 txMgr.rollback;按理说,// outer 回滚 // 验证结果:表中仅剩 'inner' 一条记录。'outer' 已被撤销。}}
—— 🔴 在你的项目里搜这些 🚩
- @Transactional without specifying a transaction manager or value. 检查所有此类方法,确认它们只涉及单一 DataSource;否则会出现“只管到一半”的情况。
- Propagation.REQUIRES_NEW. 如果外层可能回滚。请核实内层已提交的数据是否已有补偿措施,否则会产生“库存扣减却订单撤销”的典型使用者痛点。话说回来,
- @DataSourceTransactionManager beans. 统计项目中有多少个实例。它们各自对应哪个 DataSource;确保每个业务方法都显式指向合适的 manager,而不是默认的 @Primary。
- 使用 Arthas 或自定义拦截器打印 ThreadLocal 中绑定的资源,以快速定位隐藏的多连线场景。.
"
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback