Spring 事务基于 AOP 实现代理对象需要拦截Transactional方法的调用。非public方法导致事务失效的根本原因是 Spring 事务管理器默认只对public方法进行事务增强。 原理分析1. 代理与可见性的关系JDK 动态代理只能代理接口中的方法接口方法默认为public。非public方法无法被代理调用。CGLIB 代理可以代理非public方法通过生成子类但 Spring 出于设计一致性考虑默认限制了事务增强仅对public方法生效。2. Spring 源码中的判断逻辑在AbstractFallbackTransactionAttributeSource#computeTransactionAttribute方法中java// 如果方法不是 public直接返回 null表示不处理事务 if (method.getModifiers() ! Modifier.PUBLIC) { return null; }Spring 通过allowPublicMethodsOnly属性控制默认值为true因此只有public方法才会被扫描并应用事务配置。3. 为什么要这样设计避免代理复杂性非public方法涉及私有、保护的访问权限CGLIB 虽能代理但会产生额外的字节码操作和可见性问题。符合 AOP 语义AOP 通常用于跨切面关注点如事务、日志应用于公共 API 更自然。防止误用开发者容易错误地认为private方法加了Transactional就自动生效实际上内部调用根本不会被代理拦截即使方法是public同类内调用this也会失效。✅ 如果必须使用非public事务怎么办虽然不推荐但可以通过以下方式强制生效设置spring.aop.proxy-target-classtrue使用 CGLIB配置EnableTransactionManagement(proxyTargetClass true) 修改AnnotationTransactionAttributeSource的setPublicMethodsOnly(false)自定义但更推荐的做法将事务逻辑抽取到独立的public方法中或者使用编程式事务TransactionTemplate。 总结非public方法导致事务失效是 Spring 的主动设计约束旨在保证代理的可靠性和切面语义的清晰性。始终让Transactional标注在public方法上是规避此问题的最佳实践。