spring事物配置,声明式事务管理和基于@Transactional注解的使用 [转]

spring支持编程式事务管理和声明式事务管理两种方式。java

   编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。node

        声明式事务管理创建在AOP之上的。其本质是对方法先后进行拦截,而后在目标方法开始以前建立或者加入一个事务,在执行完目标方法以后根据执行状况提交或者回滚事务。声明式事务最大的优势就是不须要经过编程的方式管理事务,这样就不须要在业务逻辑代码中掺琐事务管理的代码,只需在配置文件中作相关的事务规则声明(或经过基于@Transactional注解的方式),即可以将事务规则应用到业务逻辑中。mysql

       显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就能够得到彻底的事务支持。和编程式事务相比,声明式事务惟一不足地方是,后者的最细粒度只能做用到方法级别,没法作到像编程式事务那样能够做用到代码块级别。可是即使有这样的需求,也存在不少变通的方法,好比,能够将须要进行事务管理的代码块独立为方法等等。程序员

         声明式事务管理也有两种经常使用的方式,一种是基于tx和aop名字空间的xml配置文件,另外一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。spring

spring事务特性sql

spring全部的事务管理策略类都继承自org.springframework.transaction.PlatformTransactionManager接口数据库

 

其中TransactionDefinition接口定义如下特性:express

事务隔离级别编程

  隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:数组

  • TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,一般这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务能够读取另外一个事务修改但尚未提交的数据。该级别不能防止脏读,不可重复读和幻读,所以不多使用该隔离级别。好比PostgreSQL实际上并无此级别。
  • TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另外一个事务已经提交的数据。该级别能够防止脏读,这也是大多数状况下的推荐值。
  • TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程当中能够屡次重复执行某个查询,而且每次返回的记录都相同。该级别能够防止脏读和不可重复读。
  • TransactionDefinition.ISOLATION_SERIALIZABLE:全部的事务依次逐个执行,这样事务之间就彻底不可能产生干扰,也就是说,该级别能够防止脏读、不可重复读以及幻读。可是这将严重影响程序的性能。一般状况下也不会用到该级别。

事务传播行为

      所谓事务的传播行为是指,若是在开始当前事务以前,一个事务上下文已经存在,此时有若干选项能够指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了以下几个表示传播行为的常量:

  • TransactionDefinition.PROPAGATION_REQUIRED:若是当前存在事务,则加入该事务;若是当前没有事务,则建立一个新的事务。这是默认值。
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:建立一个新的事务,若是当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_SUPPORTS:若是当前存在事务,则加入该事务;若是当前没有事务,则以非事务的方式继续运行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,若是当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,若是当前存在事务,则抛出异常。
  • TransactionDefinition.PROPAGATION_MANDATORY:若是当前存在事务,则加入该事务;若是当前没有事务,则抛出异常。
  • TransactionDefinition.PROPAGATION_NESTED:若是当前存在事务,则建立一个事务做为当前事务的嵌套事务来运行;若是当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

事务超时

      所谓事务超时,就是指一个事务所容许执行的最长时间,若是超过该时间限制但事务尚未完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

  默认设置为底层事务系统的超时值,若是底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。

事务只读属性

      只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,好比使用Hibernate的时候。
默认为读写事务。

spring事务回滚规则

     指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring事务管理器会捕捉任何未处理的异常,而后依据规则决定是否回滚抛出异常的事务。

 

@Transactional注解

                  @Transactional属性 

属性 类型 描述
value String 可选的限定描述符,指定使用的事务管理器
propagation enum: Propagation 可选的事务传播行为设置
isolation enum: Isolation 可选的事务隔离级别设置
readOnly boolean 读写或只读事务,默认读写
timeout int (in seconds granularity) 事务超时时间设置
rollbackFor Class对象数组,必须继承自Throwable 致使事务回滚的异常类数组
rollbackForClassName 类名数组,必须继承自Throwable 致使事务回滚的异常类名字数组
noRollbackFor Class对象数组,必须继承自Throwable 不会致使事务回滚的异常类数组
noRollbackForClassName 类名数组,必须继承自Throwable 不会致使事务回滚的异常类名字数组

