1.概述

spring的事务注解@Transaction 相信很多人都用过,而@Transaction 默认配置适合80%的配置。

本篇文章不是对spring注解事务做详细介绍,而是解决一些实际场景下遇到的问题

spring事务注解的基本原理

下面针对是否需要开启事务和是否需要回滚事务在特定场景下的介绍

2.事务回滚

2.1 默认回滚策略

@Transactional
public void rollback() throws SQLException {
// update db
throw new SQLException("exception");
}

上述代码事务会回滚吗?不会的,就算抛出SQLException了,但是之前的数据库操作依然会提交,原因就是@Transactional默认情况下只回滚RuntimeException和Error。

2.2 指定回滚异常

因此,如果要指定哪些异常需要回滚,则通过配置@Transactional中rollbackFor,例如

@Transactional(rollbackFor = {SQLException.class})
public void rollback() throws SQLException {
// update db
throw new SQLException("exception");
}

按照上面例子,那指定的SQLException,当抛出RuntimeException的时候,还会回滚吗?

@Transactional(rollbackFor = {SQLException.class})
public void rollback() throws SQLException {
// update db
throw new Runtime("exception");
}

还是会回滚的。

2.3 事务嵌套的回滚

假设有下面的逻辑,事务会回滚吗(或者说 updateA,updateB,updateC)哪些更新会提交

@Transactional
public void rollback() {
// updateA
try{
selfProxy.innelTransaction()
}catch(RuntimeException e){
//do nothing
}
//updateC
} @Transactional
public void innelTransaction() throws SQLException {
// updateB
throw new RuntimeException("exception");
}

答案是会回滚,因为内部事务触发回滚,当前事务被标记为 rollback-only,

当外部事务提交的时候,Spring抛出以下异常,同时回滚外部事务

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
 

2.4 小结

所以,在需要事务回滚的时候,最好还是抛出RuntimeException,并且不要在代码中捕获此类异常

三、事务传播性

@Transaction中的propagation的可以配置事务的传播性,网上介绍的很多,就直接复制一段

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 (也是默认策略)
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

3.1 如何在事务中读取最新配置

有时候需要在一个事务中,读取最新数据(默认是读取事务开始前的快照)。其实很简单,只要使用上面PROPAGATION_NOT_SUPPORTED传播性就可以了。

@Transactional
public void transaction() throws SQLException {
// do something
selfProxy.queryNewValue();
} @Transactional(propagation = Propagation.NOT_SUPPORTED)
public void queryNewValue() throws SQLException {
//查询数据中的最新值

四、内部调用事务方法

事务注解的实质就是在创建一个动态代理,在调用事务方法前开启事务,在事务方法结束以后决定是事务提交还是回滚。

因此,直接在类内部中调用事务方法,是不会经过动态代理的

。 因此,如果要使方法B点事务生效,必须这样

4.1 解决办法

解决思路:需要在内部调用方法B的时候,找到当前类的代理类,用代理类去调用方法B

4.1.1 解决办法1

 
@Service
public class MyService{
@Transactional
public void transaction(){
// do something
((MyService) AopContext.currentProxy()).queryNewValue();
} @Transactional(propagation = Propagation.NOT_SUPPORTED)
public void queryNewValue(){
//查询数据中的最新值
}
}

通过AopContext.currentProxy()可以拿到当前类的代理类,但是要使用这个时候,必须在启动类上加上

@EnableAspectJAutoProxy(exposeProxy=true)

4.1.2 解决办法2

既然是要拿到当前代理类,那其实直接在Spring的容器里面去拿也可以啊。在spring中拿Bean的方法大致有2种

通过注入

@Service
public class MyService{
@Autowired
private MyService self;
@Transactional
public void transaction() {
// do something
self.queryNewValue();
} @Transactional(propagation = Propagation.NOT_SUPPORTED)
public void queryNewValue() {
//查询数据中的最新值
}
}

tips:spring现在对一些循环依赖是提供支持的,简单来说,满足:

  1. Bean是单例
  2. 注入的方式不是构造函数注入

通过BeanFactory

@Service
public class MyService implements BeanFactoryAware{
private MyService self; @Transactional
public void transaction(){
// do something
self.queryNewValue();
} @Transactional(propagation = Propagation.NOT_SUPPORTED)
public void queryNewValue() {
//查询数据中的最新值
} @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
self = beanFactory.getBean(MyService.class);
}
}

4.2 需要注意的地方

    • 使用@Transaction注解的方法,必须用public来修饰。
    • 其实不止是@Transaction,其他类似@Cacheable,@Retryable等依赖spring proxy也必须使用上述方式达到内部调用。
    • @Transactional,@Async放在同一个类中,如果使用Autowire注入会循环依赖,而使用BeanFactoryAware会使得@Transactional无效

