事务的特性(ACID):
原子性、一致性、隔离性、持久性 (具体可参考redis笔记)
事务隔离级别:
读未提交、读提交、可重复读、串行化
不同事务隔离级别的区别:
- 读未提交:一个事务还未提交,它所做的变更就可以被别的事务看到
- 读提交:一个事务提交之后,它所做的变更才可以被别的事务看到(会出现脏读)
- 可重复读:一个事务执行过程中看到的数据是一致的。未提交的更改对其他事务是不可见的
-
串行化:对应一个记录会加读写锁,出现冲突的时候,后访问的事务必须等前一个事务执行完成才能继续执行
Y.png
- 如果事务的隔离级别为读未提交,也就是就算事务B还没有提交V1也能读到事务B修改后的值,所以 V1,V2,V3都是2
- 如果事务的隔离级别为读提交,V1无法读到事务B还没有提交修改后的值,则 V1 是 1,V2 的值是 2。事务 B 的更新在提交后才能被 A 看到。所以, V3 的值也是 2。 (此时会出现脏读)
- 若隔离级别是“可重复读”,则 V1、V2 是 1,V3 是 2。之所以 V2 还是 1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的。
- 若隔离级别是“串行化”,则在事务 B 执行“将 1 改成 2”的时候,会被锁住。直到事务 A 提交后,事务 B 才可以继续执行。所以从 A 的角度看, V1、V2 值是 1,V3 的值是 2。
多事务同时执行的时候,可能会出现的问题:脏读、不可重复读、幻读
- 脏读:脏读是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。如上二第一种情况。
- 不可重复读:是指在一个事务内,多次读同一数据。事务在执行期间看到的数据前后必须是一致的。
比如int i =1 ;事务一第一次读的时候在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。如果 只有在作者全部完成编写后编辑人员才可以读取文档(串行化),则可以避免该问题。 - 幻读:是指当事务不是独立执行时发生的一种现象,
例:事务一执行了delete * from T 删除表中的所有数据,同时第二个事务执行了一条插入语句,这时第一个事务执行完就会发现数据库里面还有一条第二个事务插入的数据,就好象发生了幻觉一样。
配置方法:
启动参数transaction-isolation
事务隔离的实现:
每条记录在更新的时候都会同时记录一条回滚操作。同一条记录在系统中可以存在多个版本,这就是数据库的多版本并发控制(MVCC)。
回滚日志什么时候删除?
系统会判断当没有事务需要用到这些回滚日志的时候,回滚日志会被删除。
什么时候不需要了?
当系统里么没有比这个回滚日志更早的read-view的时候。
为什么尽量不要使用长事务。
长事务意味着系统里面会存在很老的事务视图,在这个事务提交之前,回滚记录都要保留,这会导致大量占用存储空间。除此之外,长事务还占用锁资源,可能会拖垮库。
-
事务启动方式:
一、显式启动事务语句,begin或者start transaction,提交commit,回滚rollback;二、set autocommit=0,该命令会把这个线程的自动提交关掉。这样只要执行一个select语句,事务就启动,并不会自动提交,直到主动执行commit或rollback或断开连接。 -
建议使用方法一,
如果考虑多一次交互问题,可以使用commit work and chain语法。在autocommit=1的情况下用begin显式启动事务,如果执行commit则提交事务。如果执行commit work and chain则提交事务并自动启动下一个事务。
网友评论