用法

       @Transactional 能够做用于接口、接口方法、类以及类方法上。看成用于类上时,该类的全部 public 方法将都具备该类型的事务属性,同时,咱们也能够在方法级别使用该标注来覆盖类级别的定义。

         虽然 @Transactional 注解能够做用于接口、接口方法、类以及类方法上,可是 Spring 建议不要在接口或者接口方法上使用该注解,由于这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。若是你在 protected、private 或者默承认见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

 

各类属性的意义: 

      REQUIRED:业务方法须要在一个容器里运行。若是方法运行时,已经处在一个事务中,那么加入到这个事务,不然本身新建一个新的事务。 

      NOT_SUPPORTED:声明方法不须要事务。若是方法没有关联到一个事务,容器不会为他开启事务,若是方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行。 

      REQUIRESNEW:无论是否存在事务,该方法总汇为本身发起一个新的事务。若是方法已经运行在一个事务中,则原有事务挂起,新的事务被建立。 

      MANDATORY:该方法只能在一个已经存在的事务中执行,业务方法不能发起本身的事务。若是在没有事务的环境下被调用,容器抛出例外。 

      SUPPORTS:该方法在某个事务范围内被调用,则方法成为该事务的一部分。若是方法在该事务范围外被调用,该方法就在没有事务的环境下执行。 

      NEVER:该方法绝对不能在事务范围内执行。若是在就抛例外。只有该方法没有关联到任何事务,才正常执行。 

      NESTED:若是一个活动的事务存在,则运行在一个嵌套的事务中。若是没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个能够回滚的保存点。内部事务的回滚不会对外部事务形成影响。它只对DataSourceTransactionManager事务管理器起效。

 

@Transactional注解注意的几点:

1 @Transactional 只能被应用到public方法上, 对于其它非public的方法,若是标记了@Transactional也不会报错,但方法没有事务功能.

2用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException("注释");)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到须要捕获的例外(throw new Exception("注释");)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需咱们指定方式来让事务回滚 要想全部异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .若是让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
以下:
@Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚
public void methodName() {
throw new Exception("注释");

}
@Transactional(noRollbackFor=Exception.class)//指定不回滚,遇到运行期例外(throw new RuntimeException("注释");)会回滚
public ItimDaoImpl getItemDaoImpl() {
throw new RuntimeException("注释");
}

三、@Transactional 注解应该只被应用到 public 可见度的方法上。 若是你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 可是这个被注解的方法将不会展现已配置的事务设置。


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


五、Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你固然能够在接口上使用 @Transactional 注解,可是这将只能当你设置了基于接口的代理时它才生效。由于注解是 不能继承 的,这就意味着若是你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,并且对象也将不会被事务代理所包装(将被确认为严重的)。因 此,请接受Spring团队的建议而且在具体的类上使用 @Transactional 注解。

 

下面就简单的看以下一个例子完整的配置文件

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"    
 3         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
 4         xmlns:p="http://www.springframework.org/schema/p"  
 5         xmlns:aop="http://www.springframework.org/schema/aop"   
 6         xmlns:context="http://www.springframework.org/schema/context"  
 7         xmlns:jee="http://www.springframework.org/schema/jee"  
 8         xmlns:tx="http://www.springframework.org/schema/tx"  
 9         xsi:schemaLocation="    
