1、事务执行过程中会出现几种情况
(1)脏读
出现原因:修改数据的同时可以读取数据;
说明:当事务A对data进行了修改但是未提交事务,此时事务B对data进行读取,并使用事务A修改的数据做业务处理,;
案例:
以取款为例假设A与B同用一张银行卡,银行卡余额为1000 |
||
节点 |
A存款 |
B取款 |
T1 |
开始事务 |
- |
T2 |
- |
开始事务 |
T3 |
- |
查询余额(余额1000) |
T4 |
- |
取款1000(余额0) |
T5 |
查询余额(余额0元) |
- |
T6 |
- |
撤销事务(余额恢复1000) |
T7 |
存款500 |
- |
T8 |
提交(余额500) |
- |
(2)不可重复读
出现原因:读取数据的同时可以进行修改;
说明:事务A,事务B同时对dataA进行访问,事务A对data进行读取,事务B对data进行修改,当事务A第一次对data进行读取完后事务B提交,此时当事务A第二次读取该数据时的数据就与第一次读取的数据不同,这种情况成为不可重复读;
案例:
以取款为例假设A与B同用一张银行卡,银行卡余额为1000 |
||
节点 |
A取款 |
B取款 |
T1 |
开始事务 |
- |
T2 |
- |
开始事务 |
T3 |
- |
查询余额(余额1000元) |
T4 |
查询余额(余额1000元) |
|
T5 |
- |
取款1000 |
T6 |
- |
提交(余额0) |
T7 |
取款1000 |
- |
T8 |
提交(余额不足) |
- |
(3)幻读
出现原因:读取和修改的时候可以insert数据;
说明:data 表有一条数据,事务A对data进行读取, 事务B对data进行数据新增 ,此时事务A读取只有一条数据,而最后实际data是有两条数据,就好象发生了幻觉一样情况成为幻读;
案例:
以打印银行卡账单存款记录单为例子(银行卡本身有2条存款) |
||
节点 |
A打印 |
B存款 |
T1 |
开始事务 |
- |
T2 |
查询存款记录(2条) |
- |
T3 |
- |
开始事务 |
T4 |
- |
存款 |
T5 |
打印 |
提交(3条存款记录) |
T6 |
打印结果(3条存款记录) |
- |
2、事务的四种级别
(1)READ_UNCOMMITTED(读未提交):,可读取未提交事务的操作数据,这种情况会出现脏读;
(2)READ_COMMITTED(读提交):一个事务等另一个事务提交之后才可进行读取,解决了脏读问题,但会出现重复读问题;
(3)REPEATABLE_READ(重复读):读取事务开启的时候不能对数据进行修改,可能出现幻读问题;
(4)SERIALIZABLE (序列化):是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用;
3、spring事务的七中传播方式
spring事务的七中传播方式主要是针对于方法中间传递时的事务机制,
例如:以方法B为当前主体 ,方法A调用了方法B ,作为方法B你看方法A
(1)PROPAGATION_REQUIRED(默认):如果A有事务则B加入A事务,如果A没有事务则新B建一个事务;
(2)PROPAGATION_NEW:B总是开启一个新的事务,如果A有事务则将A事务挂起先执行B事务;
(3)PROPAGATION_NESTED:RUGU :如果A没事务则新建一个事务,如果A有事务则把B的事务当成A的一个子事务(A事务rolback,commit影响B,B事务rolback,commit不影响A);
(4)PROPAGATION_SUPPORTS:如果A没事务,那就按普通方法执行,如果有A事务则用A的事务(B本身不具备事务);
(5))PROPAGATION_NOT_SUPPORTED:B总是非事务地执行,如果A有事务则把A事务挂起,自己还是以普通方法执行(B本身不具备事务);
(6)PROPAGATION_NEVER:如果A没事务,那就按普通方法执行,如果A有事务则抛出异常((B本身不具备事务);
(7)PROPAGATION_MANDATORY:如果A没事务就抛异常,如果A有事务则使用A的事务(B本身不具备事务);
本文章学习资料来源:网络、书籍<架构探险>