@Transactional简单解释
这个事务注解可以用在类上,也可以用在方法上。
- 将事务注解标记到服务组件类级别,相当于为该服务组件的每个服务方法都应用了这个注解
- 事务注解应用在方法级别,是更细粒度的一种事务注解方式
注意 : 如果某个方法和该方法所属类上都有事务注解属性,优先使用方法上的事务注解属性。
另外,Spring 支持三个不同的事务注解 :
1.Spring 事务注解 org.springframework.transaction.annotation.Transactional(纯正血统,官方推荐)
2.JTA事务注解 javax.transaction.Transactional
3.EJB 3 事务注解 javax.ejb.TransactionAttribute
上面三个注解虽然语义上一样,但是使用方式上不完全一样,若真要使其它的时请注意各自的使用方式~
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Transactional { // value 和 transactionManager 属性 它们两个是一样的意思。当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器。 @AliasFor("transactionManager") String value() default ""; // @since 4.2 @AliasFor("value") String transactionManager() default ""; Propagation propagation() default Propagation.REQUIRED; //事务的传播行为 Isolation isolation() default Isolation.DEFAULT; // 事务的隔离级别 int timeout() default TransactionDefinition.TIMEOUT_DEFAULT; //事务的超时时间,默认值为-1 boolean readOnly() default false; //是否只读 默认是false // 需要回滚的异常 可以指定多个异常类型 不指定默认只回滚RuntimeException和Error Class<? extends Throwable>[] rollbackFor() default {}; String[] rollbackForClassName() default {}; // 不需要回滚的异常们~~~ Class<? extends Throwable>[] noRollbackFor() default {}; String[] noRollbackForClassName() default {}; }
自定义注解驱动的事务管理器 TransactionManagementConfigurer
注解的事务管理器会有一个人默认的,然后@Transaction里也可以通过value属性进行制定~~。
改变默认的有一个非常优雅的方式,那就是使用TransactionManagementConfigurer接口来提供:
@EnableTransactionManagement @Configuration public class JdbcConfig implements TransactionManagementConfigurer { @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource); return dataSourceTransactionManager; } // 复写提供一个即可。可以自己new一个,当然也可议向着一样从容器中获取~~~ @Override public PlatformTransactionManager annotationDrivenTransactionManager() { // 直接使用容器内的事务管理器~~~ return transactionManager(dataSource()); } }
思考:若既有@EnableAspectJAutoProxy又有@EnableTransactionManagement,那么自动代理创建器怎么注入谁呢?和注解的标注的先后顺序有关吗?
根据之前的分析和本文的分析,我们知道:
- @EnableAspectJAutoProxy会像容器注入AnnotationAwareAspectJAutoProxyCreator
- @EnableTransactionManagement会像容器注入InfrastructureAdvisorAutoProxyCreator
那么它俩同时使用时,形如下面:
@EnableTransactionManagement @EnableAspectJAutoProxy @Configuration public class JdbcConfig { ... }
那么最终会注入哪个代理创建类呢?
其实之前我们有分析过,核心代码在这:AopConfigUtils#registerOrEscalateApcAsRequired方法
public abstract class AopConfigUtils { ... @Nullable private static BeanDefinition registerOrEscalateApcAsRequired( Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { // 可以发现这里有一个很巧妙的处理:会对自动代理创建器进行升级~~~~ // 所以如果你第一次进来的是`InfrastructureAdvisorAutoProxyCreator`,第二次进来的是`AnnotationAwareAspectJAutoProxyCreator`,那就会取第二次进来的这个Class // 反之则不行。这里面是维护的一个优先级顺序的,具体参看本类的static代码块,就是顺序 最后一个`AnnotationAwareAspectJAutoProxyCreator`才是最为强大的 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; } ... }
从上面的分析可以知道:无论你的这些注解有多少个,无论他们的先后顺序如何,它内部都有咯优先级提升的机制来保证向下的覆盖兼容。因此一般情况下,我们使用的都是最高级的AnnotationAwareAspectJAutoProxyCreator这个自动代理创建器~~~