spring事务管理

来源:互联网 发布:同济大学 唐宇迪 知乎 编辑:程序博客网 时间:2024/05/16 17:51

关于事物隔离级别, 脏读, 不可重复读, 幻读的理解, 另有一篇文章比较生动的介绍:http://blog.csdn.net/sunxing007/article/details/6427290

spring事务管理相关的接口: 
TransactionDefinition:代表一个事物,描述了事务的隔离级别, 超时时间,事务是否只读, 传播规则等等;
TransactionStatus:描述事物的状态;
PlatformTransactionManager:事务管理器接口, 只定义了3个方法:getTransaction()获取事务的状态; commit();rollback(); PlatformTransactionManager是一个接口, 它的实现类需要根据具体的情况来选择, 比如如果用jdbc,则可以选择DataSourceTransactionManager, 如果用Hibernate, 可以选择HibernateTransactionManager;
事务管理器的实现类有多种,根据具体的持久层框架的不同而不同;
spring中的事务传播行为的种类:
PROPAGATION_REQUIRED: 如果当前没有事务,就创建一个事务;如果已经存在事务,则加入事务;
PROPAGATION_SUPPORTS: 如果已经存在事务,则加入事务;如果没有事务,则以非事务的方式执行;
PROPAGATION_MANDATORY: 使用当前事务, 如果没有, 则抛出异常;
PROPAGATION_REQUIRED_NEW: 动一个新的, 不依赖于环境的 "内部(如果是的话)"事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行
PROPAGATION_NOT_SUPPORTED:以非事务的方式执行, 如果当前有事务, 则挂起;
PROPAGATION_NEVER:以非事务的方式执行, 如果当前有事务,则抛出异常;
PROPAGATION_NESTED: 如果当前线程中没有事务, 则按照PROPAGATION_REQUIRED来执行; 如果当前线程中存在事务, 则开始一个 "嵌套的" 事务,  它是已经存在事务的一个真正的子事务.嵌套事务开始执行时,  它将取得一个 savepoint. 如果这个嵌套事务失败, 嵌套事务将回滚到此 savepoint.  外部事务可通过配置或捕获内部事务抛出的Exception来决定是回滚还是继续往下执行. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交, 外部事务回滚则内部事务也会回滚, 不管内部事务有没有提交.

关于PROPAGATION_NESTED和PROPAGATION_REQUIRED_NEW, 有一篇好文章, 我转载过来,防止原文被删除:http://blog.csdn.net/sunxing007/article/details/7743704

使用spring声明式的事务管理:
大多数情况下,事务会放在services层,spring声明式的事务管理中,需要做以下的工作:
1 把dao,service注入到spring容器(这些dao, service不涉及事务);
2 需要注入一个transactionManager(它需要dataSource);
3 通过TransactionProxyFactoryBean为目标对象(需要事务的dao, service等等)提供事务增强,产生增强后的代理对象.
看代码:
先添加一个CompanyService,

[java] view plaincopy
  1. package services;  
  2. import java.util.List;  
  3. import model.Company;  
  4. import dao.hibernate.CompanyDao;  
  5.   
  6. public class CompanyService {  
  7.  private CompanyDao companyDao;  
  8.  public CompanyDao getCompanyDao() {  
  9.   return companyDao;  
  10.  }  
  11.  public void setCompanyDao(CompanyDao companyDao) {  
  12.   this.companyDao = companyDao;  
  13.  }  
  14.  public void insertCompany(Company c){  
  15.   //some security check  
  16.   companyDao.save(c);  
  17.   //some updates  
  18.  }  
  19.  public void deleteCompany(int id){  
  20.   //some security check  
  21.   companyDao.deleteById(id);  
  22.   // some updates  
  23.  }  
  24.  public void updateCompany(Company c){  
  25.   companyDao.save(c);  
  26.  }  
  27.  public List list(){  
  28.   return companyDao.list();  
  29.  }  
  30. }  

它调用dao组件执行crud.事务控制一般都放在这一层.

spring事务管理第一种配置方式:为每个目标bean配置一个代理

