•在数据库操作中,事务是一个重要的概念。
•Spring的事务管理简化了传统的数据库事务管理流程,提高了开发效率。
•数据库编程是互联网编程的基础。
•Spring框架为开发者提供了JDBC模板模式,即jdbcTemplate,它可以简化许多代码。
•在实用中jdbcTemplate并不常用,更多的时候,是用Hibernate框架和MyBatis框架进行数据库编程。
•Spring数据库编程主要使用Spring JDBC模块的core和dataSource包。
–core包是JDBC的核心功能包,包括常用的JdbcTemplate类;
–dataSource包是访问数据源的工具类包。

•在代码中显式调用
beginTransaction()、
commit()、
rollback()
等事务处理相关的方法,就是编程式事务管理。
•当只有少数事务操作时,编程式事务管理才比较合适。
编程式事务管理方法允许你在对你的源代码编程的帮助下管理事务。这给了你极大地灵活性,但是它很难维护。
基于底层API的编程式事务管理

  • 基于底层API的编程式事务管理,是根据PlatformTransactionManager、TransactionDefinition和 TransactionStatus
    三个核心接口,通过编程的方式来进行事务处理。

    1. PlatformTransactionManager

    PlatformTransactionManager 接口是 Spring 提供的平台事务管理器,用于管理事务。该接口中提供了三个事务操作方法,具体如下。

  • TransactionStatus getTransaction(TransactionDefinition definition):用于获取事务状态信息。

  • void commit(TransactionStatus status):用于提交事务。
  • void rollback(TransactionStatus status):用于回滚事务。


在项目中,Spring 将 xml 中配置的事务详细信息封装到对象 TransactionDefinition 中,然后通过事务管理器的 getTransaction() 方法获得事务的状态(TransactionStatus),并对事务进行下一步的操作。

2. TransactionDefinition

TransactionDefinition 接口是事务定义(描述)的对象,它提供了事务相关信息获取的方法,其中包括五个操作,具体如下。

  • String getName():获取事务对象名称。
  • int getIsolationLevel():获取事务的隔离级别。
  • int getPropagationBehavior():获取事务的传播行为。
  • int getTimeout():获取事务的超时时间。
  • boolean isReadOnly():获取事务是否只读。


在上述五个方法的描述中,事务的传播行为是指在同一个方法中,不同操作前后所使用的事务。传播行为的种类如表 1 所示。

属性名称 描 述
PROPAGATION_REQUIRED required 支持当前事务。如果 A 方法已经在事务中,则 B 事务将直接使用。否则将创建新事务
PROPAGATION_SUPPORTS supports 支持当前事务。如果 A 方法已经在事务中,则 B 事务将直接使用。否则将以非事务状态执行
PROPAGATION_MANDATORY mandatory 支持当前事务。如果 A 方法没有事务,则抛出异常
PROPAGATION_REQUIRES_NEW requires_new 将创建新的事务,如果 A 方法已经在事务中,则将 A 事务挂起
PROPAGATION_NOT_SUPPORTED not_supported 不支持当前事务,总是以非事务状态执行。如果 A 方法已经在事务中,则将其挂起
PROPAGATION_NEVER never 不支持当前事务,如果 A 方法在事务中,则抛出异常
PROPAGATION.NESTED nested 嵌套事务,底层将使用 Savepoint 形成嵌套事务


在事务管理过程中,传播行为可以控制是否需要创建事务以及如何创建事务。

通常情况下,数据的查询不会改变原数据,所以不需要进行事务管理,而对于数据的增加、修改和删除等操作,必须进行事务管理。如果没有指定事务的传播行为,则 Spring3 默认的传播行为是 required。

3. TransactionStatus

TransactionStatus 接口是事务的状态,它描述了某一时间点上事务的状态信息。其中包含六个操作,具体如表 2 所示。

名称 说明
void flush() 刷新事务
boolean hasSavepoint() 获取是否存在保存点
boolean isCompleted() 获取事务是否完成
boolean isNewTransaction() 获取是否是新事务
boolean isRollbackOnly() 获取是否回滚
void setRollbackOnly() 设置事务回滚

基于TransactionTemplate的编程式事务管理

  • 事务处理的代码散落在业务逻辑代码中,破坏了原有代码的条理性,并且每一个业务方法都包含了类似的启动事务、提交以及回滚事务的样板代码。
  • TransactionTemplate的execute()方法有一个TransactionCallback接口类型的参数,该接口中定义了一个doInTransaction()方法,通常以匿名内部类的方式实现TransactionCallback接口,并在其doInTransaction()方法中书写业务逻辑代码。这里可以使用默认的事务提交和回滚规则,在业务代码中不需要显式调用任何事务处理的API。
  • doInTransaction()方法有一个TransactionStatus类型的参数,可以在方法的任何位置调用该参数的setRollbackOnly()方法将事务标识为回滚,以执行事务回滚。
  • 根据默认规则,如果在执行回调方法的过程中抛出了未检查异常,或者显式调用了setRollbackOnly()方法,则回滚事务;如果事务执行完成或者抛出了checked类型的异常,则提交事务。

