MySQL数据库——事务(隔离级别是重点)


事务是访问并更新数据库各种数据项的一个程序执行单元,可以是一条语句,也可以是一组语句。

ACID(原子性、一致性、隔离性、持久性)

原子性:undolog(rollback)要么都执行要么都不执行。

持久性:redolog

隔离性:锁和MVCC

一致性

关于隔离性。当数据库多事务同时执行,可能出现脏读、不可重复读、幻读的问题。隔离级别用来解决这些问题。

隔离越好,效率越低。事务隔离级别有:读未提交、读已提交、可重复读、串行化。

读未提交是事务还没提交,就能被其他事务看到。

读已提交是事务提交之后,才能被其他事务看到。(Oracle和微软的默认)

可重复读是事务执行过程中和刚启动时保持一致。(InnoDB默认,两个事务彻底隔离)

串行化,可以对同一行数据加读锁和写锁。当读写锁冲突的时候,后一个事务要等前一个事务完成才能执行。

在隔离级别的实现方面,视图是一个关键部分,访问的时候以视图逻辑结果为准。(读不加锁,多版本并发控制MVCC)

比如可重复读,就是视图在事务启动时创建,整个事务存在期间都用这个视图。(数据核对场景,多版本并发控制MVCC)

比如读已提交,就是在每个SQL语句开始执行的时候创建视图。

读未提交是直接返回记录的最新值,没有视图的概念。

串行化是直接用加锁的方式避免并行访问。

多事务并发会出现的问题:脏读、不可重复读、幻读。(异常)

设置了可重复读,那么即使B事务插入更改了,A事务也无法读到更改的。

但是B事务插入过,想要再次插入的时候就会出现重复的问题(就像已经存在了),这就是幻读问题。

解决幻读:lock in share mode。在可重复读隔离模式加读锁。

这样事务A插入。

在MySQL中,每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值可以通过回滚日志得到前一个状态的。

长事务是运行事件比较长并且长时间没有提交的事务。尽量不要使用长事务,因为系统里面会存在很老的事务视图,回滚日志回滚记录占用资源,长事务还造成阻塞且占用锁资源。

关于MySQL的事务启动机制。可以显示地启动事务set autocommit=1,begin或者start transaction,然后用commit提交,用rollback回滚。autocommit=0是自动启动事务,这会导致如果接下来的查询都在事务而且都是长连接,就会导致意外的长事务。

因此一般建议使用set autocommit=1。有人觉得麻烦也可以使用commit work and chain,这条提交了就自动执行下一条不是长事务的。可以在information_schema库的innodb_trx表中查询长事务,比如查询持续事件超过60秒的事务。