深入Spring:自定义事务管理

转自:

http://www.jianshu.com/p/5347a462b3a5

前言

上一篇文章讲了Spring的Aop,这里讲一下Spring的事务管理,Spring的事务管理是建立在Aop的基础上的,相比Aop,事务管理的实现耦合性比较小,自定义就比较简单了。

自定义事务

Spring的开启事务管理主要是通过@EnableTransactionManagement注解来实现的。
查看源码就会发现,这个注解主要是注入了两个类InfrastructureAdvisorAutoProxyCreatorBeanFactoryTransactionAttributeSourceAdvisor,而且这两个类是通过其他的Configure类导入的。

  • InfrastructureAdvisorAutoProxyCreator继承自AbstractAutoProxyCreator自定义Aop里介绍过这个类,主要是读取Advisor类,并对符合的bean进行二次代理。
  • BeanFactoryTransactionAttributeSourceAdvisor就是被扫描的Advisor类。这个类会扫面被Transactional注释的类的方法,并提供TransactionInterceptor,来代理被注释的方法。

完整的代码参考Github,这里介绍一下几个关键的类。

  1. 自定义的注解,简便起见注解的属性就不列出来了,跟Transactional的属性一样。

    @Target({ ElementType.METHOD, ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface MyTransactional {
     ....
    }
  2. DataSource和dao层,简便起见,用的内存式数据库h2,dao层用的是mybatis。
     @Bean
     public SqlSessionFactoryBean sqlSessionFactoryBean() {
         SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
         sqlSessionFactoryBean.setDataSource(dataSource());
         return sqlSessionFactoryBean;
     }
    
     @Bean
     public MapperScannerConfigurer mapperScannerConfigurer() {
         MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
         mapperScannerConfigurer.setBasePackage("org.wcong.test.spring.mybatis.mapper");
         return mapperScannerConfigurer;
     }
    
     @Bean
     public DataSource dataSource() {
         EmbeddedDatabaseBuilder embeddedDatabaseBuilder = new EmbeddedDatabaseBuilder();
         return embeddedDatabaseBuilder.setType(EmbeddedDatabaseType.H2).build();
     }
  3. 定义dao方法。
    public interface DbTest {
     @Select("select count(*) from db_test")
     int count();
     @Insert("insert into db_test(id,date,content) values(#{id},now(),#{content})")
     @MyTransactional
     int add(TestModel testModel);
     @Insert("create table db_test(id int,date time,content varchar)")
     int createTable();
    }
  4. 注入transactionManager。
     @Bean(name = "transactionManager")
     public PlatformTransactionManager transactionManager() {
         DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
         transactionManager.setDataSource(dataSource());
         return transactionManager;
     }
  5. InfrastructureAdvisorAutoProxyCreator是直接使用Spring内置的类。
     @Bean
     @Order(Ordered.HIGHEST_PRECEDENCE)
     public InfrastructureAdvisorAutoProxyCreator advisorAutoProxyCreator() {
         return new InfrastructureAdvisorAutoProxyCreator();
     }
  6. BeanFactoryTransactionAttributeSourceAdvisor需要扫描自定义的注解,并嵌入到方法执行的前后,就需要自己定义了。
    其中MySpringTransactionAnnotationParser继承自Spring内置的SpringTransactionAnnotationParser类,重写了扫描注解的方法。
    MyTransactionInterceptor则继承了Spring内置的TransactionInterceptor重写了invoke方法,在事务方法开始的前后输出了部分信息。
    MyProxyTransactionManagementConfiguration则是参考的Spring的注入方式,组装BeanFactoryTransactionAttributeSourceAdvisor并注入相关的Bean。
     public static class MySpringTransactionAnnotationParser extends SpringTransactionAnnotationParser {
         @Override
         public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
             AnnotationAttributes attributes = AnnotatedElementUtils
                     .getMergedAnnotationAttributes(ae, MyTransactional.class);
             if (attributes != null) {
                 return parseTransactionAnnotation(attributes);
             } else {
                 return null;
             }
         }
         public TransactionAttribute parseTransactionAnnotation(MyTransactional ann) {
             return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
         }
     }
     public static class MyTransactionInterceptor extends TransactionInterceptor {
         @Override
         public Object invoke(final MethodInvocation invocation) throws Throwable {
             System.out.println("transaction method :" +
                     invocation.getMethod().getDeclaringClass().getName() + "." + invocation.getMethod().getName());
             Object object = super.invoke(invocation);
             System.out.println(invocation.getMethod().getName() + " result :" + object);
             return object;
         }
     }
     @Configuration
     public static class MyProxyTransactionManagementConfiguration {
         protected PlatformTransactionManager txManager;
         @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
         @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
         public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
             BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
             advisor.setTransactionAttributeSource(transactionAttributeSource());
             advisor.setAdvice(transactionInterceptor());
             advisor.setOrder(Ordered.LOWEST_PRECEDENCE);
             return advisor;
         }
         @Bean
         @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
         public TransactionAttributeSource transactionAttributeSource() {
             return new AnnotationTransactionAttributeSource(new MySpringTransactionAnnotationParser());
         }
         @Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
         @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
         public TransactionalEventListenerFactory transactionalEventListenerFactory() {
             return new TransactionalEventListenerFactory();
         }
         @Autowired(required = false)
         void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
             if (CollectionUtils.isEmpty(configurers)) {
                 return;
             }
             if (configurers.size() > 1) {
                 throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
             }
             TransactionManagementConfigurer configurer = configurers.iterator().next();
             this.txManager = configurer.annotationDrivenTransactionManager();
         }
         @Bean
         @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
         public TransactionInterceptor transactionInterceptor() {
             TransactionInterceptor interceptor = new MyTransactionInterceptor();
             interceptor.setTransactionAttributeSource(transactionAttributeSource());
             if (this.txManager != null) {
                 interceptor.setTransactionManager(this.txManager);
             }
             return interceptor;
         }
     }

