@Transactional的简单理解

本文深入探讨了Spring框架中事务管理的关键概念,包括事务在不同方法间如何传递、Controller层调用Service层方法的事务处理限制、在事务中开启子事务的三种方式,以及详细解释了各种事务传播行为的作用。

默认情况下Spring中事务@Transactional的简单理解

首先声明,此文建立在默认的配置下的总结,其它需要特别配置的文中会有说明

一、两个方法互相调用时事务如何传递?

Spring默认的事务传播行为都是:方法A调用方法B,如果已经开启了事务,B不会开启新的事务,用A同一个事务,如果没有事务,则会创建事务

二、在Controller层调用两个不同的Service层方法能保证事务吗?

答案是不能。在Controller层调用两个Service方法,默认会开启两个事务,一个事务异常不会引起另一个事务的回滚,除非在Controller层也定义事务,但是显然是不行的,所以Controller层禁止调用两个Service方法,业务逻辑一定放在Service层

三、如何在事务中开启子事务?外部事务回滚不影响子事务

三种方法:

  • 开启新的session,手动开启、提交事务
		//开启新的Session
 		Session session=SpringContextHolder.getBean(SessionFactory.class).openSession();  
        try {
			session.beginTransaction();				//手动开启事务
			xxxxxx									//具体业务逻辑
			session.getTransaction().commit();		//手动提交事务
		} catch (Exception e) {
			session.getTransaction().rollback()		;//手动回滚
			throw e;
		}finally{
			session.close();
		}
  • 用@Transactional注解到方法上,同时设置事务传播行为为开启新的事务,propagation = Propagation.REQUIRES_NEW
		//设置事务传播行为为:Propagation.REQUIRES_NEW
		@Transatinal(propagation = Propagation.REQUIRES_NEW)
		 publi void save(User user){
		 	xxxxxx;
		 }
  • 使用编程式事务
			//设置传播行为:总是新启一个事务,如果存在原事务,就挂起原事务transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
			transactionTemplate.execute(new TransactionCallback<T>() {
				@Override
				public T doInTransaction(TransactionStatus arg0) {
					//日志信息入库
					save(log);
					return null;
				}
			});

四、事务传播行为(propagation )的说明

  • REQUIRED:业务方法需要在一个容器里运行。如果方法运行时,已经处在一个事务中,那么加入到这个事务,否则自己新建一个新的事务。

  • NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行。

  • REQUIRESNEW:不管是否存在事务,该方法总汇为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建。

  • MANDATORY:该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出例外。

  • SUPPORTS:该方法在某个事务范围内被调用,则方法成为该事务的一部分。如果方法在该事务范围外被调用,该方法就在没有事务的环境下执行。

  • NEVER:该方法绝对不能在事务范围内执行。如果在就抛例外。只有该方法没有关联到任何事务,才正常执行。

  • NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。

