深入理解分布式事务:原理与实战
上QQ阅读APP看书,第一时间看更新

3.1 Spring事务原理

Spring框架中支持对于事务的管理功能,开发人员使用Spring框架能够极大的简化对于数据库事务的管理操作。本节将对Spring事务的原理进行简单的介绍。

3.1.1 JDBC直接操作事务

从本质上讲,Spring事务是对数据库事务的进一步封装。也就是说,如果数据库不支持事务,Spring也无法实现事务操作。

使用JDBC通过事务的方式操作数据库的步骤如下。

第一步:加载JDBC驱动,代码如下。


Class.forName("com.mysql.jdbc.Driver");

第二步:建立与数据库的连接,后两个参数分别为账号和密码,代码如下。


Connection conn = DriverManager.getConnection(url, "root", "root");

第三步:开启事务,代码如下。


conn.setAutoCommit(true/false);

第四步:执行数据库的CRUD操作,代码如下。


PreparedStatement ps = con.prepareStatement(sql); 
//新增、修改、删除
ps.executeUpdate();
//查询
ps.executeQuery()

第五步:提交或者回滚事务,代码如下。


//提交事务
conn.commit();
//回滚事务
conn.rollback();

第六步:关闭连接,代码如下。


ps.close();
conn.close();

3.1.2 使用Spring管理事务

如果使用Spring的事务功能,则不必手动开启事务、提交事务和回滚事务,也就是不用再写3.1.1节中第三步和第五步中的代码。而是开启事务、提交事务和回滚事务的操作全部交由Spring框架自动完成,那么Spring是如何自动开启事务、提交事务和回滚事务的呢?

简单地说,就是在配置文件或者项目的启动类中配置Spring事务相关的注解驱动,在相关的类或者方法上标识@Transactional注解,即可开启并使用Spring的事务管理功能。

Spring框架在启动的时候会创建相关的bean实例对象,并且会扫描标注有相关注解的类和方法,为这些方法生成代理对象。如果扫描到标注有@Transactional注解的类或者方法时,会根据@Transactional注解的相关参数进行配置注入,在代理对象中会处理相应的事务,对事务进行管理。例如在代理对象中开启事务、提交事务和回滚事务。而这些操作都是Spring框架通过AOP代理自动完成的,无须开发人员过多关心其中的细节。

如下方法就使用了Spring的@Transactional注解管理事务。


@Transactional(rollbackFor=Exception)
Public void saveUser(User user){
    //省略保存用户的代码
}

3.1.3 Spring事务分类

通过Spring管理的事务可以分为逻辑事务和物理事务两大类。

1)逻辑事务:通常指通过Spring等框架管理的事务,这种事务是建立在物理事务之上的,比物理事务更加抽象。

2)物理事务:通常指的是针对特定数据库的事务。

Spring支持两种事务声明方式,分别是编程式事务和声明式事务。

1)编程式事务:如果系统需要明确的事务,并且需要细粒度的控制各个事务的边界,此时建议使用编程式事务。

2)声明式事务:如果系统对于事务的控制粒度较为粗糙,则建议使用声明式事务。

3.1.4 Spring事务超时

在实际工作中,对于某些性能要求比较高的应用,要求事务执行的时间尽可能短,此时可以给这些事务设置超时时间,一般事务的超时时间以秒为单位。如果事务的超时时间设置得过长,则与事务相关的数据就会被锁住,影响系统的并发性与整体性能。另外,因为检测事务超时的任务是在事务开始时启动的,所以事务超时机制对于程序在执行过程中会创建新事务的传播行为才有意义。需要注意的是,程序在执行过程中可能会创建新事务的传播类型有REQUIRED、REQUIRES_NEW、NESTED三种。

3.1.5 Spring事务回滚规则

使用Spring管理事务,可以指定在方法抛出异常时,哪些异常能够回滚事务,哪些异常不回滚事务。默认情况下,在方法抛出RuntimeException时回滚事务,也可以手动指定回滚事务的异常类型,代码如下。


@Transactional(rollbackFor?=?Exception.class)

这里需要注意的是,对于Spring事务,注解@Transactional中的rollbackFor属性可以指定Throwable异常类及其子类。