登录
/
注册
首页
论坛
其它
首页
科技
业界
安全
程序
广播
Follow
关于
签到
每天签到奖励2-10圆
导读
排行榜
TG频道
发帖说明
登录
/
注册
账号
自动登录
找回密码
密码
登录
立即注册
搜索
搜索
关闭
CSDN热搜
程序园
精品问答
技术交流
资源下载
本版
帖子
用户
软件
问答
教程
代码
写记录
VIP申请
VIP网盘
网盘
联系我们
发帖说明
每日签到
道具
勋章
任务
淘帖
动态
分享
留言板
导读
设置
我的收藏
退出
腾讯QQ
微信登录
返回列表
首页
›
业界区
›
业界
›
技术面:Spring (事务传播机制、事务失效的原因、BeanF ...
技术面:Spring (事务传播机制、事务失效的原因、BeanFactory和FactoryBean的关系)
[ 复制链接 ]
遗憩
前天 20:10
Spring的事务传播机制
什么是Spring事务传播机制
Spring的事务传播机制,主要是用于控制多个事务方法相互调用时的事务行为。
复制代码
在后端复杂的业务场景中,多个事务之间的调用可能会导致事务的不一致,例如:数据重复提交,数据丢失等问题,使用事务传播机制可以避免这些问题的发生,从而保证事务的一致性和数据的完整性。
Spring的事务规定了7种传播行为
Spring 通过 @Transactional 注解的 propagation 属性来设置传播级别
Propagation.REQUIRED (默认)
含义:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
特点:这是最常用、且Spring默认的传播行为。适用于绝大多数业务场景。
回滚:内部方法抛出异常未被捕获,会导致整个事务(包括外部方法的操作)回滚。
Propagation.REQUIRES_NEW
含义:无论当前是否存在事务,都会创建一个新的事务,并将当前事务(如果存在)挂起。
特点:创建的是一个完全独立的事务,有自己的提交和回滚边界。
回滚:内部新事务回滚,不影响外部事务(如果外部事务正常提交)。
外部事务回滚,会将内部新事务也回滚(因为外部事务的回滚会恢复到调用 REQUIRES_NEW 方法之前的状态)。
场景:记录日志、发送通知、审计等需要独立提交的场景。
Propagation.NESTED
含义:如果当前存在事务,则在嵌套事务内执行(基于数据库的 Savepoint 机制);如果不存在事务,则创建一个新事务。
特点:不是创建一个真正的新事务,而是在当前事务中设置一个保存点(Savepoint)。它可以在不破坏外部事务的情况下进行部分回滚。
回滚:内部嵌套事务回滚,只回滚到保存点,不影响外部事务已做的其他操作。外部事务回滚,会回滚整个事务,包括嵌套事务的操作。与 REQUIRES_NEW 区别:NESTED 是“子事务”,依赖于外部事务;REQUIRES_NEW 是“独立事务”,与外部事务并列。
Propagation.SUPPORTS
含义:如果当前存在事务,则加入该事务;如果不存在事务,则以非事务方式执行。
特点:对事务是“可有可无”的态度。
场景:适用于只读操作或对事务不敏感的方法。
Propagation.NOT_SUPPORTED
含义:以非事务方式执行操作。如果当前存在事务,则将当前事务挂起。
特点:强制方法不运行在事务中,可以提高性能。
场景:执行一些耗时长、不需要事务保证的操作。
Propagation.NEVER
含义:以非事务方式执行,如果当前存在事务,则抛出异常。
特点:强制禁止在事务中执行此方法。
场景:某些特定操作明确要求不能在事务上下文中运行。
Propagation.MANDATORY
含义:方法必须在一个已存在的事务中执行,如果当前没有事务,则抛出异常。
特点:强制要求调用方必须提供一个事务。
场景:用于那些必须作为更大事务一部分才能保证一致性的操作
面试题
面试官问:
一个长的事务方法a,在读写分离的情况下,里面既有读库操作,也有写库操作,再调用个读库方法b,方法b该用什么传播机制呢?
答:这种情况,读方法如果是最后一步,直接not_supported就行了,避免读报错导致数据回滚。如果是中间步骤,最好还是要required,因为异常失败需要回滚一下。
例如:A B C三个操作,C就是最后一步,B就是中间步骤如果一个读操作在中间(如B操作)失败了,那么就需要让A做回滚,因为C还没执行,所以A必须回滚才能保证一致性。
Spring事务失效可能是哪些原因
首先,容易造成事务失效的方式是通过@Transactional注解方式的声明式事务。
@Transactional是基于Spring的AOP来实现的,而AOP机制又是基于动态代理实现的,如果代理失效那么事务也就失效了。
Spring事务失效的场景
AOP代理失效
@Transactional应用在非public方法上
@Service
public class UserService {
@Transactional
private void updateUserData() { // private方法
// ...
}
}
复制代码
由于代理机制会为 public 方法创建拦截器,事务可以正常生效。而非public得方法,JDK代理是不会创建拦截器的,虽然CGLIB可能支持,但行为不一致,不保证生效。
因此在使用时还是强烈建议放到public方法上。
类内部的调用,类内部方法自调用,内部类方法调用
@Service
public class UserService {
public void businessMethod() {
// 1. 执行一些业务逻辑
// 2. 调用本类的事务方法
this.transactionalMethod(); // 自调用,事务失效
}
@Transactional
public void transactionalMethod() {
// 数据库操作
}
}
复制代码
public class OuterClass{
private class InnerClass {
@Transactional
public void doSomething() {
System.out.println("Doing something in inner class...");
}
}
public void invokeInnerClassMethod() {
InnerClass innerclass = new InnerClass();
innerclass.doSomething();//调用内部类方法,事务失效
}
}
复制代码
在对象内部调用其他方法,就会用对象直接调用了,而不是用代理对象,因此代理会失效。
static、final方法
由于static方法是属于类级别的对象,所以代理对象无法代理,因此AOP也是无效的,因此@Transactional修饰这种方法时,事务也是会失效的。
final方法,是固定形式,而AOP的代理是通过子类或实现接口来实现的,final方法无法被子类覆盖,也无法通过实现类覆盖。因此如果将@Transactional修饰这种方法时,事务也是会失效的。
不存在代理
没有使用Spring管理bean,因此也就不会存在使用AOP来创建代理对象来保证事务。
@Transactional配置错误
@Transactional的propagation属性配置错误
public class UserService{
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void notSupportedMethod() {
// 此方法不会运行在事务中
}
}
复制代码
不同的Propagation属性决定了事务的创建和参与方式。例如:Propagation.NOT_SUPPORTED或Propagation.NEVER会挂起或拒绝当前事务。
@Transactional的rollbackFor设置错误
public class UserService{
@Transactional(rollbackFor = FileNotFoundException.class)
public void someMethod(){
// 抛出 IOException
throw new IOException("文件读取失败");
// 事务不会回滚
}
}
复制代码
rollbackFor配置的异常类型需和方法抛出的异常一致,事务才会进行回滚。改成使用@Transactional(rollbackFor = Exception.class)或@Transactional(rollbackFor = IOException.class)即可。
@Transactional注解引用来源错误
有时候,在写代码的时候,由于手快也没有注意@Transactional注解的引用来源,直接就用了,等出现问题的时候,排查了很久发现写的都没问题,但是还是不生效,然后找别人来帮你看,他上来就看了一下你用的@Transactional,发现并不是Spring中的,而是其他什么地方的,比如javax.transaction.Transactional ,这样也会导致事务失效。
没有启用事务管理
原因:忘记在Spring配置中启用事务管理。
解决方案:
在Java配置中添加@EnableTransactionManagement。
在XML配置中添加。
异常被捕获
public class UserService{
@Transactional(rollbackFor = Exception.class)
public void doSomething() {
try {
// doSomething...
}catch (Exception e){
System.out.println("Exception:"+e);
}
}
}
复制代码
异常被捕获后,不会抛出,也就走不到rollbackFor这样也就不会进行回滚了。
在多线程环境下使用了声明式事务
@Transactional的事务管理使用的是ThreadLocal来存储事务上下文,
ThreadLocal存储的变量是线程隔离的
,因此每个线程都有自己的事务上下文副本。所以Spring的声明式事务在多线程环境下会失效的风险。
数据库引擎不支持事务
如果使用的数据库表引擎不支持事务(如MySQL的MyISAM引擎),那么即使Spring配置了事务,也无法回滚。
解决方案
:确保数据库表使用支持事务的引擎,如MySQL的InnoDB。
BeanFactory和FactoryBean的关系
从名字上看BeanFactory和FactoryBean看着很相似,但是实际上它俩没什么关系,是完全不相关的两个接口。
BeanFactory
BeanFactory就是Bean的工厂,是整个Spring的IOC其中的一部分,管理Bean的创建和生命周期
。
BeanFactory提供了一系列的方法,可以让我们获取到具体的Bean实例。
你可能没有直接用过BeanFactory,但是你肯定间接的使用或者看到过。
applicationContent.getBean(type);
applicationContent.getBean(name);
复制代码
这些代码通常用在一些测试用例,或者需要手动从IOC容器中获取指定的Bean的时候使用。
通过上面的代码使用示例也说明了,
BeanFactory是IOC容器的一个接口,用来获取Bean以及管理Bean的依赖注入和生命周期
。
FactoryBean
FactoryBean本质是一个特殊的Bean,用于定义一个工厂Bean,可以用来生成某些特定的Bean。
当项目中定义了某一个Bean的时候,如果这个Bean实现了FactoryBean这个接口,那么使用这个Bean的时候,Spring的IOC容器不会直接返回这个Bean实例,而是返回FactoryBean的getObject()方法返回的实体对象。(获取FactoryBean本身:需要在ID前加&符号(如&myFactoryBean))
// 定义一个FactoryBean
public class MyFactoryBean implements FactoryBean<MyObject> {
public MyObject getObject() {
return new MyObject(); // 返回实际对象
}
public Class<?> getObjectType() {
return MyObject.class;
}
public boolean isSingleton() {
return true;
}
}
// 使用
BeanFactory beanFactory = new DefaultListableBeanFactory();
// 注册MyFactoryBean
beanFactory.registerSingleton("myFactoryBean", new MyFactoryBean());
// 获取FactoryBean创建的对象
MyObject obj = (MyObject) beanFactory.getBean("myFactoryBean"); // 返回MyObject实例
// 获取FactoryBean本身
FactoryBean<MyObject> factoryBean = (FactoryBean<MyObject>) beanFactory.getBean("&myFactoryBean");
复制代码
FactoryBean常用于创建需要特殊初始化逻辑的Bean,如Spring AOP代理、JNDI数据源,kafka,Dubbo中都用FactoryBean与Spring做集成。
总结
特性BeanFactoryFactoryBean本质Spring容器核心接口一个特殊Bean名称含义Bean的工厂工厂类型的Bean获取对象获取Bean实例获取getObject()返回的对象是否为容器是否(它是容器中的一个Bean)主要用途管理所有Bean自定义特定Bean的创建逻辑
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
事务
技术
Spring
传播
机制
相关帖子
利用CI机制管控jar依赖树
读技术之外:社会联结中的人工智能03工作场所
读技术之外:社会联结中的人工智能04数据
Spring AOP、MVC高频面试题解析
技术人的阅读提效神器:多语言智能中文摘要生成指令
解锁Spring组件扫描的新视角
通过AOP拦截Spring Boot日志并将其存入数据库
一名全栈工程师的技术实践之路
Qwen2.5-VL技术报告
如何在 Spring Boot 应用中配置多个 Spring AI 的 LLM 客户端
vip免费申请,1年只需15美金$
回复
使用道具
举报
提升卡
置顶卡
沉默卡
喧嚣卡
变色卡
千斤顶
照妖镜
相关推荐
安全
利用CI机制管控jar依赖树
0
599
郁兰娜
2025-10-08
安全
读技术之外:社会联结中的人工智能03工作场所
0
120
圄旧剖
2025-10-08
安全
读技术之外:社会联结中的人工智能04数据
0
6
布相
2025-10-09
业界
Spring AOP、MVC高频面试题解析
1
808
钱匾
2025-10-10
业界
技术人的阅读提效神器:多语言智能中文摘要生成指令
0
588
聚怪闩
2025-10-10
安全
解锁Spring组件扫描的新视角
0
266
栓州
2025-10-10
安全
通过AOP拦截Spring Boot日志并将其存入数据库
0
428
咚獭
2025-10-10
安全
一名全栈工程师的技术实践之路
0
416
睁扼妤
2025-10-10
业界
Qwen2.5-VL技术报告
0
448
劝匠注
2025-10-10
业界
如何在 Spring Boot 应用中配置多个 Spring AI 的 LLM 客户端
0
90
梨恐
2025-10-10
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
立即注册
回复
本版积分规则
回帖并转播
回帖后跳转到最后一页
浏览过的版块
安全
代码
签约作者
程序园优秀签约作者
发帖
遗憩
前天 20:10
关注
0
粉丝关注
14
主题发布
板块介绍填写区域,请于后台编辑
财富榜{圆}
anyue1937
9994888
dage888
999994
3934307807
993690
4
富账慕
10007
5
柴古香
9992
6
匝抽
9986
7
孙淼淼
9989
8
筒濂
9977
9
凌彦慧
9985
10
崔瑜然
9984
查看更多