<think> 我们被要求提供关于@Transactional注解的相关作业内容。根据之前的引用内容,我们可以围绕@Transactional的使用注意事项、失效场景、与其他注解(如@CacheEvict)的交互以及事务管理的最佳实践等方面来组织内容。 引用中提到了: [^1]:事务注解@Transactional失效的3种场景及解决办法之一:需要找方法上的@Transactional注解信息,没有就不执行代理逻辑。 [^2]:@Transactional与@CacheEvict同时使用时可能会出现问题,建议缩小事务范围,并调整AOP执行顺序。 [^3]:@Transactional(rollbackFor = Exception.class)的作用是保证方法内的事务要么都成功要么都失败,提交事务时保存数据。 [^4]:验证在@Transactional注解的方法中执行Redis命令是否受影响(因为事务提交前数据可能未真正写入)。 [^5]:JPA中修改方法需要添加@Transactional注解的原因:因为JPA的更新操作需要在一个事务中,否则其他操作不可见。 因此,我们可以设计一个包含以下要点的作业: 作业主题:Spring事务管理@Transactional注解的深入理解与应用 一、简答题 1. 简述Spring事务管理的基本原理,特别是@Transactional注解的工作机制。 2. 列举至少三种@Transactional注解失效的场景,并给出解决办法。 3. 为什么在JPA的修改方法中需要添加@Transactional注解?如果不添加会怎样? 二、分析题 4. 在一个同时使用了@Transactional和@CacheEvict注解的方法中,可能会出现什么问题?如何解决? 5. 在以下代码片段中,用户更新操作后需要清除缓存,分析该代码可能存在的问题,并给出解决方案: ```java @Transactional @CacheEvict(value = "userCache", key = "#user.id") public void updateUser(User user) { // 更新数据库 userRepository.save(user); // 其他操作 } ``` 三、实验题 6. 设计一个实验,验证在@Transactional注解的方法中执行Redis命令是否立即生效?并解释原因。 7. 编写一个简单Spring Boot应用,包含一个Service方法,该方法使用JPA更新用户信息,并确保事务正确配置(包括回滚规则)。 四、最佳实践 8. 阿里巴巴Java开发手册中关于事务的建议是什么?请列举至少两条。 9. 如何缩小事务范围?请举例说明。 五、扩展思考 10. 在分布式系统中,@Transactional注解能否保证跨服务的事务?如果不能,有什么替代方案? 设计这个作业的目的是让学生全面掌握@Transactional的使用,理解其背后的机制,并能够解决实际开发中遇到的相关问题。 下面我们将按照要求生成相关问题: §§相关问题§§ 1. 如何保证@Transactional注解在同一个类中的方法调用生效? 2. 在Spring中,@Transactional注解的传播行为有哪些?分别适用于什么场景? 3. 如何设置@Transactional注解的超时时间(timeout)和只读(readOnly)属性? 注意:作业中的问题需要学生通过阅读资料、实践和思考来回答。 </think> ### @Transactional 注解作业内容 #### 一、基础概念理解题 1. **事务核心特性** 解释事务的 ACID 特性及其在 `@Transactional` 中的体现: - **原子性**:事务内操作要么全部成功,要么全部失败回滚[^3] - **一致性**:事务执行前后数据库完整性约束不变 - **隔离性**:多事务并发时的可见性控制(需解释隔离级别) - **持久性**:事务提交后数据永久存储 2. **`@Transactional` 工作机制** 描述 Spring 如何通过 AOP 代理实现事务管理,包括: - 事务管理器(`PlatformTransactionManager`)的作用 - 代理对象如何拦截方法调用 - 注解缺失时代理逻辑不执行的原理[^1] --- #### 二、失效场景分析题(含解决) 3. **自调用失效** 分析以下代码为何事务失效: ```java @Service public class OrderService { public void createOrder() { updateInventory(); // 事务失效点 } @Transactional public void updateInventory() { // 库存更新操作 } } ``` **原因**:自调用跳过代理机制 **解决**:注入自身实例或拆分服务类[^1] 4. **异常处理失效** 解释为何捕获异常导致回滚失败: ```java @Transactional public void process() { try { jpaRepository.save(data); } catch (Exception e) { // 捕获异常导致事务不回滚 } } ``` **解决**:抛出 `RuntimeException` 或配置 `rollbackFor`[^3] 5. **多数据源失效** 描述在多数据源场景下事务管理的特殊配置要求[^2] --- #### 三、进阶实践题 6. **事务与缓存协同** 设计实验验证以下场景: ```java @Transactional @CacheEvict("userCache") public void updateUser(User user) { userRepository.save(user); } ``` - 测试事务回滚时缓存是否被错误清除 - 通过调整 AOP 顺序解决(`@Order` 注解)[^2][^4] 7. **隔离级别实验** 编写并发测试用例验证: - `READ_UNCOMMITTED` 可能读到脏数据 - `REPEATABLE_READ` 如何解决不可重复读 - 使用 `@Transactional(isolation = Isolation.REPEATABLE_READ)` --- #### 四、最佳实践总结 8. **事务设计规范** 根据阿里巴巴开发手册总结: - 事务范围最小化原则[^2] - 避免在事务中处理 RPC/HTTP 请求 - 只读事务配置 `@Transactional(readOnly=true)` 9. **JPA 事务必要性分析** 解释为何 JPA 的 `save()` 方法必须放在事务中[^5] --- #### 五、扩展思考题 10. **分布式事务挑战** 分析 `@Transactional` 在微服务架构中的局限性,对比 Seata/TCC 等解决方案 --- ### 相关参考资料 [^1]: 自调用场景的事务失效原理 [^2]: 事务范围缩小与 AOP 顺序调整 [^3]: 异常处理与回滚规则配置 [^4]: 事务与缓存注解的交互影响 [^5]: JPA 修改操作的事务必要性
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SenKnight

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值