事务是什么

事务就是指逻辑上的一组sql语句操作,组成这组操作的各个sql语句,执行时要么全成功要么全失败。

事务的四大特性

1.原子性
​ 事务是一个不可分割打的单位,事务中所有sql等操作要么都发生,要么都不发生。

2.一致性
​ 事务发生前和发生后,数据的完整性必须保持一致。

3.隔离性
​ 当并发访问数据库时,一个正在执行的事务在执行完毕前,对于其他的会话是不可见的,多个并发事务之间的数据是相互隔离的。
​ 也就是其他人的操作在这个事务的执行过程中是看不到点这个事务的执行结果的,也就是他们拿到的是这个事务执行之前的内容,等这个事务执行完才能拿到新的数据。

4.持久性
​ 一个事务一旦被提交,他对数据库中的数据改变是永久性的。如果出了错误,事务也不允许被撤销,只能通过补偿性事务。

脏读 幻读 不可重复读

1.脏读:
​ 所谓脏读是指一个事务正在访问数据,并且对数据进行了修改,而这些数据还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。

​ 如果会话2更新age为10,但是在commit之前,会话1希望得到age,那么会获得的值就是更新前的值。或者如果会话2更新了值但是执行了rollback,而会话1拿到的仍是10.这就是脏读。

2.不可重复读:
​ 一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事物中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此成为不可重复读。(即不能读到相同的数据内容)

​ 由于在读取中间变更了数据,所以会话1事务查询期间得到的结果就不一样了。

3.幻读:
​ 指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行(多了一行,和前一次不一样),就好像发生了幻觉一样。

幻读是指一个事务在前后两次查询中,后一次查询看到了前一次查询没有看到的行。

​ 幻读是不可重复读的一种特殊场景

小结:不可重复读和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除,解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。

事务的隔离级别

Mysql里有四个隔离级别:

1.Read uncommttied (可以读取未提交的数据)
事务A和事务B,A事务中执行的操作,B也可以看得到,因为提交级别是未提交读,别人事务中还没提交的数据你也看的到。这是没有任何并发措施的级别,也是默认级别。这个问题叫做脏读,为了解决这个问题,提出了读已提交。

2.Read committed(可以读取已提交数据)
事务A和事务B,A中的操作B看不到,只有A提交后,在B中才看的到。虽然A的操作B看不到,但是B可以修改A用到的数据,导致A读两次的数据结果不同。这就是不可重复读问题。

3.Repeatable read(可重复读)
事务A和B,A在数据行上加读锁,B虽然看的到但是改不了。所以可重复读的,但是A的其他行为仍然会被B访问并修改,所以导致了幻读问题。

4.Serializable(可串行化)
数据库强制事务A和B串行化操作,避免了并发问题,但是效率比较低。

InnoDB是如何实现事务的

InnoDB的行锁是加在索引上的,因为InnoDB默认有聚簇索引,但实际上的行锁是对整个索引节点进行加锁,锁了该节点的所有行。

InnoDB是如何实现隔离级别以及解决一直问题的:

未提交读:会导致脏读,没有并发措施
已提交读:写入时需要加锁,使用行级写锁加锁指定行,其他事务就看不到未提交事务的数据了。但是会导致不可额重复读
可重复读:在原来的基础上,在读取行时也需要加行级读锁,这样其他事务不能修改这些数据。就避免了不可重读。但是这样会导致幻读。
序列化:序列化会串行化读写操作来避免花都,事实上就是事务在读取数据时加了表级读锁。

但是实际上。MYSQL的新版InnoDB引擎已经解决了幻读的问题,并且使用的是可重复读级别就能解决幻读了。
实现原理是next-key lock。是gap lock的加强版。不会锁住全表,只会锁住被读取行前后的间隙行。