概念理解:
举例:
A 支出100 -100
B 收到100 +100
以上操作称作一个事务,是一个不可分割的部分,要么全不做,要么全部做。
事务的特性
一致性:事务前后应该保证状态一致,在这里就是总金额保持一致
原子性:操作要么全部成功要么全部失败
隔离性:用户操作表,数据库为其开启事务,操作过程中不能被其他操作干扰
持久性:事务被修改了就是永久的
脏读 幻读 不可重复读
脏读:事务B查看到事务A未提交的数据
不可重复读:主要在更新 多select 几次发现数据被人update过
幻读:主要在插入 插入发现该数据被人插入过
幻读和不可重复读详解
sql 语句执行的流程
- 先记录 undo/redo log,确保日志刷到磁盘上持久存储。
- 更新数据记录,缓存操作并异步刷盘。
- 将事务日志持久化到 binlog。
- 提交事务,在 redo log 中写入commit记录。
- 失败回滚记录事务
事务的隔离级别
不可重复读
begin;
SQL1:select value from tab where id = 1; //返回value = 1;
SQL2:select value from tab where id = 1; //返回value = 2;
commit;
因为[SQL1]和[SQL2]执行的中间,别的事务执行了:
begin;
update tab set value = 2 where id = 1;
commit;
而[SQL1]跟[SQL2]执行所拿的Snapshot不一样(RC),造成了不可重复读,而RR隔离级别[SQL1]跟[SQL2]的Snapshot一样,结果也是一样,就不会发生不可重复读的问题。
幻读
begin;
SQL3:select value from tab where id = 1; //表中id=1的记录还没有
SQL4:select value from tab where id = 1;//value=X
commit;
在一个事务中[SQL3]跟[SQL4]读取的数据是有和没有的区别,例如在某些场景下,先检测ID=1的记录是否存在,如果有则跟新,没有就插入。那么在执行[SQL3]的时候,id=1的记录不存在,那么在执行[SQL4]之前,其他事务执行了:
begin;
insert into tab(id,value) values(1,X);
commit;
则[SQL4]就能读取刚才看不见的数据,删除也同理,数据时有时无
事务的传播级别
事务传播行为类型 | 说明 |
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
参考文献