分布式事务01课前知识

问题

  1. 事务的几个特点

  2. 数据库事务有哪些隔离级别

  3. MySQL的默认隔离级别

考点

mysql开发的三个基本面:存储引擎(了解)、索引(重要)、事务(了解原生及spring事务)

回答

事务特点

ACID

A原子性: 事务里的所有sql, 要么都成功, 要么都不成功

C一致性(不是很懂, 抄来的): 事务开始/结束不影响数据库的一致性

  1. 数据库机制层面
    数据符合设置的约束条件, 由唯一索引/外键/check约束/触发器保证

  2. 业务层面
    由研发人员保证, 但一般会转为数据库机制层面保证

I隔离性: 设计到事务的隔离机制, 根据机制的选择不同, 各个事务之间的结果也不同

D持久性: 落库, 只要提交就一定成功, 即使是断电也会通过数据库的机制保证成功(redolog)

I隔离性相关的隔离级别

四个隔离级别

读未提交
一个事务还没提交, 另一个事务就读到了结果...

读已提交(不可重复读)
(Oracle默认级别)
能读取到已经提交的事务结果(针对单条数据)
举例:
事务A, 先查一次, 结果为1
事务B, 在事务A查询之后, 改成结果2
事务A, 再查一次, 结果为2

可重复读
一个事务中的查询结果是不变的(针对单条数据)
(mysql默认隔离级别, mysql里该级别可以解决幻读)
举例:
事务A, 开始查的是1, 即使中途有其他事务改了结果, 事务A查出来还是1

串行化
事务A执行完毕, 才能执行事务B
主要是为了防止幻读:
幻读针对插入, 比如事务A已经将所有的行的数据修改为2了, 但是另一个事务B插入了一条数据为1, 那么事务A此时再查询就会有未修改的一条数据

mysql默认隔离级别是如何解决幻读

通过MVCC机制(多版本并发控制,multi-version concurrency control), 类似于快照。
简单来说就是多两个隐藏列: 该行创建的事务id, 该行删除时的事务id
查询默认带条件: 创建事务id <= 当前事务id && 当前事务id < 删除事务id

举例:

id name 创建事务id 删除事务id
1 张三 120
2 李四 119

事务A, 事务id: 121
事务B, 事务id: 122, 把id2的李四改成了小李四, 此时插入一条数据; 再把id=1的数据删除

id name 创建事务id 删除事务id
1 张三 120 122
2 李四 119
2 小李四 122

事务A, 事务id: 121
查询id=1, 可以查到(当前事务id 121 < 删除事务id 122);
查询id=2, 还是李四(创建事务id 120 <= 当前事务id 121 && 当前事务id 121< 删除事务id 122)

事务B, 事务id: 122
查询id=1, 查不到(当前事务id 122 不小于 删除事务id 122);
查询id=2, 查询为小李四(创建事务id 122 <= 当前事务id 122)

spring的事务机制

记得把日志的级别开成 debug

测试三个状态
伪代码
都成功:

serviceA save () {
   insert();
   
   serviceB.delete();
}

调用方在被调用方执行完毕后报错:

serviceA save () {
   insert();
   
   serviceB.delete();
   throws Exception;
}

被调方报错;

serviceA save () {
   insert();
   serviceB.delete( throw Exception);
}

REQUIRED, 被调用方(ServiceB)开启事务, 如果有调用方ServiceA有事务则加入调用方的事务, 两者合成一个事务, 任何一方出错, 全部回滚; 如果调用方ServiceA没有事务, 则被调用方ServiceB创建单独的事务, ServiceB出错的回滚自己, 和ServiceA无关, 即只有B的事务

  1. ServiceA, REQUIRED
  2. ServiceB, REQUIRED

合并到一个A的事务中

NOT_SUPPORTED, Spring不为当前方法开启事务,相当于没有事务, 调用方A有事务, 会无法执行B为NOT_SUPPORTED, 会报错

  1. ServiceA, NOT_SUPPORTED
  2. ServiceB, REQUIRED

B会开事务, A不会, 所以只会回滚B

REQUIRES_NEW, 不管是否存在事务,都创建一个新的事务,原来的方法挂起,新的方法执行完毕后,继续执行老的事务

  1. A: REQUIRED,
  2. B: REQUIRES_NEW,
    B事务报错, A事务catch了, 那么只会B事务回滚, A事务照常

MANDATORY, 必须要在一个事务中, 不然就报错

  1. A: 无事务,
  2. B: MANDATORY,

报错:
No existing transaction found for transaction marked with propagation 'mandatory'

NEVER, 必须在无事务环境下执行, 不然就报错

  1. A: REQUIRED,
  2. B: NEVER,

报错:
Existing transaction found for transaction marked with propagation 'never'

SUPPORTS, 看调用方是否存在事务, 有加入事务, 没有就不加

  1. A: REQUIRED,
  2. B: SUPPORTS,

会加入A事务, 如果A没有事务, 则都没有事务

NESTED, 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作

  1. A: REQUIRED,
  2. B: NESTED,

还要看mysql的环境,
The MySQL server is running with the --transaction-write-set-extraction!=OFF option so it cannot execute this statement
会报错, NESTED会不成功

据说执行的效果,save方法创建一个事务,则再调用delete方法时,直接在该事务的基础上创建一个嵌套事务,本质上还是同一个事务,做一次提交;
save方法不创建事务,则调用delete方法时,直接创建一个新的事务,单独提交

https://blog.csdn.net/dufufd/article/details/51479860

https://blog.csdn.net/qq_26323323/article/details/81908955

原文地址:https://www.cnblogs.com/richardhaha/p/15774517.html