+++++++++++++++
image.png
是这个导致一个有记录,一个无记录吗?
怎么调用setRollbackOnly()方法,谁(什么对象调用)调用,
=+++++++++++++++

声明式事务管理

  • Spring的声明式事务管理,是通过AOP技术实现的事务管理,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
  • 声明式事务管理最大的优点是不需要通过编程的方式管理事务,因而不需要在业务逻辑代码中掺杂事务处理的代码,只需相关的事务规则声明,便可以将事务规则应用到业务逻辑中。通常情况下,在开发中使用声明式事务处理,不仅因为其简单,更主要是因为这样使得纯业务代码不被污染,极大方便后期的代码维护。
  • Spring的声明式事务管理可以通过两种方式来实现,

    一是基于XML的方式,
    一是基于@Transactional注解的方式。

基于XML方式的声明式事务管理:

  • 基于XML方式的声明式事务管理是通过在配置文件中配置事务规则的相关声明来实现的。
  • Spring框架提供了tx命名空间来配置事务,元素来配置事务的通知。配置元素时,一般需要指定id和transaction-manager属性,其中id属性是配置文件中的唯一标识,transaction-manager属性指定事务管理器。另外,还需要子元素,该子元素可配置多个子元素指定执行事务的细节。
  • 元素配置了事务的增强处理后,就可以通过编写AOP配置,让Spring自动对目标对象生成代理。

在配置文件中,使用编写通知声明事务,使用编写AOP让Spring自动对目标对象生成代理。

  • 通过 标签来指定不同的事务性设置。默认的 设置如下:

–事务传播设置是 REQUIRED
–隔离级别是 DEFAULT
–事务是 读/写
–事务超时默认是依赖于事务系统的,或者事务超时没有被支持。
–任何 RuntimeException将触发事务回滚,但是任何 checkedException将不触发事务回滚。

属性 类型 默认值 说明
name

与事务属性关联的方法名。通配符()可以用来指定一批关联到相同的事务属性的方法。如:’get‘、’handle‘、’onEvent’等等。
propagation Propagation枚举 REQUIRED 事务传播属性
isolation isolation枚举 DEFAULT(所用数据库默认级别) 事务隔离级别
readOnly boolean false 事务是否只读(典型地,对于只执行查询的事务你会将该属性设为true,如果出现了更新、插入或是删除语句时只读事务就会失败)
timeout int -1 事务超时的时间(秒)
rollbackFor Class[] {} 需要回滚的异常类,以逗号分开。如:’com.foo.MyBusinessException,ServletException’
rollbackForClassName String[] {} 需要回滚的异常类名
noRollbackFor Class[] {} 不需要回滚的异常类,以逗号分开。如:’com.foo.MyBusinessException,ServletException’
noRollbackForClassName String[] {} 不需要回滚的异常类名

基于@Transactional注解的声明式事务管理

  • @Transactional注解可以作用于接口、接口方法、类以及类方法上。
  • 当作用于类上时,该类的所有public方法将都具有该类型的事务属性,同时,也可以在方法级别使用该注解来覆盖类级别的定义。
  • 虽然@Transactional注解可以作用于接口、接口方法、类以及类方法上,但是Spring小组建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。

如何在事务处理中捕获异常

  • 声明式事务处理的流程:

(1)Spring根据配置完成事务定义,设置事务属性。
(2)执行开发者的逻辑代码。
(3)如果开发者的代码产生异常,并且满足事务回滚的配置条件,则事务回滚,否则提交。
(4)事务资源释放。

  • 如果开发者代码逻辑中加入了try…catch…语句,Spring在声明式事务处理中便不能正常得到事务回滚的异常信息。

如果使用try…catch…语句,事务开始后出现异常前执行的语句回仍然有效(即不发生回滚)。
•Spring只在发生未捕获的RuntimeException时才回滚事务。
•在基于XML方式的声明式事务管理中捕获异常
(1)修改声明事务的配置
将XMLstatementapplicationContext.xml文件中的代码“”修改为


(2)在catch语句中添加“throw new RuntimeException();”语句。

•在基于@Transaction注解的声明式事务管理中捕获异常
(1)修改@Transactional注解
@Transactional(rollbackFor = { Exception.class })
//rollbackFor指定回滚生效的异常类
//noRollbackFor指定回滚失效的异常类
(2)也需要在catch语句中添加“throw new RuntimeException();”语句
•注意:在实际工程应用中,经常在catch语句中添加“TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();”语句,也就是说,不需要在XML配置文件tx:method元素中添加rollback-for属性或在@Transactional注解中添加rollbackFor属性。