Spring(三): 事务
来源:互联网 发布:ios和mac 编辑:程序博客网 时间:2024/05/16 18:55
一. 事务的基本概念
二. Spring事务的实现方式
三. Spring事务配置详解
四. Spring多事务语义配置及最佳实践
五. @Transactional实现事务管理
六. @Transactional配置详解
一. 事务的基本概念
- 更新客户所购商品的库存信息
- 保存客户付款信息
- 生成订单保存数据库
- 更新用户相关信息
正常情况下,全部做完,就是一个完整的交易,就是一个事务。但是如果第一第二步做完了,出错了,然后没保存订单,那么后果就严重了,这就不是一个事务操作。数据库事务就是保证不能出现这样的问题。
实现:
1. 配置 声明:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
2.配置业务逻辑
<bean id="userService" class="cn.javass.spring.chapter9.service.impl.ConfigUserServiceImpl"> <property name="userDao" ref="userDao"/> <property name="addressService" ref="addressService"/> </bean> <bean id="addressService" class="cn.javass.spring.chapter9.service.impl.ConfigAddressServiceImpl"> <property name="addressDao" ref="addressDao"/> </bean>
3.事务相关配置:
<tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="*" propagation="REQUIRED" isolation="READ_COMMITTED" read-only="true"/> </tx:attributes> </tx:advice>
4. AOP配置
<aop:config> <aop:pointcut id="serviceMethod" expression="execution(* cn..chapter9.service..*.*(..))"/> <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice"/> </aop:config>
解释:
- <tx:advice>:事务通知定义,用于指定事务属性,其中"transaction-manager"属性指定事务管理器,并通过 <tx:attributes> 指定具体需要拦截的方法;
- <tx:method name = "save*">:用于将拦截以save开头的方法,被拦截的方法将应用配置的事务属性:propagation="REQUIRED"表示传播行为是Required,isolation="READ_COMMITTED"表示隔离级别是提交读
- <tx:method name = "*">:表示将拦截其他所有方法,被拦截的方法将应用配置的事务属性:propagation="REQUIRED"表示传播行为是Required,isolation="READ_COMMITTED"表示隔离级别是提交读,read-only="true"表示事务只读
- <aop:config>:AOP相关配置
- <aop:pointcut />:切入点定义,定义名为"serviceMethod"的aspectJ切入点,切入点表达式为"execution(* cn..chapter9.service..*.*(..))" 表示拦截 cn包以及子包下的chapter9.service包以及子包下的任何类和任何方法。
- <aop:advisor>:Advisor定义,其中切入点为serviceMethod,通知为txAdvice。从配置中可以看出,将对cn包以及子包下的chapter9.service包以及子包下的任何类的任何方法应用"txAdvice"通知指定的事务属性。
当调用save方式时将匹配到事务通知中定义的<tx:method name = "save"> 中指定的事务属性,而调用countAll方法时将匹配到事务通知中定义的"<tx:method name = "*">"中定义的事务属性。
声明式事务管理同样是通过AOP代理方式实现。利用环绕通知 TransactionInterceptor实现事务的开启和关闭。
<tx:advice id="……" transaction-manager="……"> <tx:attributes> <tx:method name="……" propagation=" REQUIRED" isolation="READ_COMMITTED" timeout="-1" read-only="false" no-rollback-for="" rollback-for=""/> …… </tx:attributes> </tx:advice>
- <tx:advice>: id用于指定此通知的名字,transaction-manager 用于指定事务管理器,默认的事务管理器名字为 "transactionManager"。
- <tx:method>:用于定义事务属性即相关联的方法名。
<tx:method>参数;
- name:定义与事务属性相关联的方法名,将对匹配的方法应用定义的事务属性,可以使用"*"通配符来匹配一组或者所有方法,如"save*" 将匹配以save开头的方法,而"*"将匹配所有方法。
- propagation:事务传播行为定义,默认为"REQUIRED",表示Required,其值可以通过TransactionDefinition的静态传播行为变量的"PROPAGATIOIN_"后边部分指定。如"TransactionDefinition.PROPAGATION_REQUIRED" 可以使用 "REQUIRED"指定。
- isolation:事务隔离级别定义;默认为"DEFAULT",其值可以通过TransactionDefinition的静态隔离级别变量的"ISOLATION_"后边部分指定,如"TransactionDefinition.ISOLATION_DEFAULT"可以使用"DEFAULT"指定。
- timeout:事务超时时间设置,单位为秒,默认 -1,表示事务超时将依赖于底层事务系统。
- read-only:事务只读设置,默认为false,表示不是只读。
- rollback-for:需要出发回滚的异常定义,以","分割,默认任何RuntimeException将导致事务回滚,而任何CheckedException 将不导致事务回滚;异常名字定义和TransactionProxyFactoryBean中含义一样。
什么是多事务语义?说白了就是为不同的Bean配置不同的事务属性,因为我们项目中不可能就几个Bean,而可能很多,这可能需要为Bean分组,为不同组的Bean配置不同的事务语义。在Spring中,可以通过配置多切入点和多事务通知并通过不同方式组合使用即可。
<tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="create*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="merge*" propagation="REQUIRED" /> <tx:method name="del*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="put*" propagation="REQUIRED" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> <tx:method name="count*" propagation="SUPPORTS" read-only="true" /> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="list*" propagation="SUPPORTS" read-only="true" /> <tx:method name="*" propagation="SUPPORTS" read-only="true" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="txPointcut" expression="execution(* cn.javass..service.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" /> </aop:config>
该声明式事务配置可以应付常见的CRUD接口定义,并实现事务管理,我们只需修改切入点表达式来拦截我们的业务实现从而对其应用事务属性就可以了,如果还有更复杂的事务属性直接添加即可,即:
如果我们有一个batchSaveOrUpdate方法需要“REQUIRES_NEW”事务传播行为,则直接添加如下配置即可:
<tx:method name="batchSaveOrUpdate" propagation="REQUIRES_NEW" />
<tx:advice id="noTxAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="*" propagation="NEVER" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="noTxPointcut" expression="execution(* cn.javass..util.*.*())" /> <aop:advisor advice-ref="noTxPointcut" pointcut-ref="noTxAdvice" /> </aop:config>该声明将对切入点匹配的方法所在事务应用"Never"传播行为。多事务语义配置时,切入点一定不要叠加,否则将应用两次事务属性,造成不必要的麻烦和错误。
五. @Transactional实现事务管理
对声明式事务管理,Spring提供基于@Transactional注解方式来实现,但需要Java 5+。注解方式是最简单的事务配置方式,可以直接在Java源代码中声明事务属性,且对于每一个业务类或方法如果需要事务都必须使用此注解。接下来学习一下注解事务的使用吧:
1、定义业务逻辑实现:
package cn.javass.spring.chapter9.service.impl; //省略import public class AnnotationUserServiceImpl implements IUserService { private IUserDao userDao; private IAddressService addressService; public void setUserDao(IUserDao userDao) { this.userDao = userDao; } public void setAddressService(IAddressService addressService) { this.addressService = addressService; } @Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITTED) @Override public void save(final UserModel user) { userDao.save(user); user.getAddress().setUserId(user.getId()); addressService.save(user.getAddress()); } @Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITTED, readOnly=true) @Override public int countAll() { return userDao.countAll(); } }
package cn.javass.spring.chapter9.service.impl; //省略import public class AnnotationUserServiceImpl implements IUserService { private IUserDao userDao; private IAddressService addressService; public void setUserDao(IUserDao userDao) { this.userDao = userDao; } public void setAddressService(IAddressService addressService) { this.addressService = addressService; } @Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITTED) @Override public void save(final UserModel user) { userDao.save(user); user.getAddress().setUserId(user.getId()); addressService.save(user.getAddress()); } @Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITTED, readOnly=true) @Override public int countAll() { return userDao.countAll(); } }
2、定义配置文件(chapter9/service/ applicationContext-service-annotation.xml):
2.1、XML命名空间定义,定义用于事务支持的tx命名空间和AOP支持的aop命名空间:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
2.2、业务实现配置,非常简单,使用以前定义的非侵入式业务实现:
<bean id="userService" class="cn.javass.spring.chapter9.service.impl.ConfigUserServiceImpl"> <property name="userDao" ref="userDao"/> <property name="addressService" ref="addressService"/> </bean> <bean id="addressService" class="cn.javass.spring.chapter9.service.impl.ConfigAddressServiceImpl"> <property name="addressDao" ref="addressDao"/> </bean>
2.3、事务相关配置:
<tx:annotation-driven transaction-manager="txManager"/>
六. @Transactional配置详解
Spring提供的<tx:annotation-driven/>用于开启对注解事务管理的支持,从而能识别Bean类上的@Transactional注解元数据,其具有以下属性:
- transaction-manager:指定事务管理器名字,默认为transactionManager,当使用其他名字时需要明确指定;
- proxy-target-class:表示将使用的代码机制,默认false表示使用JDK代理,如果为true将使用CGLIB代理
- order:定义事务通知顺序,默认Ordered.LOWEST_PRECEDENCE,表示将顺序决定权交给AOP来处理。
Spring使用@Transaction来指定事务属性,可以在接口、类或方法上指定,如果类和方法上都指定了@Transaction,则方法上的事务属性被优先使用,具体属性如下:
- value:指定事务管理器名字,默认使用<tx:annotation-driven/>指定的事务管理器,用于支持多事务管理器环境;
- propagation:指定事务传播行为,默认为Required,使用Propagation.REQUIRED指定;
- isolation:指定事务隔离级别,默认为“DEFAULT”,使用Isolation.DEFAULT指定;
- readOnly:指定事务是否只读,默认false表示事务非只读;
- timeout:指定事务超时时间,以秒为单位,默认-1表示事务超时将依赖于底层事务系统;
- rollbackFor:指定一组异常类,遇到该类异常将回滚事务;
- rollbackForClassname:指定一组异常类名字,其含义与<tx:method>中的rollback-for属性语义完全一样;
- noRollbackFor:指定一组异常类,即使遇到该类异常也将提交事务,即不回滚事务;
- noRollbackForClassname:指定一组异常类名字,其含义与<tx:method>中的no-rollback-for属性语义完全一样;
Spring提供的@Transaction注解事务管理内部同样利用环绕通知TransactionInterceptor实现事务的开启及关闭。
使用@Transaction注解事务管理需要特别注意以下几点:
- 如果在接口、实现类或方法上都指定了@Transactional 注解,则优先级顺序为方法>实现类>接口;
- 建议只在实现类或实现类的方法上使用@Transactional,而不要在接口上使用,这是因为如果使用JDK代理机制是没问题,因为其使用基于接口的代理;而使用使用CGLIB代理机制时就会遇到问题,因为其使用基于类的代理而不是接口,这是因为接口上的@Transactional注解是“不能继承的”;
- 在JDK代理机制下,“自我调用”同样不会应用相应的事务属性,其语义和<tx:tags>中一样;
- 默认只对RuntimeException异常回滚;
- 在使用Spring代理时,默认只有在public可见度的方法的@Transactional 注解才是有效的,其它可见度(protected、private、包可见)的方法上即使有@Transactional 注解也不会应用这些事务属性的,Spring也不会报错,如果你非要使用非公共方法注解事务管理的话,可考虑使用AspectJ。
Ps:混合事务
混合事务管理就是混合多种数据访问技术使用,如混合使用Spring JDBC + Hibernate,接下来让我们学习一下常见混合事务管理:
- Hibernate + Spring JDBC/iBATIS:使用HibernateTransactionManager即可支持;
- JPA + Spring JDBC/iBATIS:使用JpaTransactionManager即可支持;
- JDO + Spring JDBC/iBATIS:使用JtaTransactionManager即可支持;
混合事务管理最大问题在于如果我们使用第三方ORM框架,如Hibernate,会遇到一级及二级缓存问题,尤其是二级缓存可能造成如使用Spring JDBC和Hibernate查询出来的数据不一致等。
因此不建议使用这种混合使用和混合事务管理。
- Spring(三): 事务
- spring声明式事务(三)
- Spring事务之三(DriverManagerDataSource)
- spring事务管理(三)--用BeanNameAutoProxyCreator自动创建事务代理
- Spring的四种事务管理(一种编程式事务+三种声明事务)<学习随笔>
- 脱离 Spring 实现复杂嵌套事务,之三(REQUIRES_NEW - 独立事务)
- Spring的四种事务管理(一种编程式事务+三种声明事务)<学习随笔>
- 【SSH】Spring学习(三)Spring整合JDBC、Spring中AOP事务
- spring的三种事务配置方式
- iBATIS&Spring合奏(三)--事务&动态SQL
- Spring事务以及三大框架整合
- Spring+SpringMVC+mybatis+easyui整合实例(三)spring mvc整合及mybatis事务部分
- 数据库事务(三)
- 框架(三)事务
- 数据库事务(三)
- spring(1) spring事务
- Spring事务(一)
- Mybatis事务(三)事务工厂
- 【小熊刷题】Two Sum II - sorted array
- muduo::EventLoopThread、EventLoopThreadPool分析
- Android下创建一个SQLite数据库
- Javascript高级程序设计第八九章
- 元素查找
- Spring(三): 事务
- 欢迎使用CSDN-markdown编辑器
- 巨幕和徽章
- poj 3620 Avoid The Lakes
- Java学习笔记(十)collections框架概述
- 初学OC控件拖动操作
- Android复习笔记(12)- listView的使用
- C语言变量类型
- Coins(2015嘉杰信息杯+dp)