转自:

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
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

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

  1. Spring之事务管理

        事务管理对于企业应用至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.     就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到 ...

  2. Spring学习笔记五:Spring进行事务管理

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6776256.html  事务管理主要负责对持久化方法进行统一的提交或回滚,Spring进行事务管理即我们无需在 ...

  3. Spring的事务管理

    事务 事务:是逻辑上一组操作,要么全都成功,要么全都失败. 事务特性(ACID) 原子性:事务不可分割 一致性:事务执行的前后,数据完整性保持一致 隔离性:一个事务执行的时候,不应该受到其他事务的打扰 ...

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

    事务简介: 事务管理是企业级应用开发中必不可少的技术,主要用来确保数据的完整性和一致性, 事务:就是一系列动作,它们被当作一个独立的工作单元,这些动作要么全部完成,要么全部不起作用. Spring中使 ...

  5. Spring应用——事务管理

    事务基础:请参看:http://www.cnblogs.com/solverpeng/p/5720306.html 一.Spring 事务管理 1.前提:事务管理器 在使用 Spring 声明式事务管 ...

  6. spring+mybatis事务管理

    spring+mybatis事务管理 最近在和朋友做一个项目,考虑用springmvc+mybatis来做,之前在公司工作吧,对于数据库这块的配置也有人再弄,最近因为这个项目,我就上网学习了一些关于数 ...

  7. spring,mybatis事务管理配置与@Transactional注解使用[转]

    spring,mybatis事务管理配置与@Transactional注解使用[转] spring,mybatis事务管理配置与@Transactional注解使用 概述事务管理对于企业应用来说是至关 ...

  8. Spring高级事务管理难点剖析

    1Spring事务传播行为 所谓事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播.Spring支持7种事务传播行为 PROPAGATION_REQUIRED(加入已有事务) 如果当前没 ...

  9. CSDN上看到的一篇有关Spring JDBC事务管理的文章(内容比较全) (转)

    JDBC事务管理 Spring提供编程式的事务管理(Programmatic transaction manage- ment)与声明式的事务管理(Declarative transaction ma ...

随机推荐

  1. lis nlogn算法

    当前所在位的最长上升子序列只和前面一个字符有关 #include <iostream> #include <algorithm> using namespace std; ]; ...

  2. python threading模块

    #coding=utf-8 import threading from time import ctime,sleep def music(func): for i in range(2): prin ...

  3. C# EPPlus导出EXCEL,并生成Chart表

    一  在negut添加EPPlus.dll库文件. 之前有写过直接只用Microsoft.Office.Interop.Excel 导出EXCEL,并生成Chart表,非常耗时,所以找了个EPPlus ...

  4. java多线程面试题整理及答案(2018年)

    1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对 运算密集型任务提速.比如,如果一个线程完 ...

  5. 阿里云mysql数据库备份还原

    1.下载备份包 在rds的备份恢复中点击下载,在弹出的窗口中复制内网下载地址(前提是目标服务器与rds内网互通,否则请复制外网地址) 在目标服务器中执行如下命令进行下载: wget -c '复制的地址 ...

  6. EF6使用Mysql,踏过的那些坑

    在vs2013中使用mysql连接entityFramework经常会遇到这个问题:您的项目引用了最新实体框架:但是,找不到数据连接所需的与版本兼容的实体框架数据提供程序.请退出此向导,安装兼容提供程 ...

  7. Liferay7 BPM门户开发之2: BPMN 2.0 规范入门 (Activiti BPMN extensions)

    Liferay最大的问题是BPM弱,如果做企业开发,BPM必不可少,所以直入主题,做个BPMN2入门. 本文参考地址:http://activiti.org/userguide/index.html# ...

  8. [原创]K8 CMS GoastGuard 密码解密工具

    工具: K8 CMS GoastGuard PASS Decrypt编译: VS2012  C# (.NET Framework v4.5)组织: K8搞基大队[K8team]作者: K8拉登哥哥博客 ...

  9. docker启动报错iptables failed: -重建docker0网络恢复

    # docker启动报错 [root@localhost mysqlconf]# docker run -d -p 8080:8080 --link zookeeper:zookeeper -e du ...

  10. 传染病传播模型(SIS)Matlab代码

    function spreadingability=sir(A,beta,mu) for i=1:length(A) for N=1:50%随机次数 InitialState=zeros(length ...