关于spring事务注解实战的更多相关文章

  1. Spring事务注解分析

    1.使用spring事务注解 2.手写事务注解 1).sql执行器 2).事务注解定义 3).AOP实现事务具体实现(同一个线程中使用同一个连接) 4).应用使用注解前 5).应用使用注解后

  2. Spring事务管理者与Spring事务注解--声明式事务

    1.在Spring的applicationContext.xml中配置事务管理者 PS:具体的说明请看代码中的注释 Xml代码: <!-- 声明式事务管理的配置 --> <!-- 添 ...

  3. spring事务注解

    @Transactional只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能. Spring使用声明式事务处理,默认 ...

  4. Spring事务注解@Transactional失效的问题

    在项目中发现事务失效,使用@Transactional注解标注的Service业务层实现类方法全部不能回滚事务了,最终发现使用因为Spring与shiro进行整合之后导致的问题,将所有的Service ...

  5. 手动实现自己的spring事务注解

    spring事务是基于同一个数据连接来实现的,认识到这一点是spring事务的关键,spring事务的关键点便在于在事务中不管执行几次db操作,始终使用的是同一个数据库连接.通过查看源码,我们可以看到 ...

  6. 这一次搞懂Spring事务注解的解析

    前言 事务我们都知道是什么,而Spring事务就是在数据库之上利用AOP提供声明式事务和编程式事务帮助我们简化开发,解耦业务逻辑和系统逻辑.但是Spring事务原理是怎样?事务在方法间是如何传播的?为 ...

  7. Spring 事务注解 错误问题

    碰到个问题,在一个springmvc项目中,设置好事务,然后在service上添加@Transactional注解,只要一添加这个注解,该service就无法被spring创建成功, error cr ...

  8. Spring事务注解@Transactional回滚问题

    Spring配置文件,声明事务时,如果rollback-for属性没有指定异常或者默认不写:经测试事务只回滚运行时异常(RuntimeException)和错误(Error). <!-- 配置事 ...

  9. spring 事务注解

    在spring中使用事务需要遵守一些规范和了解一些坑点,别想当然.列举一下一些注意点. 在需要事务管理的地方加@Transactional 注解.@Transactional 注解可以被应用于接口定义 ...

随机推荐

  1. 常见dos命令总结

    常用的内部命令有MD.CD.RD.DIR.PATH.COPY.TYPE.EDIT.REN.DEL.CLS.VER.DATE.TIME.PROMPT. 常用的外部命令有DELTREE.FORMAT.DI ...

  2. mac攻略(4) -- 使用brew配置php7开发环境(mac+php+apache+mysql+redis)

    [http://www.cnblogs.com/redirect/p/6131751.html] 网上有很多文章都是错误的,因为是copy别人的,作者没有自己亲测,不仅不能给新手提供帮助,还会产生严重 ...

  3. 用最简单的例子实现jQuery图片即时上传

    [http://www.cnblogs.com/Zjmainstay/archive/2012/08/09/jQuery_upload_image.html] 最近看了一些jQuery即时上传的插件, ...

  4. 我的2017年终总结(PF项目框架设计心得分享 1.0rc new)

    一晃眼又过去了一年,在这一年里尽管有许多不如意的事,却阻挡不了我前进的脚步.先用一句话来总结去年一年的状态,那就是“无休无止的忙碌”.而这样的忙碌状态对我来说是不可取的,因为匮乏的忙碌只能让头脑处于一 ...

  5. 试着把.net的GC讲清楚(2)

    试着把.net的GC讲清楚(1) 上篇文章说了一些基本概念的东西,然后还有很多东西概念没有头绪,这篇文章我试着解释 GC的回收算法详细步骤? 上篇]文章讲了.net GC的算法是Mark and Co ...

  6. 搭建VUE项目的准备(利用vue-cli来构建项目)

    首先需要明确的是:Vue.js 不支持 IE8 及其以下 IE 版本,一般用与移动端,基础:开启最高权限的DOS命令(否则会出现意外的错误提示)   注意:个人小推荐如果我们不知道如何才能开启最高权限 ...

  7. 用Putty通过SSH访问Linux服务器

    1,sudo apt-get install ssh 2,sudo service ssh restart 3,重启ssh成功后,就可以直接用Putty访问服务器.

  8. 为什么要使用Docker?

    作为一种新兴的虚拟化方式,Docker跟传统的虚拟化方式相比具有众多的优势. 更高效的利用系统资源 由于容器不需要进行硬件虚拟及运行完整操作系统等额外开销,Docker对系统资源的利用率更高.无论是应 ...

  9. 老男孩Python全栈开发(92天全)视频教程 自学笔记09

    day9课程内容: 乌班图(ubuntu)64位系统 和 VMware 虚拟机安装(官网收费又麻烦,在网上找资源 安装vmware: vm运行(秘钥找度娘)--文件--新建虚拟机--自定义 下一步-- ...

  10. nyoj137 取石子(三) 楼教主男人八题之一

    思路:一堆时,N态.两堆时,当两堆数量相同,P态,不同为N态.三堆时,先手可以变成两堆一样的,必胜N态. 此时可以总结规律:堆数为偶数可能且石子数都是两两相同的,为P态.分析四堆时,当四堆中两两数量一 ...