1、介绍
spring操作数据库时,实现包含数据库操作方法如果异常退出,对数据库的操作是回退,反之方法正常退出,对数据库才操作提交。
2、使用
- 导入相关依赖:数据源,数据库驱动,Spring-jdbc模块
- 配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据
1 //数据源 2 @Bean 3 public DataSource dataSource() throws Exception{ 4 ComboPooledDataSource dataSource = new ComboPooledDataSource(); 5 dataSource.setUser("root"); 6 dataSource.setPassword("123456"); 7 dataSource.setDriverClass("com.mysql.jdbc.Driver"); 8 dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); 9 return dataSource; 10 } 11 12 // 13 @Bean 14 public JdbcTemplate jdbcTemplate() throws Exception{ 15 //Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件 16 JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource()); 17 return jdbcTemplate; 18 }
- 配置事务管理器来控制事务
1 //注册事务管理器在容器中 2 @Bean 3 public PlatformTransactionManager transactionManager() throws Exception{ 4 return new DataSourceTransactionManager(dataSource()); 5 }
- 给方法上标注 @Transactional 表示当前方法是一个事务方法;
1 @Service 2 public class UserService { 3 4 @Autowired 5 private UserDao userDao; 6 7 @Transactional 8 public void insertUser(){ 9 userDao.insert(); 10 //otherDao.other();xxx 11 System.out.println("插入完成..."); 12 int i = 10/0; 13 } 14 15 }
- @EnableTransactionManagement 开启基于注解的事务管理功能;
3、原理
同样先从@EnableXxx作为入口,看它是否给Spring容器中注入了一个什么样的组件,这个组件是否是一个后置处理器,做了哪些工作。
3.1、@EnableTransactionManagement
1 @Target(ElementType.TYPE) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 @Import(TransactionManagementConfigurationSelector.class) 5 public @interface EnableTransactionManagement { 6 7 /** 8 * Indicate whether subclass-based (CGLIB) proxies are to be created ({@code true}) as 9 * opposed to standard Java interface-based proxies ({@code false}). The default is 10 * {@code false}. <strong>Applicable only if {@link #mode()} is set to 11 * {@link AdviceMode#PROXY}</strong>. 12 * <p>Note that setting this attribute to {@code true} will affect <em>all</em> 13 * Spring-managed beans requiring proxying, not just those marked with 14 * {@code @Transactional}. For example, other beans marked with Spring's 15 * {@code @Async} annotation will be upgraded to subclass proxying at the same 16 * time. This approach has no negative impact in practice unless one is explicitly 17 * expecting one type of proxy vs another, e.g. in tests. 18 */ 19 boolean proxyTargetClass() default false; 20 21 /** 22 * Indicate how transactional advice should be applied. The default is 23 * {@link AdviceMode#PROXY}. 24 * @see AdviceMode 25 */ 26 AdviceMode mode() default AdviceMode.PROXY; 27 28 /** 29 * Indicate the ordering of the execution of the transaction advisor 30 * when multiple advices are applied at a specific joinpoint. 31 * The default is {@link Ordered#LOWEST_PRECEDENCE}. 32 */ 33 int order() default Ordered.LOWEST_PRECEDENCE; 34 35 }
1 public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { 2 3 /** 4 * {@inheritDoc} 5 * @return {@link ProxyTransactionManagementConfiguration} or 6 * {@code AspectJTransactionManagementConfiguration} for {@code PROXY} and 7 * {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()}, respectively 8 */ 9 @Override 10 protected String[] selectImports(AdviceMode adviceMode) { 11 switch (adviceMode) { 12 case PROXY: 13 return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; 14 case ASPECTJ: 15 return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME}; 16 default: 17 return null; 18 } 19 } 20 21 }
1 public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector { 2 3 public static final String DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME = "mode"; 4 5 6 /** 7 * The name of the {@link AdviceMode} attribute for the annotation specified by the 8 * generic type {@code A}. The default is {@value #DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME}, 9 * but subclasses may override in order to customize. 10 */ 11 protected String getAdviceModeAttributeName() { 12 return DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME; 13 } 14 15 /** 16 * This implementation resolves the type of annotation from generic metadata and 17 * validates that (a) the annotation is in fact present on the importing 18 * {@code @Configuration} class and (b) that the given annotation has an 19 * {@linkplain #getAdviceModeAttributeName() advice mode attribute} of type 20 * {@link AdviceMode}. 21 * <p>The {@link #selectImports(AdviceMode)} method is then invoked, allowing the 22 * concrete implementation to choose imports in a safe and convenient fashion. 23 * @throws IllegalArgumentException if expected annotation {@code A} is not present 24 * on the importing {@code @Configuration} class or if {@link #selectImports(AdviceMode)} 25 * returns {@code null} 26 */ 27 @Override 28 public final String[] selectImports(AnnotationMetadata importingClassMetadata) { 29 Class<?> annoType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class); 30 AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType); 31 if (attributes == null) { 32 throw new IllegalArgumentException(String.format( 33 "@%s is not present on importing class '%s' as expected", 34 annoType.getSimpleName(), importingClassMetadata.getClassName())); 35 } 36 37 AdviceMode adviceMode = attributes.getEnum(this.getAdviceModeAttributeName()); 38 String[] imports = selectImports(adviceMode); 39 if (imports == null) { 40 throw new IllegalArgumentException(String.format("Unknown AdviceMode: '%s'", adviceMode)); 41 } 42 return imports; 43 } 44 45 /** 46 * Determine which classes should be imported based on the given {@code AdviceMode}. 47 * <p>Returning {@code null} from this method indicates that the {@code AdviceMode} could 48 * not be handled or was unknown and that an {@code IllegalArgumentException} should 49 * be thrown. 50 * @param adviceMode the value of the {@linkplain #getAdviceModeAttributeName() 51 * advice mode attribute} for the annotation specified via generics. 52 * @return array containing classes to import; empty array if none, {@code null} if 53 * the given {@code AdviceMode} is unknown. 54 */ 55 protected abstract String[] selectImports(AdviceMode adviceMode); 56 57 }
解析:
Class<?> annoType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
获取泛型的类型,上例中就是获取 EnableTransactionManagement.class
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
获取注解类型 annoType(也就是 EnableTransactionManagement.class)熟悉值。
可以得到 @EnableTransactionManagement 是要往容器里面注入 AutoProxyRegistrar、ProxyTransactionManagementConfiguration 两个类型的组件
3.2、AutoProxyRegistrar
1 public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar { 2 3 private final Log logger = LogFactory.getLog(getClass()); 4 5 @Override 6 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 7 boolean candidateFound = false; 8 Set<String> annoTypes = importingClassMetadata.getAnnotationTypes(); 9 for (String annoType : annoTypes) { 10 AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType); 11 if (candidate == null) { 12 continue; 13 } 14 Object mode = candidate.get("mode"); 15 Object proxyTargetClass = candidate.get("proxyTargetClass"); 16 if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && 17 Boolean.class == proxyTargetClass.getClass()) { 18 candidateFound = true; 19 if (mode == AdviceMode.PROXY) { 20 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); 21 if ((Boolean) proxyTargetClass) { 22 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); 23 return; 24 } 25 } 26 } 27 } 28 .... 29 } 30 31 }
1 public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) { 2 return registerAutoProxyCreatorIfNecessary(registry, null); 3 } 4 5 public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) { 6 return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source); 7 }
1 private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) { 2 Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); 3 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { 4 BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); 5 if (!cls.getName().equals(apcDefinition.getBeanClassName())) { 6 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); 7 int requiredPriority = findPriorityForClass(cls); 8 if (currentPriority < requiredPriority) { 9 apcDefinition.setBeanClassName(cls.getName()); 10 } 11 } 12 return null; 13 } 14 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); 15 beanDefinition.setSource(source); 16 beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); 17 beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 18 registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); 19 return beanDefinition; 20 }
结论:给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;
InfrastructureAdvisorAutoProxyCreator -> AbstractAdvisorAutoProxyCreator -> AbstractAutoProxyCreator implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
参照 Spring注解版学习笔记——AOP 中的 AnnotationAwareAspectJAutoProxyCreator:
AnnotationAwareAspectJAutoProxyCreator -> AspectJAwareAdvisorAutoProxyCreator -> AbstractAdvisorAutoProxyCreator -> AbstractAutoProxyCreator implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
可以得出结论:两者都是利用后置处理器机制,在对象创建完成以后,判断所有增强器是否可以用于这个对象上,返回一个代理对象,代理对象执行方法利用拦截器链进行调用。
再观察一下两个类之间区别:
1 public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator { 2 3 private ConfigurableListableBeanFactory beanFactory; 4 5 6 @Override 7 protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) { 8 super.initBeanFactory(beanFactory); 9 this.beanFactory = beanFactory; 10 } 11 12 @Override 13 protected boolean isEligibleAdvisorBean(String beanName) { 14 return (this.beanFactory.containsBeanDefinition(beanName) && 15 this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE); 16 } 17 18 }
1 public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { 2 3 private List<Pattern> includePatterns; 4 5 private AspectJAdvisorFactory aspectJAdvisorFactory; 6 7 private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder; 8 9 public void setIncludePatterns(List<String> patterns) { 10 this.includePatterns = new ArrayList<Pattern>(patterns.size()); 11 for (String patternText : patterns) { 12 this.includePatterns.add(Pattern.compile(patternText)); 13 } 14 } 15 16 @Override 17 protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) { 18 super.initBeanFactory(beanFactory); 19 if (this.aspectJAdvisorFactory == null) { 20 this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory); 21 } 22 this.aspectJAdvisorsBuilder = 23 new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory); 24 } 25 26 protected boolean isEligibleAspectBean(String beanName) { 27 if (this.includePatterns == null) { 28 return true; 29 } 30 else { 31 for (Pattern pattern : this.includePatterns) { 32 if (pattern.matcher(beanName).matches()) { 33 return true; 34 } 35 } 36 return false; 37 } 38 } 39 40 41 @Override 42 protected boolean isEligibleBean(String beanName) { 43 return AnnotationAwareAspectJAutoProxyCreator.this.isEligibleAspectBean(beanName); 44 } 45 } 46 47 ... 48 49 }
可以看到两个类在判断是否是为可增强对象的方法上不相同,一个是通过判断 BeanDefinition.role 是否为 ROLE_INFRASTRUCTURE;另一个是通过切面规则是否匹配。
3.3、ProxyTransactionManagementConfiguration
1 @Configuration 2 public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { 3 4 @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) 5 @Role(BeanDefinition.ROLE_INFRASTRUCTURE) 6 public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() { 7 BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor(); 8 advisor.setTransactionAttributeSource(transactionAttributeSource()); 9 advisor.setAdvice(transactionInterceptor()); 10 advisor.setOrder(this.enableTx.<Integer>getNumber("order")); 11 return advisor; 12 } 13 14 @Bean 15 @Role(BeanDefinition.ROLE_INFRASTRUCTURE) 16 public TransactionAttributeSource transactionAttributeSource() { 17 return new AnnotationTransactionAttributeSource(); 18 } 19 20 @Bean 21 @Role(BeanDefinition.ROLE_INFRASTRUCTURE) 22 public TransactionInterceptor transactionInterceptor() { 23 TransactionInterceptor interceptor = new TransactionInterceptor(); 24 interceptor.setTransactionAttributeSource(transactionAttributeSource()); 25 if (this.txManager != null) { 26 interceptor.setTransactionManager(this.txManager); 27 } 28 return interceptor; 29 } 30 31 }
可以看到ProxyTransactionManagementConfiguration 主要是往容器里面注册事务增强器
- 事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解
- 事务拦截器:
- TransactionInterceptor;保存了事务属性信息,事务管理器;他是一个 MethodInterceptor;在目标方法执行的时候;事务拦截器:
- 先获取事务相关的属性
- 再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger,最终会从容器中按照类型获取一个PlatformTransactionManager;
- 执行目标方法,如果异常,获取到事务管理器,利用事务管理回滚操作;如果正常,利用事务管理器,提交事务
- TransactionInterceptor;保存了事务属性信息,事务管理器;他是一个 MethodInterceptor;在目标方法执行的时候;事务拦截器: