1. 1. 事务
  2. 2. 事务的特性
  3. 3. 多事务同时执行引起的问题
  4. 4. 事务隔离级别
  5. 5. 配置事务方法
  6. 6. 事务隔离的实现
  7. 7. 尽量不要使用长事务
  8. 8. 事务的启动方式
  9. 9. 事务隔离 or 不隔离
  10. 10. “快照”在MVCC里是怎么工作的

事务

事务是为了保证一组数据库操作,要么全部执行成功,要么全部执行不成功,InnoDB支持,Myisam不支持

事务的特性

  • 原子性
  • 一致性
  • 隔离性
  • 持久性

多事务同时执行引起的问题

  • 脏读
  • 不可重复读
  • 幻读

事务隔离级别

  • 读未提交(read uncommitted) 一个事务还没提交时,它做的变更就能被别的事务看到
  • 读提交(read committed) 一个事务提交之后,它做的变更才会被其他事务看到
  • 可重复读(repeatable read) 一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的
  • 串行化(serializable) “写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突时,后访问的事务必须等前一个事务执行完成后,才能继续执行

配置事务方法

1
启动参数transaction-isolation

事务隔离的实现

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

同一条记录在系统中可以存在多个版本,这就是数据库的多版本并发控制(MVCC)。

回滚日志在不需要的时候删除,当系统里没有比这个回滚日志更早的read-view时候,系统自动删除

尽量不要使用长事务

长事务意味着系统里面会存在很老的事务视图,在事务提交之前,回滚日志必须保留,这就会导致大量占用存储空间

事务的启动方式

  • 显示启动事务

    1
    2
    3
    begin transaction
    do something
    commit / rollback
  • set autocommit=0,将这个线程的自动提交关掉,只要你执行一个查询语句,事务就启动了,接下来的查询都在事务中,如果是长连接,将导致意外的长事务,这样直到你主动执行commit或者rollback语句或者断开连接才释放,可以通过set autocommit=1来显式方式来启动事务

    1
    2
    3
    4
    5
    begin tracsaction; # 不是一个事务的起点,在执行到它之后的第一个操作InnoDB语句,事务才真正启动
    start transaction with consistent snapshot; # 马上启动一个事务
    commit; # 提交事务
    autocommit=1;

事务隔离 or 不隔离

如果是可重复读隔离级别,事务启动时会创建一个视图read-view,之后事务执行期间,即使有其他事务修改了数据,该事务看到的仍然跟启动时看到的一样,也就是在可重复读隔离级别下执行事务,不受外界影响

1
start transaction with consistent snapshot; # 执行该命令后马上启动一个事务

Mysql中的两个“视图”:

  • 一个view,用于查询语句定义的虚拟表,在调用的时候执行查询语句并生成结果
  • InnoDB在实现MCVV时用到的一致性读视图,即consistent read view,用于支持RC(Read Committed,读提交)和RR(Repeatable Read,可重复读)隔离级别的实现,作用在事务执行期间用来定义”我能看到什么数据”

“快照”在MVCC里是怎么工作的

在可重复读隔离级别下,事务在启动的时候就拍下快照,这个快照是基于整库

Innodb里面每个事务有一个唯一的事务ID,叫作transaction id,它是在事务开始的时候向Innodb的事务系统申请的,是按申请顺序严格递增的

每行数据也都都是有多个版本的,每次事务更新数据时,都会生成一个新的数据版本,而且把transaction id赋值给这个数据版本的事务id,记为row trx_id; 同时,旧的数据版本要保留,并且在新的数据版本中能够有信息可以直接拿到它

数据表中一行记录,其实可能有多个版本(row),每个版本有自己的rowtrx_id

InnoDB利用了“所有数据都有多个版本”的特性,实现了“秒级创建快照的能力”

更新数据都要先读后写,而这个读,只能读当前的值,称之为”当前读”;当前读总是读取已经提交完成的最新版本

  • 对于可重复读,查询只承认在事务启动前就已经提交完成的数据
  • 对于读提交,查询只承认在语句启动前就已经提交完成的数据