事务介绍
数据库事务是指一个业务单元执行的一系列操作,这些操作要么一起成功,要么一起失败,是一个不可分割的一个整体。最典型的案例就是转账:
张三要给李四转账 100 块钱,这里涉及到两个操作,从张三的账户上减去 100 块钱,给李四的账户添加 100 块钱,这两个操作要么同时成功,要么同时失败;如何确保他们同时成功或者同时失败呢?就是需要事务。
事务有四大特性(ACID):
- 原子性(Atomicity): 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成。
- 一致性(Consistency): 在事务开始之前和事务结束以后,数据库的完整性没有被破坏。
- 隔离性(Isolation): 数据库允许多个并发事务同时对其数据进行读写操作,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
- 持久性(Durability): 事务处理结束后,对数据的修改就是永久的。
Spring事务的三大核心类
基于 Spring 5.1.9 版本 的分析
1. PlatformTransactionManager 事务管理器:
定义如下,具体由不同的子类来实现:
public interface PlatformTransactionManager {
// TransactionDefinition 中定义了一些事务的基本规则, 如传播性、隔离级别等
TransactionStatus getTransaction(@Nullable TransactionDefinition definition);
// 用来提交事务
void commit(TransactionStatus status) throws TransactionException;
// 用来回滚事务
void rollback(TransactionStatus status) throws TransactionException;
}
PlatformTransactionManager
(事务管理器)是事务处理的核心,它有诸多的实现类。
- 使用
JDBC
的实现类DataSourceTransactionManager
- 使用
Hibernate
的实现类HibernateTransactionManager
- 使用
JPA
的实现类JpaTransactionManager
2. TransactionDefinition 事务规则类
TransactionDefinition
用来描述事务的具体规则,也称作事务的属性。主要有五种属性:
- 隔离性、传播性、回滚规则、超时时间、是否只读
public interface TransactionDefinition {
// 获取事务的传播性
int getPropagationBehavior();
// 获取事务的隔离级别,事务管理器根据它来控制另外一个事务
int getIsolationLevel();
// 获取事务的超时时间, 表示事务必须在多少秒内完成
int getTimeout();
// 事务是否只读, 事务管理器能够根据这个返回值进行优化, 确保事务是只读的
boolean isReadOnly();
String getName();
}
- 事务传播机制,7个事务传播机制的具体含义
// 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务
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;
// 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。
int PROPAGATION_NESTED = 6;
- 隔离级别
// 数据库的默认隔离级别
int ISOLATION_DEFAULT = -1;
// 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
int ISOLATION_READ_UNCOMMITTED = 1;
// 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
int ISOLATION_READ_COMMITTED = 2;
// 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
int ISOLATION_REPEATABLE_READ = 4;
// 最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别
int ISOLATION_SERIALIZABLE = 8;
- 默认超时
int TIMEOUT_DEFAULT = -1;
在开发时,直接使用 TransactionDefinition 的实现类
DefaultTransactionDefinition
即可
3. TransactionStatus 事务状态
TransactionStatus
用来记录事务执行过程中的状态,提供了控制事务执行和查询事务状态的方法。
public interface SavepointManager {
// 创建回滚点
Object createSavepoint() throws TransactionException;
// 回滚到回滚点
void rollbackToSavepoint(Object savepoint) throws TransactionException;
// 释放回滚点
void releaseSavepoint(Object savepoint) throws TransactionException;
}
继承了 SavepointManager
接口,封装了事务回滚点的相关操作
public interface TransactionStatus extends SavepointManager, Flushable {
// 获取当前事务是否是一个新事务
boolean isNewTransaction();
// 是否有回滚点
boolean hasSavepoint();
// 将一个事务标识为不可提交的。在调用完setRollbackOnly()后只能被回滚
// 在大多数情况下,事务管理器会检测到这一点,在它发现事务要提交时会立刻结束事务。
// 调用完setRollbackOnly()后,数据库可以继续执行select,但不允许执行update语句,因为事务只可以进行读取操作,任何修改都不会被提交。
void setRollbackOnly();
boolean isRollbackOnly();
// 将底层会话中的修改刷新到数据库,一般用于 Hibernate/JPA 的会话,对如JDBC类型的事务无任何影响
void flush();
// 判断事务是否已经完成
boolean isCompleted();
}
DefaultTransactionStatus
是 TransactionStatus 的一个实现类
关于获取 TransactionStatus 实例
事物管理器PlatformTransactionManager
可以获取 TransactionStatus
,在管理器的接口中有定义:
public interface PlatformTransactionManager {
// 获取事务状态,实际上获取的是 DefaultTransactionStatus实例
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
...
}