文档章节

Spring事务——使用TransactionProxyFactoryBean创建事务代理

摆渡者
 摆渡者
发布于 2014/03/26 21:45
字数 1864
阅读 1929
收藏 6

    Spring同时支持编程式事务策略和声明式事务策略,大部分时候,我们都推荐采用声明式事务策略。使用声明式事务策略的优势十分明显:

  • 声明式事务能大大降低开发者的代码书写量,而且声明式事务几乎不影响应用的代码。因此,不论底层事务策略如何变化,应用程序都无需任何改变

  • 应用程序代码无需任何事务处理代码,可以更专注于业务逻辑的实现

  • Spring可对任何POJO的方法提供事务管理,而且Spring的声明式事务管理无需容器的支持,可在任何环境下使用

  • EJB的CMT无法提供声明式回滚规则;而通过配置文件,Spring可指定事务在遇到特定异常时自动回滚。Spring不仅可在代码中使用setRollbackOnly回滚事务,也可在配置文件中配置回滚规则

  • 由于Spring采用AOP的方式管理事务,因此,可以在事务回滚动作中插入用户自己的动作,而不仅仅是执行系统默认的回滚

    本文主要介绍Spring中声明式事务管理的使用。

    在Spring1.X中,声明式事务使用TransactionProxyFactoryBean来配置事务代理Bean。正如它的类名所暗示的,它是一个专门为目标Bean生成事务代理的工厂Bean。既然TransactionProxyFactoryBean产生的是事务代理Bean,可见Spring的声明式事务策略是基于Spring AOP的。

    每个TransactionProxyFactoryBean为一个目标Bean生成一个事务代理Bean,事务代理的方法改写了目标Bean的方法,就是在目标Bean的方法执行之前加入开始事务,在目标Bean的方法正常结束之前提交事务,如果遇到特定异常则回滚。

    TransactionProxyFactoryBean创建事务代理时,需要了解当前事务所处的环境,该环境属性通过PlatformTransactionManager实例(其实现类的实例)传入,而相关事务规则则在该Bean定义中给出。下面是一个简单的持久化测试程序,该程序插入两条数据,这两条数据完全相同,将违反唯一键约束:

package com.abc.dao.impl;

public class NewsDaoImpl implements NewsDao {
    private DataSource dataSource;
    public void setDataSource(DataSrouce dataSource) {
        this.dataSource = dataSource;
    }
    public void insert(String title, String content) {
        JdbcTemplate template = new JdbcTemplate(dataSource);
        template.update("insert into news_table values (....)");
        //两次相同的操作,将违反主键约束
        template.update("insert into news_table values (....)");
    }
}

    上面的程序中,两次update语句将会违反主键约束——该行代码将会引发异常,如果在没有事务的环境下,前一条代码会向数据库中插入一条记录;但如果在增加了事务控制的环境下,则这两条语句是一个整体,因为第二条语句插入失败将导致第一条插入的记录也被回滚。下面是在Spring配置文件中配置该测试程序,并使用TransactionProxyFactoryBean为它们配置事务代理:

<!-- 使用C3P0数据库连接池作为数据源 -->
<bean id="dataSource" 
    class="com.mchange.v2.c3p0.ComboPolledDataSource" destroy-method="close">
    <property name="driverClass" value="com.mysql.jdbc.Driver" />
    <property name="jdbcUrl" value="jdbc:mysql://localhost/test" />
    <property name="user" value="root" />
    <property name="password" value="root" />
    <property name="maxPoolSize" value="40" />
    <property name="minPoolSize" value="4" />
    <property name="initialPoolSize" value="10" />
    <!-- 指定数据库连接池的连接的最大空闲时间 -->
    <property name="maxIdleTime" value="20" />
</bean>

<!-- 配置JDBC数据源的局部事务管理器,使用DataSourceTransactionManager类,该类实现了
PlatformTransactionManager接口,是针对采用数据源连接的特定实现 -->
<bean id="transactionManager" 
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!-- 配置TransactionManager时需要注入数据源引用 -->
    <property name="dataSource" ref="dataSource" />
</bean>

<!-- 下面这个是前面定义的业务Bean -->
<bean id="newsDao" class="com.abc.dao.impl.NewsDaoImpl">
    <!-- 为业务Bean注入属性 -->
    <property name="dataSource" ref="dataSource" />
</bean>

<bean id="newsDaoTransProxy" 
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <!-- 为事务代理工厂Bean注入事务管理器 -->
    <property name="transactionManager" ref="transactionManager" />
    <!-- 要在哪个Bean上面创建事务代理对象 -->
    <property name="target" ref="newsDao" />
    <!-- 指定事务属性 -->
    <property name="transactionAttributes">
        <props>
            <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
</bean>

    上面的配置文件中定义了一个事务管理器transactionManager,该事务管理器是针对JDBC局部事务的特定实现类。配置事务代理(如上面的newsDaoTransProxy)时需要传入一个事务管理器,一个目标Bean,并指定该事务代理的事务属性。事务属性由transactionAttributes属性指定。上面事务属性只有一条事务传播规则,该规则制定对于所有方法都使用PROPAGATION_REQUIRED的传播规则。Spring支持的事务传播规则如下:

  • PROPAGATION_MANDATORY:要求调用该方法的线程必须处于事务环境中,否则抛出异常

  • PROPAGATION_NESTED:如果执行该方法的线程已处于事务环境下,依然启动新的事务,方法在嵌套的事务里执行。如果执行方法的线程为处于事务中,也启动新的事务,然后执行该方法,此时与PROPAGATION_REQUIRED相同

  • PROPAGATION_NEVER:不允许调用该方法的线程处于事务环境下,如果调用该方法的线程处于事务环境下,则抛出异常

  • PROPAGATION_NOT_SUPPORTED:如果调用该方法的线程处在事务中,则暂停当前事务,然后执行该方法

  • PROPAGATION_REQUIRED:要求在事务环境中执行该方法,如果当前执行的线程已处于事务中,则直接调用;如果当前执行线程不处于事务中,则启动新的事务后执行该方法

  • PROPAGATION_REQUIRES_NEW:要求在事务环境中执行该方法,如果当前执行的线程已处于事务中,则暂停当前事务,启动新事务后执行该方法;如果当前执行线程不处于事务中,则启动新的事务后执行该方法

  • PROPAGATION_SUPPORTS:如果当前执行线程处于事务中,则使用当前事务;不过不在事务中,则不使用事务

    主程序中主要获取了定义的NewsDao类型的Bean,并调用其insert方法,下面是主程序:

