事务的基本原理

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行:

  1. 获取连接 Connection con = DriverManager.getConnection()
  2. 开启事务con.setAutoCommit(true/false);
  3. 执行CRUD
  4. 提交事务/回滚事务 con.commit() / con.rollback();
  5. 关闭连接 conn.close();

使用Spring的事务管理功能后,我们可以不再写步骤 2 和 4 的代码,而是由Spirng 自动完成。
那么Spring是如何在我们书写的 CRUD 之前和之后开启事务和关闭事务的呢?解决这个问题,也就可以从整体上理解Spring的事务管理实现原理了。下面简单地介绍下,注解方式为例子

  1. 配置文件开启注解驱动,在相关的类和方法上通过注解@Transactional标识。
  2. spring 在启动的时候会去解析生成相关的bean,这时候会查看拥有相关注解的类和方法,并且为这些类和方法生成代理,并根据@Transaction的相关参数进行相关配置注入,这样就在代理中为我们把相关的事务处理掉了(开启正常提交事务,异常回滚事务)。
  3. 真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

    Spring的事务是如何回滚的

    spring的事务是由aop来实现的,首先要生成具体的代理对象,然后按照aop的整套流程来执行具体的操作逻辑,正常情况下要通过通知来完成核心功能,但是事务不是通过通知来实现的,而是通过一个TransactionInterceptor来实现的,然后调用invoke来实现具体的逻辑

分:1、先做准备工作,解析各个方法上事务相关的属性,根据具体的属性来判断是否开始新事务
2、当需要开启的时候,获取数据库连接,关闭自动提交功能,开起事务
3、执行具体的sql逻辑操作
4、在操作过程中,如果执行失败了,那么会通过completeTransactionAfterThrowing看来完成事务的回滚操作,回滚的具体逻辑是通过doRollBack方法来实现的,实现的时候也是要先获取连接对象,通过连接对象来回滚
5、如果执行过程中,没有任何意外情况的发生,那么通过commitTransactionAfterReturning来完成事务的提交操作,提交的具体逻辑是通过doCommit方法来实现的,实现的时候也是要获取连接,通过连接对象来提交
6、当事务执行完毕之后需要清除相关的事务信息cleanupTransactionInfo

Spring中的隔离级别

spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致:

  1. ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
    2. ISOLATION_READ_UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
    3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。 (会造成幻读、不可重复读),SQL server 的默认级别;
    4. ISOLATION_REPEATABLE_READ:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读 MySQL 的默认级别;
    ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,事务被处理为顺序执行。该隔离级别能防止脏读、不可重复读、幻读。

    Spring 管理事务的方式?

Spring支持两种类型的事务管理:

编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。

声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。


声明式事务又分为:
①基于XML的声明式事务
②基于注解的声明式事务

你更倾向用那种事务管理类型:

大多数Spring框架的用户选择声明式事务管理,因为它对应用代码的影响最小,因此更符合一个无侵入的轻量级容器的思想。声明式事务管理要优于编程式事务管理,虽然比编程式事务管理(这种方式允许你通过代码控制事务)少了一点灵活性。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。