[xhtml] view plaincopy
  1. <bean id="companyDao" class="dao.hibernate.CompanyDaoImpl">  
  2.  <property name="hibernateTemplate" ref="hibernateTemplate" />  
  3. </bean>  
  4. <!-- 需要被增强的bean通常命名为xxxxTarget -->  
  5. <bean id="companyServiceTarget" class="services.CompanyService">  
  6.  <property name="companyDao" ref="companyDao" />  
  7. </bean>  
  8. <!-- 事务管理器 -->  
  9. <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  10.  <property name="dataSource" ref="dataSource" />  
  11. </bean>  
  12. <!-- 被代理之后的service,它具有事务功能,程序中我们就使用它 -->  
  13. <bean id="companyService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">  
  14.  <!-- 事务管理器 -->  
  15.  <property name="transactionManager" ref="txManager" />  
  16.  <!-- 需要被代理的目标 -->  
  17.  <property name="target" ref="companyServiceTarget" />  
  18.  <!-- optimize可选,true代表使用CGLib, false代表使用jdk proxy -->  
  19.  <property name="optimize" value="true" />  
  20.  <!-- 事务属性, 顺序: PROPAGATION, ISOLATION, readOnly, -Exceptions, +Exceptions -->  
  21.  <property name="transactionAttributes">  
  22.   <props>  
  23.    <prop key="insert*">PROPAGATION_REQUIRED</prop>  
  24.    <prop key="update*">PROPAGATION_REQUIRED</prop>  
  25.    <prop key="delete*">PROPAGATION_REQUIRED</prop>  
  26.    <prop key="list">PROPAGATION_REQUIRED, readOnly</prop>  
  27.    <prop key="search*">PROPAGATION_REQUIRED, readOnly</prop>  
  28.   </props>  
  29.  </property>  
  30. </bean>  

测试:
[java] view plaincopy
  1. public class Test {  
  2.  public static void main(String[] args) throws InterruptedException, SQLException{  
  3.   ApplicationContext c = new ClassPathXmlApplicationContext("spring-test.xml");  
  4.   CompanyService s = (CompanyService)c.getBean("companyService");  
  5.   List list = s.list();  
  6.   System.out.println(list.size());  
  7.   s.insertCompany(new Company("www.ddd.com","ddd","wuhan"new Date()));  
  8. }}  

你会发现,这里的配置和前面讲的spring aop多么的相同,不错,他们的原理都是一样的,如果你没有了解过spring aop, 建议看一下。

通常情况下,service层需要的事务控制的配置大都相同,而且方法名大都是insertXXX, updateXXX, deleteXXX, searchXXX, checkXXX诸如此类,所以我们可以配置一个可复用的事务代理:

spring事务管理第二种配置方式:目标bean共享代理基类

[xhtml] view plaincopy
  1. <!-- abstract="true"标明它是抽象的 -->  
  2. <bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">  
  3.  <property name="transactionManager" ref="txManager" />  
  4.  <!-- target被注释掉 -->  
  5.  <!--property name="target" ref="companyServiceTarget" /-->  
  6.  <property name="transactionAttributes">   
  7.   <props>  
  8.    <prop key="insert*">PROPAGATION_REQUIRED</prop>  
  9.    <prop key="update*">PROPAGATION_REQUIRED</prop>  
  10.    <prop key="delete*">PROPAGATION_REQUIRED</prop>  
  11.    <prop key="list">PROPAGATION_REQUIRED, readOnly</prop>  
  12.    <prop key="search*">PROPAGATION_REQUIRED, readOnly</prop>  
  13.   </props>  
  14.  </property>  
  15. </bean>  
  16. <bean id="companyService" parent="baseTransactionProxy">  
  17.  <property name="target" ref="companyServiceTarget" />  
  18. </bean>  
  19. <bean id="otherService" parent="baseTransactionProxy">  
  20.  <property name="target" ref="otherServiceTarget" />  
  21. </bean>  
  22. ......  

虽然我们为需要事务增强的bean配置了代理类,但是难保用户还会直接使用目标对象companyServiceTarget; 可以使用拦截器.

spring事务管理第三种配置方式:使用拦截器

[xhtml] view plaincopy
  1. <!-- 配置一个事务拦截器,他对目标对象有事务增强的作用 -->  
  2. <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">  
  3.     <property name="transactionManager" ref="txManager" />  
  4.     <property name="transactionAttributes">    
  5.         <props>    
  6.             <prop key="*">PROPAGATION_REQUIRED</prop>    
  7.         </props>    
  8.     </property>    
  9. </bean>  
  10. <!-- 为目标对象自动创建代理 -->  
  11. <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">    
  12.     <property name="beanNames">  
  13.         <list>    
  14.             <value>companyServiceTarget</value>  
  15.         </list>    
  16.     </property>    
  17.     <property name="interceptorNames">    
  18.         <list>    
  19.             <value>transactionInterceptor</value>    
  20.         </list>    
  21.     </property>    
  22. </bean>  

测试:此时可以直接使用companyServiceTarget.

[java] view plaincopy
  1. public class Test {  
  2.     public static void main(String[] args) throws InterruptedException, SQLException{  
  3.         ApplicationContext c = new ClassPathXmlApplicationContext("spring-test.xml");  
  4.         //直接使用目标对象  
  5.         CompanyService s = (CompanyService)c.getBean("companyServiceTarget");  
  6.         List list = s.list();  
  7.         System.out.println(list.size());  
  8.         s.insertCompany(new Company("www.ddd.com","ddd","wuhan"new Date()));  
  9. }}  

spring事务管理第四种配置方式:使用tx命名空间