public class SpringTest {
    public static void main(String[] arg) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        NewsDao dao = (NewsDao)context.getBean("newsDaoTransProxy",NewsDao.class);
        dao.insert("新闻标题","新闻内容");
    }
}

    上面的第4行中获取了newsDaoTransProxy Bean,该Bean已经不在是NewsDaoImpl类的实例了,它只是Spring容器创建的事务代理,该事务代理以NewsDaoImpl实例为目标对象,且该目标对象也实现了NewsDao接口(与NewsDaoImpl实现了相同的接口),故代理对象也可以当成NewsDao实例来使用。运行上面的程序,将出现一个异常,而且insert方法所执行的两条SQL语句全部回滚——因为事务控制的缘故。

    当我们使用TransactionProxyFactoryBean为目标Bean配置了事务代理以后,SpringAOP将会把负责事务操作的增强处理织入目标Bean的业务方法当中。事实上,Spring不仅支持对接口的代理,整合CGLIB后,Spring甚至可以对具体类生成代理,只要设置proxyTargetClass属性为true即可。如果目标Bean没有实现任何接口,proxyTargetClass属性默认被设为true,此时Spring会对具体类生成代理。当然通常建议面向接口编程,而不要面向具体的实现类编程。

© 著作权归作者所有

摆渡者
粉丝 343
博文 171
码字总数 206342
作品 0
浦东
程序员
私信 提问
Spring3事务管理——基于tx/aop命名空间的配置

基于tx/aop配置的声明式事务管理是实际开发中最常用的事务管理方式之一。 在“Spring3事务管理——使用原始的TransactionProxyFactoryBean”代码基础上修改applicationContext.xml。 配置如下...

guanzhenxing
2014/03/29
4.1K
0
Spring事务——Spring 2.X的事务配置策略

Spring 2.X的事务配置策略 虽然前面介绍的TransactionProxyFactoryBean配置策略简单易懂,但配置起来极为麻烦:每个目标Bean都需要配置一个TransactionProxyFactoryBean代理,这种方式将导致...

摆渡者
2014/03/27
644
0
Spring3事务管理——使用原始的TransactionProxyFactoryBean

Spring的早期版本用户必须通过TransactionProxyFactoryBean代理对需要事务管理的业务类进行代理,便于实施事务功能的增强。 让我们先看代码吧! 业务层代码: public interface UserScoreSe...

guanzhenxing
2014/03/28
6.4K
0
怎么使用Spring配置事务 ?

Spring同时支持编程式事务策略和声明式事务策略,大部分时候都采用声明式事务策略。 声明式事务管理的配置方式,通常有以下4种: (1) 使用TransactionProxyFactoryBean为目标Bean生成事务代理...

a'ゞ浪人گق
2018/08/09
0
0
分布式事务系列(1.2)Spring的事务体系

1 系列目录 - 分布式事务系列(开篇)提出疑问和研究过程- 分布式事务系列(1.1)Spring事务管理器PlatformTransactionManager源码分析- 分布式事务系列(1.2)Spring事务体系- 分布式事务系...

乒乓狂魔
2015/05/18
4.7K
4

没有更多内容

加载失败,请刷新页面

加载更多

64.监控平台介绍 安装zabbix 忘记admin密码

19.1 Linux监控平台介绍 19.2 zabbix监控介绍 19.3/19.4/19.6 安装zabbix 19.5 忘记Admin密码如何做 19.1 Linux监控平台介绍: 常见开源监控软件 ~1.cacti、nagios、zabbix、smokeping、ope...

oschina130111
昨天
64
0
当餐饮遇上大数据,嗯真香!

之前去开了一场会,主题是「餐饮领袖新零售峰会」。认真听完了餐饮前辈和新秀们的分享,觉得获益匪浅,把脑子里的核心纪要整理了一下,今天和大家做一个简单的分享,欢迎感兴趣的小伙伴一起交...

数澜科技
昨天
26
0
DNS-over-HTTPS 的下一代是 DNS ON BLOCKCHAIN

本文作者:PETER LAI ,是 Diode 的区块链工程师。在进入软件开发领域之前,他主要是在做工商管理相关工作。Peter Lai 也是一位活跃的开源贡献者。目前,他正在与 Diode 团队一起开发基于区块...

红薯
昨天
41
0
CC攻击带来的危害我们该如何防御?

随着网络的发展带给我们很多的便利,但是同时也带给我们一些网站安全问题,网络攻击就是常见的网站安全问题。其中作为站长最常见的就是CC攻击,CC攻击是网络攻击方式的一种,是一种比较常见的...

云漫网络Ruan
昨天
27
0
实验分析性专业硕士提纲撰写要点

为什么您需要研究论文的提纲? 首先当您进行研究时,您需要聚集许多信息和想法,研究论文提纲可以较好地组织你的想法, 了解您研究资料的流畅度和程度。确保你写作时不会错过任何重要资料以此...

论文辅导员
昨天
44
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部