@boothsun
2018-04-03T08:32:19.000000Z
字数 2619
阅读 1377
Spring
参考文章
1. spring事物配置,声明式事务管理和基于@Transactional注解的使用
2. 尚硅谷 佟刚 Spring视频教程PPT
编程式事务管理是指在代码里通过Spring API手动控制事务的提交和回滚。
声明式事务管理是建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或加入一个事务,在执行完目标方法之后根据执行情况提交或回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。
显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。
声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
事务的传播行为可以有传播属性指定。Spring定义了7种传播行为。
事务传播属性可以在 @Transactional 注解的 propagation 属性中定义
从理论上来说,事务应该彼此完全隔离,以避免并发事务所导致的问题;然后,那样会对性能产生极大的影响,因为事务必须按串行运行。通常,在实际开发中,为了提升性能,事务会以较低的隔离级别运行。
Spring支持的事务隔离级别:
事务的隔离级别要得到底层数据库引擎的支持,而不是应用程序或者框架支持。
设置事务隔离属性:
用@Transactional
注解声明式地管理事务时可以在@Transactional
的isolation
属性中设置隔离级别。
在Spring 2.X 事务通知中,可以在<tx:method>
元素中指定隔离级别。
默认情况下只有未检查异常(RuntimeException和Error类型的异常)会导致事务回滚,而受检查异常不会。
事务的回滚规则可以通过@Transactional
注解的rollbackFor
和noRollbackFor
属性来定义,这两个属性被声明为 Class[] 类型的,因此可以为这两个属性指定多个异常类。
rollbackFor
遇到时必须进行回滚:在Spring2.X 事务通知中,可以在<tx:method>
元素中指定回滚规则。如果有不止一种异常,用逗号分隔。
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在TransactionDefinition中以int的值来表示超时时间,其单位是秒。
默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那就是none,没有超时限制。
只读事务用于客户端代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候,默认为读写事务。
“只读事务”并不是一个强制选项,它只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。
但是你非要在“只读事务”里面修改数据,也并非不可以,只不过对于数据一致性的保护不像“读写事务”那样保险而已。
因此,“只读事务”仅仅是一个性能优化的推荐配置而已,并非强制你要这样做不可。
事务超时与事务只读属性设置:
超时和只读属性可以在 @Transactional 注解中定义,超时属性以秒为单位来计算:
在 Spring 2.x 事务通知中,超时和只读属性可以在 元素中进行指定。
@Transactional
可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。
虽然@Transactional
注解可以作用于接口、接口方法、类以及类方法上,但是Spring建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外,@Transactional
注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在protected
、private
或者默认可见性的方法上使用@Transactional
注解,这将被忽略,也不会抛出任何异常。
默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional
注解进行修饰。
Spring事务的本质其实就是对数据库事务的包装,往简单了说其实就是利用了AOP在事务操作前调用了conn.setAutoCommit
,事务操作结束时调用了conn.commit();
。
Connection conn = DriverManager.getConnection();
try {
conn.setAutoCommit(false); //将自动提交设置为false
执行CRUD操作
conn.commit(); //当两个操作成功后手动提交
} catch (Exception e) {
conn.rollback(); //一旦其中一个操作出错都将回滚,所有操作都不成功
e.printStackTrace();
} finally {
conn.colse();
}
Spring 事务就是利用AOP特性,将上述代码进行了封装隐藏。