观察程序的日志就会发现在Spring加载了被MyTransactional的方法,并放到了事务中执行。同时在方法执行前后输出了方法的一些信息。

customizeTransactional.jpg

结语

Spring的事务管理是建立在Aop之上的,借用了AdvisorInterceptor的很多方法。扩展一下,还可以通过自定义注解,对相应的方法进行代理。

文/wcong(简书作者)
原文链接:http://www.jianshu.com/p/5347a462b3a5
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

时间: 2024-10-12 08:37:32

深入Spring:自定义事务管理的相关文章

spring与事务管理

就我接触到的事务,使用最多的事务管理器是JDBC事务管理器.现在就记录下在spring中是如何使用JDBC事务管理器 1)在spring中配置事务管理器 <!-- JDBC事务 -->    <bean id="jdbcTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property

Spring初学之spring的事务管理xml

所有的java类都是用的上一篇文章:Spring初学之spring的事务管理 不同的是,这时xml配置事务,所以就要把java类中的那些关于spring的注解都删掉,然后在xml中配置,ApplicationContext.xml如下: 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans&q

Spring的事务管理

事务 事务:是逻辑上一组操作,要么全都成功,要么全都失败. 事务特性(ACID) 原子性:事务不可分割 一致性:事务执行的前后,数据完整性保持一致 隔离性:一个事务执行的时候,不应该受到其他事务的打扰 持久性:一旦结束,数据就永久的保存到数据库 如果不考虑隔离性 脏读:一个事务读到另一个事务未提交数据 不可重复读:一个事务读到另一个事务已经提交数据(update)导致一个事务多次查询结果不一致 虚读:一个事务读到另一个事务已经提交数据(insert)导致一个事务多次查询结果不一致 事务的隔离级别

spring笔记--事务管理之声明式事务

事务简介: 事务管理是企业级应用开发中必不可少的技术,主要用来确保数据的完整性和一致性, 事务:就是一系列动作,它们被当作一个独立的工作单元,这些动作要么全部完成,要么全部不起作用. Spring中使用事务: 作为一个受欢迎的企业应用框架,Spring在不同的事务管理API上定义了一个抽象层,而开发时不必了解底层的事务管理API,就可以使用Spring的事务管理机制. Spring既支持编程式的事务管理,也支持声明式的事务管理,大多数情况我们选择后者. 编程式事务管理:将事务管理代码嵌入到业务代

mybatis集成spring的事务管理

第一 创建一个测试实体 1 public class Order { 2 3 private int id; 4 private String orderName; 5 6 public Order(String orderName) { 7 this.orderName = orderName; 8 } 9 10 public int getId() { 11 return id; 12 } 13 public void setId(int id) { 14 this.id = id; 15

Spring初学之spring的事务管理注解

spring的事务管理,本文的例子是:比如你需要网购一本书,卖书的那一方有库存量以及书的价格,你有账户余额.回想我们在编程中要实现买书这样的功能,由于你的账户表和书的库存量表肯定不是同一张数据库表,所以必定会有一个先后,要么先将账户余额扣除书的价格,紧接着将书的库存量减一,要么反过来.那么问题来了,假如我们先将你的账户余额减掉,然后发现书的库存不足,这时怎么办呢,这就需要事务了,当我们发现书的库存不足时就要回滚事务,将你的余额返回去.只要配置了事务,发生了异常,就回滚.这就是事务的回滚.注:新人

Spring高级事务管理难点剖析

1Spring事务传播行为 所谓事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播.Spring支持7种事务传播行为 PROPAGATION_REQUIRED(加入已有事务) 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中.这是最常见也是默认的方式. PROPAGATION_SUPPORTS(跟随环境) 支持当前事务,如果当前没有事务,就以非事务方式执行. PROPAGATION_MANDATORY(需要事务) 使用当前的事务,如果当前没有事务,就抛出异

spring,mybatis事务管理配置与@Transactional注解使用

spring,mybatis事务管理配置与@Transactional注解使用[转] 概述事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性.Spring Framework对事务管理提供了一致的抽象,其特点如下: 为不同的事务API提供一致的编程模型,比如JTA(Java Transaction API), JDBC, Hibernate, JPA(Java Persistence API和JDO(Java Data Objects) 支持声明式事务管理,特别是基

spring的事务管理注解

软件152班杨锦宏 spring的事务管理,本文的例子是:比如你需要网购一本书,卖书的那一方有库存量以及书的价格,你有账户余额.回想我们在编程中要实现买书这样的功能,由于你的账户表和书的库存量表肯定不是同一张数据库表,所以必定会有一个先后,要么先将账户余额扣除书的价格,紧接着将书的库存量减一,要么反过来.那么问题来了,假如我们先将你的账户余额减掉,然后发现书的库存不足,这时怎么办呢,这就需要事务了,当我们发现书的库存不足时就要回滚事务,将你的余额返回去.只要配置了事务,发生了异常,就回滚.这就是