@Transaction注解详解

362 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情

一、@Transaction注解属性

编号属性名说明
1name当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器。
2propagation事务的传播行为,默认值为 REQUIRED。
3isolation事务的隔离度,默认值采用 DEFAULT。isolation = Isolation.READ_COMMITTED
4timeout事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
5read-only指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
6rollback-for用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。
7no-rollback- for抛出 no-rollback-for 指定的异常类型,不回滚事务。

二、使用范例

指定回滚定义的特定的异常类型 @Transactional(rollbackFor= MyException.class)

三、作用范围

1、方法:推荐将注解使用于方法上,不过需要注意的是:该注解只能应用到 public 方法上,否则不生效。

2、:如果这个注解使用在类上的话,表明该注解对该类中所有的 public 方法都生效

3、接口不推荐在接口上使用

四、@Transactional 的使用注意事项总结

1)@Transactional 注解只有作用到 public 方法上事务才生效,不推荐在接口上使用;

2)避免同一个类中调用 @Transactional 注解的方法,这样会导致事务失效;

3)正确的设置 @Transactional 的 rollbackFor 和 propagation 属性,否则事务可能会回滚失败;

4)被 @Transactional 注解的方法所在的类必须被 Spring 管理,否则不生效;

5)底层使用的数据库必须支持事务机制,否则不生效;

6)只有当 @Transactional 注解的方法在类以外被调用的时候,Spring 事务管理才生效。

五、@Transactional事务注解原理

我们知道,@Transactional 的工作机制是基于 AOP 实现的,AOP 又是使用动态代理实现的。如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理,如果目标对象没有实现了接口,会使用 CGLIB 动态代理。 createAopProxy() 方法 决定了是使用 JDK 还是 Cglib 来做动态代理,源码如下:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}
}

如果一个类或者一个类中的 public 方法上被标注@Transactional 注解的话,Spring 容器就会在启动的时候为其创建一个代理类,在调用被@Transactional 注解的 public 方法的时候,实际调用的是,TransactionInterceptor 类中的 invoke()方法。这个方法的作用就是在目标方法之前开启事务,方法执行过程中如果遇到异常的时候回滚事务,方法调用完成之后提交事务。