1.数据并发问题

  • 脏读
    A事务读取B事务尚未提交的更新数据,并在此数据的基础上操作。如果B事务回滚,则A事务读取的数据就是错误的。即读取了脏数据或者错误数据。
  • 不可重复组
    A事务先后读取了B事务提交【更新】之前和提交更新之后的数据,两者数据不一致。A和B读取同一个数据。
  • 幻象读
    A事务先后读取B事务提交【新增】之前和提交新增之后的数据,两者数据不一致。A和B读取的数据范围不一致,A读取范围大于B的。
  • 丢失更新
    A事务提交或回滚时,将B事务的更新操作覆盖。

2.spring事务管理api

Spring 框架中,涉及到事务管理的 API 大约有100个左右,其中最重要的有三个:TransactionDefinition、PlatformTransactionManager、TransactionStatus。所谓事务管理,其实就是“按照给定的事务规则来执行提交或者回滚操作”。“给定的事务规则”就是用 TransactionDefinition 表示的,“按照……来执行提交或者回滚操作”便是用 PlatformTransactionManager 来表示,而 TransactionStatus 用于表示一个运行着的事务的状态。

TransactionDefinition

用于定义一个事务。它包含了事务的静态属性,比如:事务传播行为、超时时间等等。

Spring 为我们提供了一个默认的实现类:DefaultTransactionDefinition,该类适用于大多数情况。如果该类不能满足需求,可以通过实现 TransactionDefinition 接口来实现自己的事务定义。

事务隔离级别

隔离级别是指若干个并发的事务之间的隔离程度。

TransactionDefinition 接口中定义了五个表示隔离级别的常量:

  • TransactionDefinition.ISOLATION_DEFAULT
    这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED
    该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
  • TransactionDefinition.ISOLATION_READ_COMMITTED
    该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
  • TransactionDefinition.ISOLATION_REPEATABLE_READ
    该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
  • TransactionDefinition.ISOLATION_SERIALIZABLE
    所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

事务传播行为

所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。

在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

  • TransactionDefinition.PROPAGATION_REQUIRED
    如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

  • TransactionDefinition.PROPAGATION_REQUIRES_NEW
    创建一个新的事务,如果当前存在事务,则把当前事务挂起。

  • TransactionDefinition.PROPAGATION_SUPPORTS
    如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED
    以非事务方式运行,如果当前存在事务,则把当前事务挂起。

  • TransactionDefinition.PROPAGATION_NEVER
    以非事务方式运行,如果当前存在事务,则抛出异常。

  • TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

  • TransactionDefinition.PROPAGATION_NESTED
    如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

这里需要指出的是,前面的六种事务传播行为是 Spring 从 EJB 中引入的,他们共享相同的概念。而 PROPAGATION_NESTED是 Spring 所特有的。

PROPAGATION_REQUIRES_NEW与PROPAGATION_NESTED区别
  • PROPAGATION_REQUIRES_NEW启动的事务是一个全新的独立事务,与外部事务无关(如果存在外部事务的话)。新事务提交和回滚,不影响外部事务;同时,外部事务的提交和回滚也不影响新事务。
  • 以 PROPAGATION_NESTED 启动的事务内嵌于外部事务中(如果存在外部事务的话),此时,内嵌事务并不是一个独立的事务,它依赖于外部事务的存在。只有通过外部的事务提交,才能引起内部事务的提交。如果外部事务回滚,内部事务必然回滚。但是,如果内部事务回滚,外部事务可以根据需要选择回滚或者执行其他的操作。

事务超时

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

事务的只读属性

事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。如果确定只对事务性资源进行只读操作,可以将事务标志为只读的,以提高事务处理的性能。

事务的回滚规则

默认情况下,如果在事务中抛出了未检查异常(继承自 RuntimeException 的异常),则将回滚事务。如果没有抛出任何异常,或者抛出了已检查异常,则仍然提交事务。可以配置事务在抛出某些未检查异常时依然提交事务,或者在抛出某些已检查异常时回滚事务。

PlatformTransactionManager

public interface PlatformTransactionManager {
	TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
	void commit(TransactionStatus status) throws TransactionException;
	void rollback(TransactionStatus status) throws TransactionException;
}

TransactionStatus

public interface TransactionStatus extends SavepointManager, Flushable {
	boolean isNewTransaction();
	boolean hasSavepoint();
	void setRollbackOnly();
	boolean isRollbackOnly();
	@Override
	void flush();
	boolean isCompleted();
}

3.声明式事务管理

Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

  • 基于 <tx><aop> 命名空间的声明式事务管理是目前推荐的方式,其最大特点是与 Spring AOP 结合紧密,可以充分利用切点表达式的强大支持,使得管理事务更加灵活。

  • 基于 @Transactional 的方式将声明式事务管理简化到了极致。开发人员只需在配置文件中加上一行启用相关后处理 Bean 的配置,然后在需要实施事务管理的方法或者类上使用 @Transactional 指定事务规则即可实现事务管理,而且功能也不必其他方式逊色。

参考资料:
IBM文档
博客

posted on 2017-01-05 19:37  漫夭  阅读(1266)  评论(0编辑  收藏  举报