`
liuluo129
  • 浏览: 116493 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring 声明式事务

阅读更多

Spring的声明式事务管理是通过Spring AOP实现的,默认情况下,Spring事务只在遇见RuntimeException时才会回滚,可以通过配置来设置其他类型异常。

概念上来说,在事务代理上调用方法的工作过程看起来像这样:

基于@Transactional注解的事务方式

 

首先配置Spring容器:

 

<!-- 激活annotation功能 -->
<context:annotation-config />
<!-- 开启使用@Transactional注解方式 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<context:component-scan base-package="com.sohu.tv.crm"
    scoped-proxy="targetClass">
</context:component-scan>-->

<bean id="jdbcTemplate"  class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!-- DataSource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
      destroy-method="close">
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/test"/>
    <property name="user" value="root"/>
    <property name="password" value="root"/>
    <!-- 指定连接池里最小连接数 -->
    <property name="minPoolSize" value="2"/>
    <!-- 指定连接池里最大连接数 -->
    <property name="maxPoolSize" value="5"/>
    <!-- 连接最大空闲时间,超过时间将被丢弃,单位是秒 -->
    <property name="maxIdleTime" value="60"/>
    <!-- 当连接池里面的连接用完的时候,C3P0一次获取的新的连接数 -->
    <property name="acquireIncrement" value="3"/>
    <!-- 指定连接池里最大缓存多少个Statement对象 -->
    <property name="maxStatements" value="10"/>
    <!-- 初始创建连接的数量 -->
    <property name="initialPoolSize" value="2"/>
    <!-- 每隔XX秒检查连接池里的空闲连接 ,单位是秒 -->
    <property name="idleConnectionTestPeriod" value="900"/>
    <property name="numHelperThreads" value="10" />
    <property name="preferredTestQuery" value="select 1 from dual" />
</bean>
<!-- DataSourceTransactionManager是用于JDBC、ibatis/MyBatis类型的Spring内置事务管理器 -->
<bean id="transactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    <property name="rollbackOnCommitFailure" value="true" />
</bean>

 配置中的<tx:annotation-driven/>属性proxy-target-class决定为那些使用了@Transactional注解的类创建何种事务代理。 如果 "proxy-target-class" 属性被设为 "true", 那么基于类的代理就会被创建。即使用CGLib创建增强的代理,如果 "proxy-target-class"属性被设为"false" 或者没设,那么基于接口的标准JDK代理就会被创建。

 

@Transactional注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。 然而,请注意只是使用@Transactional注解并不会启用事务行为, 它仅仅 是一种元数据,能够被可以识别@Transactional注解和上述的配置适当的具有事务行为的beans所使用。其实是<tx:annotation-driven/>元素的出现 开启了事务行为。

Spring团队的建议是你只在具体的类上使用@Transactional注解, 而不要注解在接口上。我在实际项目中一般只在操作数据库的方法上使用,而不是在整个类上使用。

 

@Service
public class BlogServiceImpl implements BlogService {

    @Resource
    private BlogDao blogDao;

    @Override
    @Transactional
    public void insert(Blog blog) {
        // 一些其他逻辑...
        blogDao.insert(blog);
        // 一些其他逻辑...
    }

    @Override
    @Transactional
    public void update(Blog blog) {
        // 一些其他逻辑...
        blogDao.update(blog);
        // 一些其他逻辑...
    }

    @Override
    @Transactional
    public void insertOrUpdate(Blog blog) {
        if (blog.getId() == null) {
            insert(blog);
        } else {
            update(blog);
        }
    }

    @Override
    public Blog get(Integer id) {
        return blogDao.get(id);
    }
}

 这样在调用BlogService方法的时候,带有@Transactional的方法就会在事务的控制下。但是这里需要注意和Spring AOP一样的场景,即方法调用同一个类中的另一个方法时不能被拦截的问题。从上面来看,即insertOrUpdate方法中调用了insert()和update()方法,则insert()或者update()方法使用的实际是insertOrUpdate()方法的事务,如果insertOrUpdate()方法没有@Transactional注解,则调用该方法时,内部的insert()方法的事务是不起作用的,具体原因参见 http://my.oschina.net/mushui/blog/161387.

 

@Transactional注解属性

属性 类型 描述
propagation 枚举型:Propagation 可选的传播性设置
isolation 枚举型:Isolation 可选的隔离性级别(默认值:ISOLATION_DEFAULT)
readOnly 布尔型 读写型事务 vs. 只读型事务
timeout int型(以秒为单位) 事务超时
rollbackFor 一组Class类的实例,必须是Throwable的子类 一组异常类,遇到时 必须 进行回滚。默认情况下checked exceptions不进行回滚,仅unchecked exceptions(即RuntimeException的子类)才进行事务回滚。
rollbackForClassname 一组Class类的名字,必须是Throwable的子类 一组异常类名,遇到时 必须 进行回滚
noRollbackFor 一组Class类的实例,必须是Throwable的子类 一组异常类,遇到时 必须不 回滚。
noRollbackForClassname 一组Class类的名字,必须是Throwable的子类 一组异常类,遇到时 必须不 回滚

事务传播行为

Spring管理的事务是逻辑事务,而且物理事务和逻辑事务最大差别就在于事务传播行为,事务传播行为用于指定在多个事务方法间调用时,事务是如何在这些方法间传播的,Spring共支持7种传播行为:

Required:默认的事务传播行为,表示必须有逻辑事务,否则新建一个事务,使用PROPAGATION_REQUIRED指定,表示如果当前存在一个逻辑事务,则加入该逻辑事务,否则将新建一个逻辑事务:

RequiresNew:创建新的逻辑事务,使用PROPAGATION_REQUIRES_NEW指定,表示每次都创建新的逻辑事务(物理事务也是不同的)因此外部事务可以不受内部事务回滚状态的影响独立提交或者回滚。

Supports:支持当前事务,使用PROPAGATION_SUPPORTS指定,指如果当前存在逻辑事务,就加入到该逻辑事务,如果当前没有逻辑事务,就以非事务方式执行。

NotSupported:不支持事务,如果当前存在事务则暂停该事务,使用PROPAGATION_NOT_SUPPORTED指定,即以非事务方式执行,如果当前存在逻辑事务,就把当前事务暂停,以非事务方式执行。

Mandatory:使用PROPAGATION_MANDATORY指定,如果当前有事务,使用当前事务执行,如果当前没有事务,则抛出异常(IllegalTransactionStateException)。

Never:不支持事务,如果当前存在是事务则抛出IllegalTransactionStateException异常,使用PROPAGATION_NEVER指定。

 

Nested:嵌套事务支持,使用PROPAGATION_NESTED指定,如果当前存在事务,则在嵌套事务内执行,如果当前不存在事务,则创建一个新的事务,嵌套事务使用数据库中的保存点来实现,即嵌套事务回滚不影响外部事务,但外部事务回滚将导致嵌套事务回滚。

Nested和RequiresNew的区别: 

  • RequiresNew每次都创建新的独立的物理事务,而Nested只有一个物理事务;
  • Nested嵌套事务回滚或提交不会导致外部事务回滚或提交,但外部事务回滚将导致嵌套事务回滚,而 RequiresNew由于都是全新的事务,所以之间是无关联的;
  • Nested使用JDBC 3的保存点实现,即如果使用低版本驱动将导致不支持嵌套事务。

    实际应用中一般使用默认的事务传播行为,偶尔会用到RequiresNew和Nested方式。

基于XML配置的事务

个人比较偏爱使用@Transactional注解的方式,但是很大一部分项目是使用XML方式的,使用XML方式只需要把上面配置中的

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

 去掉,然后添加如下配置即可:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
   <tx:attributes>
       <tx:method name="insert*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
       <tx:method name="get*" read-only="true"/>
   </tx:attributes>
</tx:advice>
<aop:config>
   <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.sohu.tv.crm.service.impl.*.*(..))" />
</aop:config>
分享到:
评论

相关推荐

    Spring声明式事务

    spring声明式事务实例 可复制修改使用。。。。。。。。。。

    Spring源代码解析(六):Spring声明式事务处理.doc

    Spring 声明式事务处理 Spring 中的事务处理可以分为两种方式:声明式事务处理和编程式事务处理。声明式事务处理通过 AOP 的实现,把事务管理代码作为方面封装到业务代码中,使得事务管理代码和业务代码解藕。这...

    Spring声明式事务处理

    文件名为`Spring声明式事务处理-1.mht`到`Spring声明式事务处理-5.mht`,通过阅读这些文件,你将能够深入理解Spring声明式事务处理的各个方面,包括配置、使用场景、最佳实践以及常见问题的解决方法。

    spring声明式事务处理demo

    在这个"spring声明式事务处理demo"中,我们将探讨如何在MyEclipse环境下实现这一功能。 首先,我们要理解Spring事务管理的两种主要方式:编程式事务管理和声明式事务管理。编程式事务管理通常通过AOP(面向切面编程...

    Spring声明式事务配置管理方法

    Spring声明式事务配置管理方法

    spring声明式事务管理配置方式

    在"spring声明式事务管理配置方式"中,主要涉及到以下几个关键知识点: 1. **Spring事务管理器(Transaction Manager)**: - Spring支持多种事务管理器,如DataSourceTransactionManager(用于JDBC事务)和...

    spring声明式事务配置

    ### 标题解读:Spring声明式事务配置 Spring框架提供了两种主要类型的事务管理方式:编程式事务管理和声明式事务管理。声明式事务管理通过XML配置或注解的形式定义事务边界,使得业务逻辑与事务控制分离。 ### ...

    spring声明式事务.zip

    本文将深入探讨Spring声明式事务的实现机制、优缺点以及如何在实际项目中进行配置和使用。 1. **声明式事务管理概述** 声明式事务管理与编程式事务管理相对,后者需要开发者在代码中显式调用开始、提交、回滚等...

    Spring 声明式事务和Spring 编程式事务

    Spring 声明式事务和Spring 编程式事务

    Spring Boot多数据源(支持Spring声明式事务切换和回滚).pdf

    《Spring Boot多数据源(支持Spring声明式事务切换和回滚)》 Spring Boot多数据源技术是构建高效、灵活的多租户SaaS架构的关键。在本文中,我们将深入探讨如何实现动态数据源切换,支持Spring声明式事务管理,并讨论...

    实验 spring 声明事务

    1. **配置Spring声明式事务**: 在Spring中,声明式事务管理依赖于AOP(面向切面编程)来实现。首先,需要配置一个事务管理器,通常使用`DataSourceTransactionManager`,它与数据源`dataSource`关联。然后,通过`...

    Spring Data JPA系列4——Spring声明式事务处理与多数据源支持.doc

    Spring 声明式事务处理与多数据源支持 在大部分涉及到数据库操作的项目里面,事务控制、事务处理都是一个无法回避的问题。Spring 框架提供了声明式事务处理机制,使得业务代码中进行事务控制操作起来非常简单。只需...

    spring声明式事务配置方法.docx

    Spring声明式事务管理是Spring框架中的一个重要特性,它允许开发者在不修改代码的情况下,通过配置来控制事务的边界。这种方式极大地简化了事务管理,使得事务处理与业务逻辑解耦,提高了代码的可维护性和可测试性。...

    spring声明式事务管理+jdbc+连接池.zip

    本资料包"spring声明式事务管理+jdbc+连接池.zip"显然是针对Spring框架在数据库操作方面的深入学习,特别是如何利用Spring进行声明式事务管理和JDBC操作,以及如何配置和使用数据库连接池。接下来,我们将详细探讨这...

    深入理解Spring声明式事务:源码分析与应用实践

    Spring声明式事务是Java开发中不可或缺的一部分,它利用Spring的AOP(面向切面编程)和代理机制,为开发者提供了一种简洁的方式来管理事务。在本文中,我们将深入探讨Spring声明式事务的工作原理,源码分析,以及...

    Spring 事务 (二) Spring 声明式事务 配置

    本文主要探讨Spring声明式事务管理的配置,这是Spring提供的一种简便的事务管理方式,允许开发者在不编写任何事务管理代码的情况下实现事务控制。这种方式极大地提高了代码的可维护性和可读性。 首先,我们要理解...

    spring 声明式事务

    1.本例子的使用了 ssh 框架 2.本例子DAO层 使用了 getHibernateTemplate 来实现数据的新增修改和删除 3.本例子使用了声明式...4.本例子提供了详细的使用方法,可以根据 readme.txt 来逐步的验证声明式事务是否起作用

    Spring声明式事务及BaseDao完整版

    一、Spring声明式事务管理 1. **什么是事务**:事务是数据库操作的基本单元,它保证了数据的一致性和完整性。一个事务中的所有操作要么全部成功,要么全部失败。 2. **事务特性**:事务通常遵循ACID原则,即原子性...

Global site tag (gtag.js) - Google Analytics