前言

我们都知道Spring给我们提供了很多抽象,比如我们在操作数据库的过程中,它为我们提供了事物方面的抽象,让我们可以非常方便的以事物方式操作数据库。不管你用JDBC、Mybatis、Hibernate等任何一种方式操作数据库,也不管你使用DataSource还是JTA的事物,Spring事物抽象管理都能很好的把他统一在一起。接下来看一下事物的抽象核心接口

Spring事务抽象

PlatformTransactionManager是事物管理器接口

//事务管理器接口有以下几个接口,获取事物信息,提交和回滚
public interface PlatformTransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException; void commit(TransactionStatus var1) throws TransactionException; void rollback(TransactionStatus var1) throws TransactionException;
}

常见的事物管理器有以下几种

  • DataSourceTransactionManager
  • HibernateTransactionManager
  • JtaTransactionManager

    这些管理器都实现了PlatformTransactionManager中的三个接口,实现逻辑略有差别,但是对用户来讲区别不大

定义事物的一些参数:

一些事物的参数在TransactionDefinition.java中,详情如下:

public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
//默认隔离级别,和数据库的隔离级别一致
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
//默认不超时
int TIMEOUT_DEFAULT = -1;
}

下面两张图对这些参数进行了说明:

7种事务传播特性:



四种事务隔离级别:

在看事务隔离级别前需要先了解下什么是脏读、不可重复读、幻读

脏读: 脏读就是一个事物未提交的数据,被另外一个事物读到了,显然这种情况不可接受

不可重复读: 不可重复读是指在一个事务内,多次读同一数据,前后读取的结果不一致。

幻读: 事务A对表中的一个数据进行了修改,这种修改涉及到表中的全部数据行。同时事务B也修改了这个表中的数据,这种修改是向表中插入一行新数据。那么就会发生操作事务A的用户发现表中还存在没有修改的数据行,就好像发生了幻觉一样

知道了以上几个概念,我们来看看隔离级别:

这里我们可以看到,Spring并不是提供了所有的事物管理的实现,而是提供了标准的事物管理器的操作接口PlatformTransactionManager, 并且规范了其行为,具体的事物实现由各个平台自行实现。这就是Spring的事物抽象。

Spring之编程式事物

Spring提供了TransactionTemplate工具类可以很方便的使用编程式事务。默认情况下TransactionTemplate使用的是DataSourceTransactionManager。

在Spring上下文中,我们不配置TransactionTemplate这个bean,也能获取到TransactionTemplate。比如下面的例子。

@Service
public class UserInfoService { @Resource
private UserInfoDAO userInfoDAO;
@Autowired
private TransactionTemplate transactionTemplate; public void updateUser1(){
transactionTemplate.execute(transactionStatus -> {
userInfoDAO.updateUserName(1,"zhangsanfeng");
transactionTemplate.execute(transactionStatus2 -> {
userInfoDAO.updateUserName(2,"lisi");
return null;
});
return null;
});
}
}

由于Spring默认的事物传播特性是PROPAGATION_REQUIRED,我们来做一下验证,看是不是这样





上面两幅图可以看出,TransactionStatus中的newTransaction属性,第一个是true,第二个是false,正好符合PROPAGATION_REQUIRED所描述的情况。其他的传播特性可以自己去验证。

声明式事物

除了编程式事物外,Spring还为我们提供了声明式事物。使用@Transactional注解。

@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该注解来覆盖类级别的定义。

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

@Transactional的rollbackFor属性可以设置一个 Throwable 的数组,用来表明如果方法抛出这些异常,则进行事务回滚。默认情况下如果不配置rollbackFor属性,那么事务只会在遇到RuntimeException的时候才会回滚。

下面的代码事物就不会生效:

    @Transactional
public void updateUser2() throws Exception {
int r1 = userInfoDAO.updateUserName(1,"wanger");
int r2 = userInfoDAO.updateUserName(2,"mawu");
if (r2==1){
throw new Exception();
}
}

如果我们把抛出的异常改成RuntimeException,这时候事物就会生效了。或者指定异常让事物生效,比如 @Transactional(rollbackFor = Exception.class),这样碰到所有的异常事物都会生效了。

为什么加了@Transactional注解事物就生效了?

这是因为Spring容器会为加了这个注解的对象生成一个代理对象,实际调用的时候,实际上是调用的代理对象。 代理对象的实现了AOP的增强,实现了事物的实现。