[xhtml] view plaincopy
  1. <tx:advice id="txAdvice" transaction-manager="txManager">  
  2.     <tx:attributes>  
  3.         <tx:method name="insert*" propagation="REQUIRED" />  
  4.         <tx:method name="update*" propagation="REQUIRED" />  
  5.         <tx:method name="delete*" propagation="REQUIRED" />  
  6.         <tx:method name="list" propagation="REQUIRED" read-only="true" />  
  7.     </tx:attributes>  
  8. </tx:advice>  
  9. <aop:config>  
  10.     <aop:pointcut id="interceptorPointCuts"  
  11.         expression="execution(* services.*Service(..))" />  
  12.     <aop:advisor advice-ref="txAdvice"  
  13.         pointcut-ref="interceptorPointCuts" />          
  14. </aop:config>  

使用tx命名空间还能对业务方法做更加细致的事务配置, 下面的表格摘自spring docs, 是一些可配置的参数列表和默认值:

AttributeRequired?DefaultDescriptionnameYes 

Method name(s) with which the transaction attributes are to be associated. The wildcard (*) character can be used to associate the same transaction attribute settings with a number of methods; for example,get*,handle*, on*Event, and so forth.

propagationNoREQUIREDTransaction propagation behavior.isolationNoDEFAULTTransaction isolation level.timeoutNo-1Transaction timeout value (in seconds).read-onlyNofalseIs this transaction read-only?rollback-forNo 

Exception(s) that trigger rollback; comma-delimited. For example,com.foo.MyBusinessException,ServletException.

no-rollback-for
No 

Exception(s) that do not trigger rollback; comma-delimited. For example,com.foo.MyBusinessException,ServletException


但是这种配置就需要把tx, aop的命名空间加入进来了:臭长臭长的。

[xhtml] view plaincopy
  1. <beans xmlns="http://www.springframework.org/schema/beans"   
  2.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.         xmlns:p="http://www.springframework.org/schema/p"   
  4.         xmlns:context="http://www.springframework.org/schema/context"  
  5.         xmlns:aop="http://www.springframework.org/schema/aop"  
  6.         xmlns:tx="http://www.springframework.org/schema/tx"  
  7.         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
  8.                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd  
  9.                 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
  10.                 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">  
  11. ......  
  12. </beans>  

例子:


<!-- 事务 -->
<tx:annotation-driven transaction-manager="jtaTransactionManager" />
<tx:advice id="jdbcTxAdvice" transaction-manager="jtaTransactionManager">
<tx:attributes>
<tx:method name="insert*" isolation="DEFAULT" propagation="REQUIRED" />
<tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" />
<tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" />
<tx:method name="del*" isolation="DEFAULT" propagation="REQUIRED" />
<tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED" />
<tx:method name="find*" read-only="true" />
<tx:method name="check*" read-only="true" />
<tx:method name="page*" read-only="true" />
<tx:method name="query*" read-only="true" />
<tx:method name="transaction" isolation="DEFAULT" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="jdbcTxServiceOperation" expression="execution(* com.cyou.nad.service.impl.*.*(..))" />
<aop:advisor pointcut-ref="jdbcTxServiceOperation" advice-ref="jdbcTxAdvice" />
</aop:config>


@Override
public void transaction(Integer id, String author, Integer point) throws Exception{
User source = userDao.findById(id);
User destination = userDao.findByName(author).get(0);
source.setPoint(source.getPoint()-point);
destination.setPoint(destination.getPoint()+point);
userDao.update(source);

/*        if(true){
        throw new RuntimeException("xxxxxxxxxxxx");  
//         throw new Exception("xxxxxxxxxx");
        }*/


userDao.update(destination);

   Transaction transaction = new Transaction();
transaction.setSourceId(source.getId());
transaction.setDestinationId(destination.getId());
transaction.setPoint(point);
transaction.setDealTime(new Date());
transactionDao.insert(transaction);
}



一、结论 
Spring的事务管理默认只对出现运行期异常(java.lang.RuntimeException及其子类)进行回滚。 
如果一个方法抛出Exception或者Checked异常,Spring事务管理默认不进行回滚。 
关于异常的分类一下详细介绍: 
1、基本概念 
看java的异常结构图
  
Throwable是所有异常的根,java.lang.Throwable 
Error是错误,java.lang.Error 
Exception是异常,java.lang.Exception 
2、Exception 
一般分为Checked异常和Runtime异常,所有RuntimeException类及其子类的实例被称为Runtime异常,不属于该范畴的异常则被称为CheckedException。 
①Checked异常 
只有java语言提供了Checked异常,Java认为Checked异常都是可以被处理的异常,所以Java程序必须显示处理Checked异常。如果程序没有处理Checked异常,该程序在编译时就会发生错误无法编译。这体现了Java的设计哲学:没有完善错误处理的代码根本没有机会被执行。


p表示对该bean里面的属性进行注入,格式为p:属性名=注入的对象效果与在bean里面使用<property>标签一样

spring事务管理第五种配置方式:注解

略...

0 0
原创粉丝点击