一:使用

本文在spring + spring mvc + mybatis中使用

第一步配置xml:注意xml最前面tx名称空间一定要配置

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 配置SqlSessionFactory对象 --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 注入数据库连接池--><property name="dataSource" ref="localdataSource"/><!-- 设置这个以后再Mapper配置文件中在parameterType的值就不用写成全路径名了 --><property name="typeAliasesPackage" value="com.qiqi.juint.model"/><!-- 扫描sql配置文件:mapper需要的xml文件--><property name="mapperLocations" value="classpath:mapper/*.xml"/></bean>
<!-- 配置事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- 注入数据库连接池--><property name="dataSource" ref="localdataSource"/></bean><!-- 配置基于注解的声明式事务 --><tx:annotation-driven transaction-manager = "transactionManager" />

在这里,由于org.mybatis.spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致,所以MyBatis自动参与到spring事务管理中,无需额外配置。

第二步:

在接口、接口方法、类以及类方法( public方法)上直接添加@Transactional即可。

注意:不要导错包,使用org.springframework.transaction.annotation.Transactional包,而不是javax.transaction.Transactional

当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性。在方法上使用该注解会覆盖类上的定义。

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

二:Spring事务回滚原则

Spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。

默认配置下,Spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException及其子类以及Errors,抛出checked异常则不会导致事务回滚。

可以明确的配置在抛出哪些异常时回滚事务,包括checked异常。例如:使用@Transactional(rollbackFor=IOException.class)

则抛出IOException异常时也可以回滚事务。也可以明确定义哪些异常抛出时不回滚事务,例如@Transactional(noRollbackFor = IOException.class)

还可以编程性的通过TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()方法来手动地指示一个事务必须回滚。

三:实例分析

Controller层:

@Controller
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping(value = "jsp1",method = RequestMethod.GET)public String getJsp( ){return "test";}@RequestMapping(value = "insertUser", method = RequestMethod.POST)public void insertUser(@RequestBody User user)throws Exception {userService.insertUser(user);}
}

Service层:

public interface UserService {void insertUser(User user)throws Exception;
}@Transactional
@Service
public class UserServiceImpl implements UserService {private static final Logger logger = Logger.getLogger(UserServiceImpl.class);@Autowiredprivate UserServiceTestTransactionImpl userServiceTestTransaction;@Autowiredprivate UserMapper userMapper;public void insertUser(User user) throws Exception{
//        try {userMapper.inserUser(new User(11,"格格A"));userServiceTestTransaction.insertUser(user);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }}
}@Transactional(RollbackFor = IOException.class)
@Service
public class UserServiceTestTransactionImpl {@Autowiredprivate UserMapper userMapper;public void insertUser(User user) throws Exception {userMapper.inserUser(user);throw new IOException();//throw new RuntimeException();//throw new Error();}
}

dao层不再展示。

注意:@Transactional注解默认的事务传播行为是REQUIRED。可以通过propagation 属性指定具体的传播行为。例如:@Transactional(rollbackFor = IOException.class ,propagation = Propagation.SUPPORTS)

这里简单介绍一下:PROPAGATION_REQUIRED。解释:在ServiceA.methodA中调用了ServiceB.methodB时,若ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED。如果ServiceA.methodA已经起了事务(有@Transactional注解),这时ServiceB.methodB就加入ServiceA.methodA的事务中,就不再起新的事务。而如果ServiceA.methodA运行的时候发现自己没有在事务中,ServiceA.methodA会为自己创建一个事务。这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被回滚。即使ServiceB.methodB的事务已经被提交,但是ServiceA.methodA在接下来fail要回滚时,ServiceB.methodB也要回滚。

本文验证了一下:UserServiceImpl(A)作为ServiceA,UserServiceTestTransactionImpl(B)作为ServiceB。

验证结果如下:

当UserServiceTestTransactionImpl(B)中的public方法抛出RuntimeException异常时。

若在UserServiceImpl(A)的方法中Try catch住异常

  • AB都有@Transtractional,B抛出RunTimeexception异常,AB都会回滚
  • A没有B有@Transtractional,B抛出RunTimeexception异常, A不会回滚 B回滚
  • A有B没有@Transtractional,B抛出RunTimeexception异常, AB都不会回滚(REQUIRED,B加入A的事务,但是被A捕获)

若没有在UserServiceImpl(A)的方法中Try catch住异常

