Spring编程式事务管理
2016-03-10 20:40
417 查看
在基于数据库的应用中,事务是非常重要的。为了方便使用,Spring提供了基于XML和基于注解的方式配置事务,思路都是使用AOP,在特定的切入点统一开启事务,以方法为粒度进行事务控制。并且定义了事务的传播属性,规定了配置了事务的方法互相嵌套调用时的行为准则:
PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED:支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。
越是统一的东西,灵活性就越差。事务是业务逻辑的一部分,有时候事务的开启并不能以方法为粒度进行统一控制,这时候很多开发人员的做法是"将就"基于AOP的事务配置的方法,将需要开启事务的逻辑单独拆出方法进行控制,这其实是一种妥协,而且有时候并不见得称心如意。那么Spring除了基于AOP,还有别的方式管理事务吗?答案就是org.springframework.transaction.support.TransactionTemplate。下面我们研究下它的使用。首先看下类图:
![](http://img.blog.csdn.net/20160310200307831?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
TransactionTemplate继承了DefaultTransactionDefinition,它是TransactionDefinition的一个实现,TransactionDefinition是Spring事务管理中很重要的一个概念,它是事务配置的入口,可以配置事务的各种属性,如隔离级别、传播属性、超时时间、是否只读,通过实现这个接口,TransactionTemplate具备了配置事务的能力。另外必须为它指定transactionManager,毕竟它只是负责触发事务的开启,并不具备事务管理的能力:
现在就可以在Spring管理的Bean中注入并使用:
看到TransactionTemplate的使用比较简单,只需将需要在事务中之行的逻辑封装成TransactionCallback<T>,这个是带返回值的,不带返回值的封装成TransactionCallbackWithoutResult。
观察下事务的执行情况,事务work了。
![](http://img.blog.csdn.net/20160310202809481)
看下它的核心代码:
需要执行事务的业务逻辑被封装成action,它所做的也很简单,在action执行前后进行事务的开启和提交(或着rollback)。开启事务时需要transactionManager的getTransaction方法获取TransactionStatus,而这个方法的参数是TransactionDefinition,前面说过TransactionTemplate本身就是TransactionDefinition的实现,所以将this作为参数传递给这个方法就可以。
也可以看到,TransactionTemplate和基于AOP的配置一样,也是在方法前后执行事务的开启和提交,只是实现的方式改变了。
PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED:支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。
越是统一的东西,灵活性就越差。事务是业务逻辑的一部分,有时候事务的开启并不能以方法为粒度进行统一控制,这时候很多开发人员的做法是"将就"基于AOP的事务配置的方法,将需要开启事务的逻辑单独拆出方法进行控制,这其实是一种妥协,而且有时候并不见得称心如意。那么Spring除了基于AOP,还有别的方式管理事务吗?答案就是org.springframework.transaction.support.TransactionTemplate。下面我们研究下它的使用。首先看下类图:
TransactionTemplate继承了DefaultTransactionDefinition,它是TransactionDefinition的一个实现,TransactionDefinition是Spring事务管理中很重要的一个概念,它是事务配置的入口,可以配置事务的各种属性,如隔离级别、传播属性、超时时间、是否只读,通过实现这个接口,TransactionTemplate具备了配置事务的能力。另外必须为它指定transactionManager,毕竟它只是负责触发事务的开启,并不具备事务管理的能力:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan"> <list> <!-- 可以加多个包 --> <value>com.cuilei01.mgr.utils</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> </props> </property> </bean> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> <value>${jdbc.mgr.url}</value> </property> <property name="username"> <value>${jdbc.mgr.user}</value> </property> <property name="password"> <value>${jdbc.mgr.password}</value> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置transactionTemplate --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"></property> <!--定义事务隔离级别,-1表示使用数据库默认级别--> <property name="readOnly" value="false"></property> <property name="isolationLevelName" value="ISOLATION_DEFAULT"></property> <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"></property> </bean>
现在就可以在Spring管理的Bean中注入并使用:
@ContextConfiguration(locations = {"classpath:applicationContext.xml"}) @RunWith(SpringJUnit4ClassRunner.class) public class TransactionTest { private final Logger logger = LoggerFactory.getLogger(TransactionTest.class); @Resource private TransactionTemplate transactionTemplate; @Test public void testProgrammaticTransaction() { logger.info("Begin test programmatic transaction!########################"); // 第一个事务 Integer result = transactionTemplate.execute(new TransactionCallback<Integer>() { @Override public Integer doInTransaction(TransactionStatus status) { logger.info("Do in transaction with a return value!#####################################"); // 在事务中执行, 有返回值 return 1; } }); logger.info("result:{}", result); // 第二个事务 transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { logger.info("Do in transaction without a return value!#####################################"); // 在事务中执行,没有返回值 } }); }
看到TransactionTemplate的使用比较简单,只需将需要在事务中之行的逻辑封装成TransactionCallback<T>,这个是带返回值的,不带返回值的封装成TransactionCallbackWithoutResult。
观察下事务的执行情况,事务work了。
看下它的核心代码:
@Override public <T> T execute(TransactionCallback<T> action) throws TransactionException { if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) { return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action); } else { TransactionStatus status = this.transactionManager.getTransaction(this); T result; try { result = action.doInTransaction(status); } catch (RuntimeException ex) { // Transactional code threw application exception -> rollback rollbackOnException(status, ex); throw ex; } catch (Error err) { // Transactional code threw error -> rollback rollbackOnException(status, err); throw err; } catch (Exception ex) { // Transactional code threw unexpected exception -> rollback rollbackOnException(status, ex); throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception"); } this.transactionManager.commit(status); return result; } }
需要执行事务的业务逻辑被封装成action,它所做的也很简单,在action执行前后进行事务的开启和提交(或着rollback)。开启事务时需要transactionManager的getTransaction方法获取TransactionStatus,而这个方法的参数是TransactionDefinition,前面说过TransactionTemplate本身就是TransactionDefinition的实现,所以将this作为参数传递给这个方法就可以。
也可以看到,TransactionTemplate和基于AOP的配置一样,也是在方法前后执行事务的开启和提交,只是实现的方式改变了。
相关文章推荐
- java小细节
- Struts2框架的标签库
- java批量下载文件
- Java程序设计概述及环境(Java核心技术卷Ⅰ)
- java语言的I/O操作预习
- 尚学堂java基础——第13、14集笔记
- 关于SpringMvc中的事务@Transactional
- java异常处理预习
- Java NIO笔记 NIO概览
- 成为一名JAVA高级工程师你需要学什么【转】
- java提高篇-----详解java的四舍五入与保留位
- Java集合框架(四)
- Java构造方法
- java项目——java中输出当前时间的各种方法
- 安装JDK包时出现 内部错误 2350 的解决办法
- Java作业
- Java编程思想学习(十) 正则表达式
- 优秀的Java工程师需要掌握的10项技能
- Java泛型和链表
- Java并发编程:Thread类的使用