前几天灿哥问我,在做程序的时候,有没有考虑到事务,如果一个函数在中间执行过程中报错了,它会回滚么?我查了一查,spring确实有这样一个注解,能快速帮助我们配置事务管理。下面我就简单介绍一下这个注解。

  1、如何在spring中配置事务管理?为了使用@Transactional,我们需要在spring的配置文件中添加如下声明:

<beans:bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="entityManagerFactory" ref="entityManagerFactory" />
</beans:bean> <!-- 声明使用注解式事务 -->
<tx:annotation-driven transaction-manager="transactionManager" />

  dataSource是在Spring配置文件中定义的数据源的对象实例,entityManagerFactory是基于JPA使用的实体类管理器。这些都是用来配置与数据库的连接信息,本质上,@Transactional使用了JDBC的事务来进行事务控制的。<tx:annotation-driven>标签的声明,则是在Spring内部启用@Transactional来进行事务管理,类似开关。

  2、在spring中,我们通过上面的配置文件,简单的开启了事务,但是在实际的工作中,我们往往会遇到各种复杂的问题,这时候我们就需要了解更深层次的使用,我找了一下@Transactional这个注解的源码:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional { /**
* A qualifier value for the specified transaction.
* <p>May be used to determine the target transaction manager,
* matching the qualifier value (or the bean name) of a specific
* {@link org.springframework.transaction.PlatformTransactionManager}
* bean definition.
*/
String value() default ""; /**
* The transaction propagation type.
* Defaults to {@link Propagation#REQUIRED}.
* @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior()
*/
Propagation propagation() default Propagation.REQUIRED; /**
* The transaction isolation level.
* Defaults to {@link Isolation#DEFAULT}.
* @see org.springframework.transaction.interceptor.TransactionAttribute#getIsolationLevel()
*/
Isolation isolation() default Isolation.DEFAULT; /**
* The timeout for this transaction.
* Defaults to the default timeout of the underlying transaction system.
* @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()
*/
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT; /**
* {@code true} if the transaction is read-only.
* Defaults to {@code false}.
* <p>This just serves as a hint for the actual transaction subsystem;
* it will <i>not necessarily</i> cause failure of write access attempts.
* A transaction manager which cannot interpret the read-only hint will
* <i>not</i> throw an exception when asked for a read-only transaction.
* @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly()
*/
boolean readOnly() default false; /**
* Defines zero (0) or more exception {@link Class classes}, which must be a
* subclass of {@link Throwable}, indicating which exception types must cause
* a transaction rollback.
* <p>This is the preferred way to construct a rollback rule, matching the
* exception class and subclasses.
* <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class clazz)}
*/
Class<? extends Throwable>[] rollbackFor() default {}; /**
* Defines zero (0) or more exception names (for exceptions which must be a
* subclass of {@link Throwable}), indicating which exception types must cause
* a transaction rollback.
* <p>This can be a substring, with no wildcard support at present.
* A value of "ServletException" would match
* {@link javax.servlet.ServletException} and subclasses, for example.
* <p><b>NB: </b>Consider carefully how specific the pattern is, and whether
* to include package information (which isn't mandatory). For example,
* "Exception" will match nearly anything, and will probably hide other rules.
* "java.lang.Exception" would be correct if "Exception" was meant to define
* a rule for all checked exceptions. With more unusual {@link Exception}
* names such as "BaseBusinessException" there is no need to use a FQN.
* <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String exceptionName)}
*/
String[] rollbackForClassName() default {}; /**
* Defines zero (0) or more exception {@link Class Classes}, which must be a
* subclass of {@link Throwable}, indicating which exception types must <b>not</b>
* cause a transaction rollback.
* <p>This is the preferred way to construct a rollback rule, matching the
* exception class and subclasses.
* <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class clazz)}
*/
Class<? extends Throwable>[] noRollbackFor() default {}; /**
* Defines zero (0) or more exception names (for exceptions which must be a
* subclass of {@link Throwable}) indicating which exception types must <b>not</b>
* cause a transaction rollback.
* <p>See the description of {@link #rollbackForClassName()} for more info on how
* the specified names are treated.
* <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String exceptionName)}
*/
String[] noRollbackForClassName() default {}; }

  3、value配置

  value这里主要用来指定不同的事务管理器;主要用来满足在同一个系统中,存在不同的事务管理器。比如在Spring中,声明了两种事务管理器txManager1, txManager2.然后,用户可以根据这个参数来根据需要指定特定的txManager。那有你可能会问什么情况下会存在多个事务管理器的情况呢? 比如在一个系统中,需要访问多个数据源或者多个数据库,则必然会配置多个事务管理器的。

