MySql事务隔离等级、Spring事务管理
MySql默认引擎InnoDb的数据储存在表空间(tablespace)中,表空间是innoDB管理的一个黑盒,储存了一系列的数据。InnoDB也可以将每个表的数据和索引放到单独的文件中。
InnoDB采用MVCC(MultiVersion Concurrency Control)支持高并发,实现了四个标准的隔离级别:
事务级别 |
脏读 |
不可重复读 |
幻读 |
READ UNCOMMITTED |
是 |
是 |
是 |
READ COMMITTED |
否 |
是 |
是 |
REPEATABLE READ |
否 |
否 |
是 |
SERIALIZABLE |
否 |
否 |
否 |
InnoDB默认级别为REPEATABLE READ,并且会通过间隙锁防止幻影行的插入。
关于脏读、不可重复读和幻读:
并发问题 |
描述 |
脏读 Dirty Reads |
事务A读到了未持久化的数据,比如某数据发生了回滚 |
不可重复读 Non-Repeatable Reads |
事务A多次对读同一数据但结果不同 |
幻读 Phantom Reads |
事务A多次读统一数据但结果发生了新增或缺失 |
作为MySql另一个主要引擎,MyIsam和InnoDB的主要区别在于前者不提供事务和行级锁的支持,且有一个严重的缺陷是崩溃后无法安全恢复。无法支持事务意味着无法保证ACID(见下表)性质,无法支持行级锁意味着只能对整张表进行加锁,在并发环境下性能将大幅下降。
事务ACID性质:
原子性 Atomicity |
事务要么全部完成,要么全部不做 |
一致性 Consistency |
执行事务之后,数据库的完整性约束不能被破坏 |
隔离性 Isolation |
事务之间不能有相互的干扰,隔离性被分成了四个等级 |
持久性 Durability |
事务正常结束后,数据得到持久化,不能回滚 |
Spring中的事务管理:
Spring为JDBC、Hibernate和JTA提供了一套相同的模型,都是通过事务管理接口PlatformTransactionManager进行管理,该接口中定义了三个方法:
public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }
Spring事务特性主要包括事务传播,事务等级,是否只读,超时时间,回滚规则
其中事务的默认隔离等级为ISOLATION_DEFAULT,也就是采用所用数据库的默认隔离等级。其余的四个等级和上表所述的相同,需要说明的是,Spring本身并没有对事务隔离进行具体的实现,而是依赖了数据库的实现。
事务传播,这项属性定义了一个方法应当在怎么样的事务环境中运行:
传播属性 |
描述 |
PROPAGATION_REQUIRED |
必须运行在事务中,若当前事务不存在则新建一个事务 |
PROPAGATION_SUPPORTs |
若存在当前事务则运行在其中,不存在则不需要事务 |
PROPAGATION_MANDATORY |
必须运行在当前事务中,若当前无事务,则抛出异常 |
PROPAGATION_REQUIRED_NEW |
必须运行在自己新建的事务中,将阻塞当前事务 |
PROPAGATION_NOT_SUPPORTed |
必须在无事务环境下运行,将阻塞当前事务 |
PROPAGATION_NEVER |
必须在无事务环境下运行,若存在当前事务则抛出异常 |
PROPAGATION_NESTED |
创建一个新事务并嵌套进当前事务,外部事务发生回滚则一同 回滚,若外部事务正常,则内部事务独立完成或回滚 |
事务是否只读:
若设置为是,则性能会得到一定程度的优化
回滚规则:
默认发生RuntimeException后回滚,但也可以设置为发生其他异常后回滚
事务超时:
Spring中默认为30s,若发生超时则回滚事务。