通过注解怎么实现指定的传播特性和隔离级别的?

public @interface Transactional {
@AliasFor("transactionManager")
String value() default ""; @AliasFor("value")
String transactionManager() default ""; String[] label() default {}; Propagation propagation() default Propagation.REQUIRED; Isolation isolation() default Isolation.DEFAULT; int timeout() default -1; String timeoutString() default ""; boolean readOnly() default false; Class<? extends Throwable>[] rollbackFor() default {}; String[] rollbackForClassName() default {}; Class<? extends Throwable>[] noRollbackFor() default {}; String[] noRollbackForClassName() default {};
}

代码中可以看出,我们可以指定隔离级别和传播特性,在Spring为我们生成代理类的时候,会读取这些属性,体现在增强逻辑中。

事物失效的8种情况及解决办法

数据库引擎不支持事务

这里以 MySQL 为例,其 MyISAM 引擎是不支持事务操作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用 InnoDB,这时候选择支持事物的数据库即可(好像是废话,哈哈哈)

没有被 Spring 管理

这个好像没什么可说的,脱离了Spring的管理,还谈什么Spring事物管理。

方法不是 public 的

@Transactional 只能用于 public 的方法上,否则事务不会失效,如果要用在非 public 方法上,可以开启 AspectJ 代理模式。

数据源没有配置事务管理器

相当于没开启事务管理,如果不是Springboot情况需要进行如下操作。

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}

如果是SpringBoot,在启动类上直接加上注解@EnableTransactionManagement即可。

传播特性配错了

传播特性配置成,Propagation.NOT_SUPPORTED或者Propagation.NOT_SUPPORTED,改成支持事物的传播特性即可。

异常类型错误

因为默认的异常类型是运行时异常,如果抛出了其他异常就不生效。

解决方式:

1、将异常改成运行时异常

2、指定异常进行事物回滚,如:@Transactional(rollbackFor = Exception.class)

异常被吃掉了

如果你代码这么写,事物不生效:

    @Transactional(rollbackFor = Exception.class)
public void updateUser2() {
int r1 = userInfoDAO.updateUserName(1,"3");
int r2 = userInfoDAO.updateUserName(2,"4");
if (r2==1){
throw new RuntimeException();
}
try { }catch (Exception e){ }
}

解决办法: 必须要抛出异常,否则Spring事务管理,不会走到回滚逻辑

类内部调用

@Service
public class UserInfoService {
public void justUpdate(){
updateUser2();
}
@Transactional(rollbackFor = Exception.class)
public void updateUser2() { }
}

上述代码不生效,因为内部调用不会涉及到代理类的调用,更不会有AOP的增强,因此不会生效。

解决办法:

1、自注入

@Service
public class UserInfoService {
@Autowired
private UserInfoService userInfoService;
public void justUpdate(){
userInfoService.updateUser2();
}
@Transactional(rollbackFor = Exception.class)
public void updateUser2() { }
}

2、Spring上下文

@Service
public class UserInfoService {
ApplicationContext applicationContext;
public void justUpdate(){
UserInfoService userInfoService = (UserInfoService) applicationContext.getBean("userInfoService");
userInfoService.updateUser2();
}
@Transactional(rollbackFor = Exception.class)
public void updateUser2() {
}
}

3、获取他的代理类,直接调用代理类

@Service
public class UserInfoService {
public void justUpdate(){
((UserInfoService) AopContext.currentProxy()).updateUser2();
}
@Transactional(rollbackFor = Exception.class)
public void updateUser2() {
}
}

----------------------------END---------------------------

更多Spring相关知识,请关注我,各平台都是同一个ID