4、propagation配置   (传播)

  Propagation支持7种不同的传播机制:

  REQUIRED(必须的):业务方法需要在一个事务中运行,如果方法运行时,已处在一个事务中,那么就加入该事务,否则自己创建一个新的事务.这是spring默认的传播行为.。
  SUPPORTS(支持):如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分,如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行。
  MANDATORY(强制性的):只能在一个已存在事务中执行,业务方法不能发起自己的事务,如果业务方法在没有事务的环境下调用,就抛异常
  REQUIRES_NEW(要求是新的):业务方法总是会为自己发起一个新的事务,如果方法已运行在一个事务中,则原有事务被挂起,新的事务被创建,直到方法结束,新事务才结束,原先的事务才会恢复执行.
  NOT_SUPPORTED:声明方法需要事务,如果方法没有关联到一个事务,容器不会为它开启事务.如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行.
  NEVER:声明方法绝对不能在事务范围内执行,如果方法在某个事务范围内执行,容器就抛异常.只有没关联到事务,才正常执行.
  NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中.如果没有活动的事务,则按REQUIRED属性执行.它使用了一个单独的事务, 这个事务拥有多个可以回滚的保证点.内部事务回滚不会对外部事务造成影响, 它只对DataSourceTransactionManager 事务管理器起效。

5.   @Transactional之isolation
       隔离级别所要解决的问题是在应用程序中,存在多个事务同时在运行之时,需要解决和处理好的问题。那首先来看看,一般会出现哪些问题呢?先来看看吧。

  • 脏读(dirty read)

一个事物更新了数据库中的某些数据,另一个事物读取了这些数据,这时前一个事物由于某些原因回滚了,那么第二个事物读取的数据就是“脏数据”

  • 不可重复读(non-repeatable read)

一个事物需要两次查询同一数据,但两次查询中间可能有另外一个事物更改了这个数据,导致前一个事物两次读出的数据不一致。

  • 幻读 (phantom read)

一个事物两次查询同一个表,但两次查询中间可能有另外一个事物又向这个表中插入了一些新数据,导致前一个事物的两次查询不一致  
  下面来看看Spring中@Transactional中Isolation有具备的值:

  • DEFAULT  使用各个数据库默认的隔离级别
  • Read Uncommited :读未提交数据( 会出现脏读,不可重复读,幻读  )
  • Read Commited :读已提交的数据(会出现不可重复读,幻读)
  • Repeatable Read :可重复读(会出现幻读)
  • Serializable :串行化

其与事务中容易出现的问题对应关系具体如下:     

具体如何来设置具体的隔离界别,则依据业务系统具体可以容忍的程度而定。Serializable最为严格,然而效率最低;Read Uncommited效率最高,但是容易出现各种问题,中间的2个级别介于二者之间,故本质上是效率与出错概率的平衡与妥协。

6.    @Transactional之timeout

用于设置事务处理的时间长度,阻止可能出现的长时间的阻塞系统或者占用系统资源。单位为秒。如果超时设置事务回滚,并抛出TransactionTimedOutException异常。

spring事务超时 = 事务开始时到最后一个Statement创建时时间 + 最后一个Statement的执行时超时时间(即其queryTimeout)。

关于事务超时时间的计算可以参考:http://jinnianshilongnian.iteye.com/blog/1986023

7.   @Transactional之readOnly

默认情况下是false,可以显示指定为true, 告诉程序该方法下使用的是只读操作,如果进行其他非读操作,则会跑出异常;这个紧紧适用于只有readOnly标识的情况下,当其与propagation机制同时使用之时,则会出现只读设置被覆盖的情况,比如在required的情况下。在使用 REQUIRED 传播模式时,会抛出一个只读连接异常。使用 JDBC 时是这样。使用基于 ORM 的框架时,只读标志只是对数据库的一个提示,并且一条基于 ORM 框架的指令(本例中是 hibernate)将对象缓存的 flush 模式设置为 NEVER,表示在这个工作单元中,该对象缓存不应与数据库同步。不过,REQUIRED 传播模式会覆盖所有这些内容,允许事务启动并工作,就好像没有设置只读标志一样。

具体的详细内容可以参考: http://robinsoncrusoe.iteye.com/blog/825531

8.   @Transactional之rollbackForClassName/rollbackFor

Spring默认情况下会对运行期例外(RunTimeException)进行事务回滚。这个例外是unchecked,如果遇到checked意外就不回滚。

用来指明回滚的条件是哪些异常类或者异常类名。用法比较简单,这些不再赘述。

9.   @Transactional之noRollbackForClassName/noRollbackFor
       作用雷同于8, 用来指明在抛出特定异常的情况下,不进行数据库的事务回滚操作。

10. 总结

在针对@Transactional的各个属性进行详细分析之后,相信各位对他们具体的含义和应用场景有了一定的认识,使用起来便会不再那么迷茫和犹豫;非常感谢Spring给我们提供了这些便捷的事务管理方式,摆脱了繁琐的体力活,提升了开发的效率。

