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 中的事务处理可以分为两种方式:声明式事务处理和编程式事务处理。声明式事务处理通过 AOP 的实现,把事务管理代码作为方面封装到业务代码中,使得事务管理代码和业务代码解藕。这...
文件名为`Spring声明式事务处理-1.mht`到`Spring声明式事务处理-5.mht`,通过阅读这些文件,你将能够深入理解Spring声明式事务处理的各个方面,包括配置、使用场景、最佳实践以及常见问题的解决方法。
在这个"spring声明式事务处理demo"中,我们将探讨如何在MyEclipse环境下实现这一功能。 首先,我们要理解Spring事务管理的两种主要方式:编程式事务管理和声明式事务管理。编程式事务管理通常通过AOP(面向切面编程...
Spring声明式事务配置管理方法
在"spring声明式事务管理配置方式"中,主要涉及到以下几个关键知识点: 1. **Spring事务管理器(Transaction Manager)**: - Spring支持多种事务管理器,如DataSourceTransactionManager(用于JDBC事务)和...
### 标题解读:Spring声明式事务配置 Spring框架提供了两种主要类型的事务管理方式:编程式事务管理和声明式事务管理。声明式事务管理通过XML配置或注解的形式定义事务边界,使得业务逻辑与事务控制分离。 ### ...
本文将深入探讨Spring声明式事务的实现机制、优缺点以及如何在实际项目中进行配置和使用。 1. **声明式事务管理概述** 声明式事务管理与编程式事务管理相对,后者需要开发者在代码中显式调用开始、提交、回滚等...
Spring 声明式事务和Spring 编程式事务
《Spring Boot多数据源(支持Spring声明式事务切换和回滚)》 Spring Boot多数据源技术是构建高效、灵活的多租户SaaS架构的关键。在本文中,我们将深入探讨如何实现动态数据源切换,支持Spring声明式事务管理,并讨论...
1. **配置Spring声明式事务**: 在Spring中,声明式事务管理依赖于AOP(面向切面编程)来实现。首先,需要配置一个事务管理器,通常使用`DataSourceTransactionManager`,它与数据源`dataSource`关联。然后,通过`...
Spring 声明式事务处理与多数据源支持 在大部分涉及到数据库操作的项目里面,事务控制、事务处理都是一个无法回避的问题。Spring 框架提供了声明式事务处理机制,使得业务代码中进行事务控制操作起来非常简单。只需...
Spring声明式事务管理是Spring框架中的一个重要特性,它允许开发者在不修改代码的情况下,通过配置来控制事务的边界。这种方式极大地简化了事务管理,使得事务处理与业务逻辑解耦,提高了代码的可维护性和可测试性。...
本资料包"spring声明式事务管理+jdbc+连接池.zip"显然是针对Spring框架在数据库操作方面的深入学习,特别是如何利用Spring进行声明式事务管理和JDBC操作,以及如何配置和使用数据库连接池。接下来,我们将详细探讨这...
Spring声明式事务是Java开发中不可或缺的一部分,它利用Spring的AOP(面向切面编程)和代理机制,为开发者提供了一种简洁的方式来管理事务。在本文中,我们将深入探讨Spring声明式事务的工作原理,源码分析,以及...
本文主要探讨Spring声明式事务管理的配置,这是Spring提供的一种简便的事务管理方式,允许开发者在不编写任何事务管理代码的情况下实现事务控制。这种方式极大地提高了代码的可维护性和可读性。 首先,我们要理解...
1.本例子的使用了 ssh 框架 2.本例子DAO层 使用了 getHibernateTemplate 来实现数据的新增修改和删除 3.本例子使用了声明式...4.本例子提供了详细的使用方法,可以根据 readme.txt 来逐步的验证声明式事务是否起作用
一、Spring声明式事务管理 1. **什么是事务**:事务是数据库操作的基本单元,它保证了数据的一致性和完整性。一个事务中的所有操作要么全部成功,要么全部失败。 2. **事务特性**:事务通常遵循ACID原则,即原子性...