Spring系列之事物是如何管理的的更多相关文章

  1. Spring中的事物管理----HelloWorld

    在学习Spring的事物管理之前明白先明白几个概念1什么是事物:事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用例子说明:例如银行转账,A账户转账(转2 ...

  2. Spring系列.事务管理

    Spring提供了一致的事务管理抽象.这个抽象是Spring最重要的抽象之一, 它有如下的优点: 为不同的事务API提供一致的编程模型,如JTA.JDBC.Hibernate和MyBatis数据库层 ...

  3. Spring系列之Spring常用注解总结 转载

    Spring系列之Spring常用注解总结   传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点:1.如果所有的内容都配置在.xml文件中,那么.x ...

  4. Spring系列(六):Spring事务源码解析

    一.事务概述 1.1 什么是事务 事务是一组原子性的SQL查询,或者说是一个独立的工作单元.要么全部执行,要么全部不执行. 1.2 事务的特性(ACID) ①原子性(atomicity) 一个事务必须 ...

  5. Spring 系列: Spring 框架简介 -7个部分

    Spring 系列: Spring 框架简介 Spring AOP 和 IOC 容器入门 在这由三部分组成的介绍 Spring 框架的系列文章的第一期中,将开始学习如何用 Spring 技术构建轻量级 ...

  6. Spring 系列: Spring 框架简介(转载)

    Spring 系列: Spring 框架简介 http://www.ibm.com/developerworks/cn/java/wa-spring1/ Spring AOP 和 IOC 容器入门 在 ...

  7. Spring系列

    Spring系列之访问数据库   阅读目录 一.概述 二.JDBC API的最佳实践 三.Spring对ORM的集成 回到顶部 一.概述 Spring的数据访问层是以统一的数据访问异常层体系为核心,结 ...

  8. 通俗化理解Spring3 IoC的原理和主要组件(spring系列知识二总结)

    ♣什么是IoC? ♣通俗化理解IoC原理 ♣IoC好处 ♣工厂模式 ♣IoC的主要组件 ♣IoC的应用实例 ♣附:实例代码 1.什么是IoC(控制反转)? Spring3框架的核心是实现控制反转(Io ...

  9. 【SSH框架】之Spring系列(一)

    微信公众号:compassblog 欢迎关注.转发,互相学习,共同进步! 有任何问题,请后台留言联系! 1.前言 前面更新过几篇关于 Struts2 框架和 Hibernate 框架的文章,但鉴于这两 ...

随机推荐

  1. POJ3662

    poj3662 大意:n个点p条边的无向图,求在删去k条边后使1和n号点联通路径上的最长边最小值. 一开始理解错题意以为是分层图求最短路径,结果写完发现k太大了发现事情没有那么简单(讨厌英语题面!) ...

  2. Select、Poll、Epoll IO复用技术

    简介 目前多进程方式实现的服务器端,一次创建多个工作子进程来给客户端提供服务, 但是创建进程会耗费大量资源,导致系统资源不足 IO复用技术就是让一个进程同时为多个客户端端提供服务 IO复用技术 之 S ...

  3. 斐波那契数列——Python实现

      # 功能:求斐波那契数列第 n 个数的值 # 在此设置 n n = 30 print('\n');print('n = ',n) # 代码生成 Fibonacci 序列,存于数组A A = [0] ...

  4. JIS-CTF_VulnUpload靶机

    仅供个人娱乐 靶机信息 下载地址:https://www.vulnhub.com/entry/jis-ctf-vulnupload,228/ 一.网卡设置 设置为NAT模式, 使用vi去修改/etc/ ...

  5. Dubbo 实现一个Route Factory(用于灰度发布)

    Dubbo 可以实现的扩展很多, 官方文档在这: https://dubbo.apache.org/zh/docs/v2.7/dev/impls/ (太简单了....) 下面我们实现一个Route F ...

  6. Ghost ,博客系统代名词

    Ghost 博客系统是前 WordPress 的一些优秀员工的创业项目.项目仍然采用 100% 开源,加上官方的收费托管的商业模式,目前已经发展成为一个非常的博客系统. 为了更好的方便读者理解 Gho ...

  7. UI_UE在线就业班(2)(Adobe Illustrator软件学习)

    Adobe Illustrator软件的使用     认识AIUI_UE在线就业班(2) .   ▼ AI是Adobe Illustrator的英文缩写,是Adobe公司旗下推出的一款基于矢量图形制作 ...

  8. 【LeetCode】316. 去除重复字母

    316. 去除重复字母 知识点:栈:单调 题目描述 给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次.需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置). 示例 输 ...

  9. oracle、postgres、mysql数据库的建库、创建用户、导人导出备份总结

    本文包含的内容:使用命令操作oracle.postgres.mysql的导入导出,登录到数据,创建用户 注:我在公司使用的是Center OS操作系统,所以oracle和postgres均是在Linu ...

  10. filter,interceptor,controllerAdvice,aspect,controller执行顺序

    1.filter,这是java的过滤器,和框架无关的,是所有过滤组件中最外层的,从粒度来说是最大的. 配置方式,有直接实现Filter+@component,@Bean+@configuration( ...