  • A B都有@Transtractional, B抛出RunTimeexception异常,AB都会回滚
  • A没有B有@Transtractional, B抛出RunTimeexception异常 ,A不会回滚 B回滚
  • A有B没有@Transtractional ,B抛出RunTimeexception异常, AB都会回滚(REQUIRED,B加入A的事务,没有被A捕获)

总结:

可以发现,只要我们在Service层每一个类上都加上@Transtractional注解,即:每一个类均开启事务,不论是否捕获B抛出的异常,事务都会回滚。

当B由于自己没有事务而加入A的事务时(此时AB都在A的事务中),若A中没有捕获B抛出的异常,则AB都会回滚(这里证明了事务的传播规则REQUIRED的特性);此时若A中捕获了B抛出的异常,则事务失效,AB都不会回滚。

当A没有事务,而B存在事务时,由于A无法为自己开启事务,所以A会因为没有事务而不会回滚。B只存在自己的事务中,无论在A中是否被捕获异常,都会回滚,因为B在自己的事务中并没有捕获异常,而是抛出异常。

为什么捕获了异常,事务就不会回滚呢?

因为,Spring的声明式事务管理是基于AOP实现的。

具体原理如下:在应用系统调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常,利用抽象事务管理器AbstractPlatformTransactionManager 操作数据源 DataSource 提交或回滚事务。Spring AOP 代理有 CglibAopProxy 和 JdkDynamicAopProxy 两种。

而Spring aop 异常捕获原理是被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚。捕获异常后,aop就发现不了异常,进而不能回滚。

怎么避免:

方案一:保证所有涉及到的service类均加上事务

方案二:保证A有事务,在A中不要捕获异常,异常继续向上抛出

方案三:保证A有事务,并在其捕获异常后的cathch语句后面加上throw new RuntimeException()语句

方案四:保证A有事务,并在其捕获异常后的cathch语句后面加上TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()语句

Spring声明式事务管理中的事务回滚相关推荐

  1. Java中Spring中的方法加上try catch后事务管理器失效无法回滚的情况

    beab.xml配置 <bean id="dataSource" class="org.springframework.jdbc.datasource.Driver ...

  2. Spring声明式事务原理

    本文我们将通过一个简单的例子回顾Spring声明式事务的使用,并通过源码解读内部实现原理,最后通过列举一些常见事务不生效的场景来加深对Spring事务原理的理解. 1. 案例 新建SpringBoot ...

  3. 详细解读Spring2.5 +Struts1.3 框架(使用Spring声明式事物管理和springjjdbc模板)

    这个是我用Spring2.5 加Struts1.3搭建的一个web框架, 数据访问层使用springjdbc来访问数据库. 实现了SpringIOC容器维护bean和声明式事物管理. -------- ...

  4. mysql事务管理及spring声明式事务中主动异常抛出使数据库回滚

    mysql事务管理及spring声明式事务中主动异常抛出使数据库回滚 参考文章: (1)mysql事务管理及spring声明式事务中主动异常抛出使数据库回滚 (2)https://www.cnblog ...

  5. Spring声明式事务管理

    事务管理方式 1.编码方案 不建议使用,它具有侵入性.在原有的业务代码基础上去添加事务管理代码 2. 声明式事务控制,基于AOP对目标进行代理,添加around环绕通知. 这种方案,它不具有侵入性,不 ...

  6. Spring声明式事务管理、事务的传播行为xml配置

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 1. <tx:method name="insert*" propagat ...

  7. 【Spring学习笔记 九】Spring声明式事务管理实现机制

    什么是事务?事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用,关乎数据准确性的地方我们一定要用到事务,防止业务逻辑出错. 什么是事务管理,事务管理对于企业应用而言至 ...

  8. Spring声明式事务管理的配置详解

    环境配置 项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加方法: 点击项目右键->Build Path->Add ...

  9. Spring声明式事务管理实现及原理详解

    目录 1.实现步骤 1.1.配置事务管理器 1.2.启动事务注解 1.3.业务添加注解 2.代码演示 2.1.bean文件 2.2.目标类 2.3.测试类 3.Spring事务属性 3.1.传播行为 ...

最新文章

  1. 《Raspberry Pi用户指南》——2.4 使用外部存储设备
  2. linux用户层驱动--VFIO(四)
  3. 更新Composer依赖报错处理Fatal error: Declaration of Fxp\Composer\AssetPlugin\Repository\AbstractAssetsRe...
  4. python 柱形图_Python 写入 Excel III 详解图形生成-柱形图
  5. URL转码escape() encodeURI() encodeURIComponent()
  6. tensorflow 中的 array_ops
  7. Java中使用各种方式实现网页跳转
  8. WPF学习笔记(5):两个DataGrid的滚动条实现同步滚动(转)
  9. ai人工智能_相信AI?
  10. Cube IDE 的下载安装
  11. TCP粘包原因及解决办法
  12. 机器学习十大算法实现代码汇总(python)----线性回归、逻辑回归、决策树、支持向量机、朴素贝叶斯、K邻近算法、K-均值算法、随机森林、降低维度算法、梯度增强算法
  13. 可能是求质数最高效的算法
  14. python百度爬虫_Python爬虫 - 简单抓取百度指数
  15. 【无中生有】---14---用户行为监控系统嵌入
  16. 卡在硬盘启动计算机,插硬盘启动卡死了,怎么办?电脑维修方法
  17. 【Web前端】一文带你吃透HTML(完整篇)
  18. 椭圆曲线ECC倍点运算forJava
  19. 关于knife4j工具聚合api文档的使用
  20. Python基于face-alignment实现2D/3D人脸关键点检测

热门文章

  1. Excel中批量插入图片并对齐
  2. php 获取所有的下级组织,树形结构 查找上下级
  3. selenium+Java模拟鼠标操作
  4. linux rpm卸载包及其依赖,Linux下如何用rpm卸载软件 rpm依赖包强制卸载
  5. 火星发现神秘“地下水库”
  6. ES java 根据条件查询总数
  7. equalsIgnoreCase
  8. 网络中数据传输的理解
  9. html图标右上角添加小图标,图片右上角增加删除图标(css布局示例)
  10. PySpark算子处理空间数据全解析(2): 啥是算子(1):RDD