spring中的@Transactional注解的更多相关文章

  1. 对于spring中事务@Transactional注解的理解

    现在spring的配置都喜欢用注解,这边就说下@Transactional 一.如何开启@Transactional支持 要使用@Transactional,spring的配置文件applicatio ...

  2. [转]使用spring中的@Transactional注解时,可能需要注意的地方

    前情提要 在编写业务层方法时,会遇到很多需要事务提交的操作,spring框架为我们提供很方便的做法,就是在需要事务提交的方法上添加@Transactional注解,比起我们自己开启事务.提交以及控制回 ...

  3. 使用spring中的@Transactional注解时,可能需要注意的地方

    前情提要 在编写业务层方法时,会遇到很多需要事务提交的操作,spring框架为我们提供很方便的做法,就是在需要事务提交的方法上添加@Transactional注解,比起我们自己开启事务.提交以及控制回 ...

  4. Spring中的@Transactional

    spring中的@Transactional基于动态代理的机制,提供了一种透明的事务管理机制,方便快捷解决在开发中碰到的问题. 一般使用是通过如下代码对方法或接口或类注释: @Transactiona ...

  5. spring 事务-使用@Transactional 注解(事务隔离级别)

    转: spring 事务-使用@Transactional 注解(事务隔离级别) 2016年08月11日 21:49:20 华华鱼 阅读数 15490 标签: spring事务Transactiona ...

  6. Spring下面的@Transactional注解的讲解

    摘自: https://www.cnblogs.com/xiohao/p/4808088.html Spring下面的@Transactional注解标志的讲解 最近在开发中对Spring中的事务标记 ...

  7. Spring中的@Transactional必须要了解的概念

    spring中的@Transactional基于动态代理的机制,提供了一种透明的事务管理机制,方便快捷解决在开发中碰到的问题. 一般使用是通过如下代码对方法或接口或类注释: 1 @Transactio ...

  8. Spring中的@Transactional 放在 类级别 和 方法级别 上有什么不同?

    Spring中的@Transactional 放在类级别 和 方法级别 上有什么不同? @Transactional放在类级别上是否等同于该类的每个方法都放上了@Transactional? 是的一般 ...

  9. 第5章—构建Spring Web应用程序—关于spring中的validate注解后台校验的解析

    关于spring中的validate注解后台校验的解析 在后台开发过程中,对参数的校验成为开发环境不可缺少的一个环节.比如参数不能为null,email那么必须符合email的格式,如果手动进行if判 ...

随机推荐

  1. Educational Codeforces Round 82 C. Perfect Keyboard

    Polycarp wants to assemble his own keyboard. Layouts with multiple rows are too complicated for him ...

  2. debezium、kafka connector 解析 mysql binlog 到 kafak

    目的: 需要搭建一个可以自动监听MySQL数据库的变化,将变化的数据捕获处理,此处只讲解如何自动捕获mysql 中数据的变化 使用的技术 debezium :https://debezium.io/d ...

  3. 02-14Android学习进度报告十四

    今天我学习了关于构建一个可复用的自定义BaseAdapter的知识. 首先将Entity设置成泛型 代码示例: public class MyAdapter<T> extends Base ...

  4. iOS 混合开发之 Cordova 实践

    在15年时,之前公司使用 Cordova 做混合开发使用,后来公司没有用到了,现在重新记录下. Cordova (官网:http://cordova.apache.org/)简介: Apache Co ...

  5. css不起作用报错:Resource interpreted as Stylesheet but transferred with MIME type text/html

    解决:https://blog.csdn.net/sky_cui/article/details/86703706 找了好久........

  6. 使用Servlet处理AJAX请求

    AJAX用于异步更新页面的局部内容. ajax常用的请求数据类型 text    纯文本字符串 json    json数据 使用ajax获取text示例 此种方式常用于前端向后台查询实体的一个属性( ...

  7. extractvalue报错注入

    查看源码 $uagent = $_SERVER['HTTP_USER_AGENT']; ………… $uname = check_input($_POST['uname']); $passwd = ch ...

  8. 算法复杂度图示&JavaScript算法链接

    https://juejin.im/post/5c9a1d58e51d4559bb5c6694

  9. 02-05Android学习进度报告五

    今天主要学习了关于Android 开发的关于进度条和拖动条的知识. 主要学习了一些关于进度条的基本属性: android:max:进度条的最大值 android:progress:进度条已完成进度值 ...

  10. 实用类-<装箱与拆箱>

    装箱:把基本数据类型装换为对应的对象类 作用:1.在需要使用对象类型的时候,装换成对应的对象类型(集合里面) 2.转换完成以后,拥有相应的属性和方法,方便咱们的数据操作 拆箱 Integer intO ...