10             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd  
11             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd  
12             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
13             http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.2.xsd  
14             http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
15     <!-- 引入外部properties属性文件 -->
16     <context:property-placeholder location="classpath:jdbc.properties"/>
17     
18     <!-- 原理:自动注入processor解析器,用来解析注解 -->
19     <!-- 
20     <context:annotation-config/>
21      -->
22      
23     <!-- 自动扫描包,也会自动注入解释器,因此不须要 context:annotation-config-->
24     <context:component-scan base-package="news"/>
25     
26     <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
27         <!-- 注入链接池,包含了数据库用户名,密码等等信息 -->
28         <property name="dataSource" ref="myDataSource"/>
29         
30         <!-- 配置Hibernate的其余的属性 -->
31         <property name="hibernateProperties">
32             <props>
33                 <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
34                 <prop key="hibernate.show_sql">true</prop>
35                 <prop key="hibernate.format_sql">true</prop>
36                 <prop key="hibernate.connection.autocommit">false</prop>
37                 <!-- 开机自动生成表 -->
38                 <prop key="hibernate.hbm2ddl.auto">update</prop>
39             </props>
40         </property>
41         <property name="packagesToScan">
42             <list>
43                 <value>news.entity</value>
44             </list>
45         </property>
46         <!-- 
47         <property name="mappingResources">
48             <list>
49                 <value>news/entity/News.hbm.xml</value>
50             </list>
51         </property>
52          -->
53     </bean>    
54      
55     <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
56         <property name="driverClass" value="${jdbc_MySQL.driver}"/>
57         <property name="jdbcUrl" value="${jdbc_MySQL.url}"/>
58         <property name="user" value="${jdbc_MySQL.user}"/>
59         <property name="password" value="${jdbc_MySQL.password}"/>
60         <!-- 每300秒检查全部链接池中的空闲链接 -->
61         <property name="idleConnectionTestPeriod" value="300"></property>
62         <!-- 最大空闲时间,900秒内未使用则链接被丢弃。若为0则永不丢弃 -->
63         <property name="maxIdleTime" value="900"></property>
64         <!-- 最大链接数 -->
65         <property name="maxPoolSize" value="2"></property>
66     </bean>
67     
68     <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
69         <property name="sessionFactory" ref="sessionFactory"/>
70     </bean> 
71     
72     <!--启动spring事务注解功能-->
73     <tx:annotation-driven transaction-manager="transactionManager"/>
74     
75     <!-- 
76     <tx:advice id="txAdvice" transaction-manager="transactionManager">
77         <tx:attributes>
78             <tx:method name="add*" propagation="REQUIRED"/>
79             <tx:method name="del*" propagation="REQUIRED"/>
80             <tx:method name="mod*" propagation="REQUIRED"/>
81             <tx:method name="*" propagation="REQUIRED" read-only="true"/>
82         </tx:attributes>
83     </tx:advice>
84     
85     <aop:config>
86         <aop:pointcut expression="execution(* news.dao.*.*(..))" id="intercePointCuts"/>
87         <aop:advisor advice-ref="txAdvice" pointcut-ref="intercePointCuts"/>
88     </aop:config>
89     -->
90 </beans>
91             

如今就用注解方法来实现去掉一份实体类的映射文件

须要在applicationContext.xml这份配置文件里自动扫描具体实体类的包

 

实体类的注解配置以下所示:

使用Spring的AOP注解功能,必须导入以下几个包。aspectjrt.jar,aspectjweaver.jar,cglib-nodep.jar.

使用springAOP管理事务以后,在以前的DAO中须要把openSession获取会话的方式改成getCurrentSession

//Session session=sessionFactory.openSession();
Session session=sessionFactory.getCurrentSession();

openSession与getCurrentSession二者的区别:

1.getCurrentSession的方式会在事务结束时自动关闭链接,而openSession则须要手动关闭链接。

2.采用getCurrentSession建立的session会绑定带当前的线程中去,但openSession则不会。

采用@Transactional注解方式以下:

@Transactional    //放在这里表示类的全部方法都加入事务管理  
public class NewsServiceImpl implements NewsService{
  ······
} 
//也能够在单个方法上加注解
@Transactional(readOnly=true)    
public List showAllNews() {
  ······
}  

事务管理声明注解配置以下

以上xml文件配置的方法换为注解来实现,这里须要这样来配置:

还要配置一下实现注解功能

还能够是在具体的实现方法上加实现注解功能

 

下面来讲一下spring事务注解和xml文件实现注解的区别所在

这两种实现事务注解各有优点,只是看程序员的编码风格喜爱罢了,其中有的程序员喜爱spring事务注解编码风格,而有的程序员就偏好于xml文件实现注解功能固然我仍是比较偏好于xml文件来实现注解功能。

对于这两种都是实现事务注解来讲,spring事务注解编码风格相对就比较简单,但是它与spring框架耦合在一块儿了,对于以后的可维护性和可读性没那么好;而对于xml文件实现注解是与spring框架没有耦合在一块儿,以后的可维护性和可读性相对就好一点,但是编写的代码有点麻烦,还有就是实现的方法命名规范不能随意进行更改。

 

有关注解就写到这里,若是还要想深刻的去学习实现注解功能,但愿大家还要多点去

搜索网上关于注解的详细讲解,好好珍惜当今互联网的资源学习。 谢谢!

相关文章
相关标签/搜索