原子性(atomicity)
:事务是最小的执行单位,不允许分割,事务执行时要么全部成功,要么失败回滚。一致性(consistency)
:事务执行之前和事务执行结束,数据库完整性没有被破坏,也就是数据从一个正确的状态转换到另一个正确状态。隔离型(isolation)
:数据库允许多个并发事务同时对数据进行读写,而隔离是一个事务执行,不影响其他事务的运行效果。持久性(durability)
:一个事务一旦提交(结束),对数据库的修改就是永久的,即使系统故障也不会丢失。对于服务器来说可能同时处理多个事务。事务有隔离性
的特性,理论上在某个事务 对某个数据进行访问
时,其他事务应该进行排队
,当该事务提交之后,其他事务才可以继续访问这个数据。但是这样对 性能影响太大
,我们既想保持事务的隔离性,又想让服务器在处理访问同一数据的多个事务时 性能尽量高些 。
脏读( Dirty Read )
:事务A和事务B交替执行,事务A读取
了已经被事务B修改
但是还未提交的字段
,而此时事务B发生了回滚
,那么事务A读到的就是脏数据
。
幻读( Phantom )
: 事务A查询一个范围的结果集,另一个并发事务B往这个范围中插入/删除了数据
,并提交,然后事务A再次查询相同的范围,两次读取得到的结果集不一样了,这就是幻读。
不可重复读( Non-Repeatable Read )
:事务 A 读取 了一个字段,然后 事务 B 更新 了该字段。 之后事务A 再次读取 同一个字段, 值就不同了
丢弃修改
:俩个写事务A,B同时对A = 0进行+1操作,结果B覆盖了A,导致最终结果是1而不是2,事务被覆盖。
幻读和不可重复读区别
例如事务A读取工资为1000操作没完成,此时事务B修改1000为2000,此时A在读导致钱是1000.
幻读是事务A查询工资单中大于3000的一共有3人,而此时事务B又加了一条4000元进行,此时事务A读到的就是4人。
READ UNCOMMITTED
:读未提交,事务发生了修改,即使没有提交,所有事务都可以看到其他未提交事务的执行结果。不能避免脏读、不可重复读、幻读。
READ COMMITTED
:读已提交,一个事务从开始直到提交前,所做的任何修改时其他事务不可见的。这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。可以避免脏读,但不可重复读、幻读问题
仍然存在。REPEATABLE READ
:可重复读,事务A在读到一条数据之后,此时事务B对该数据进行了修改并提交,那么事务A再读该数据,读到的还是原来的内容。可以避免脏读、不可重复读,但幻读问题仍然存在。这是MySQL的默认隔离级别。SERIALIZABLE
:可串行化,确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作。所有的并发问题都可以避免,但性能十分低下。能避免脏读、不可重复读和幻读。主要是利用 Innodb 的undo log。 undo log名为回滚日志,是实现原子性的关键,当事务回滚时能够撤销所有已经成功执行的 SQL语句,他需要记录你要回滚的相应日志信息。 例如
undo log记录了这些回滚需要的信息,当事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。
分为两个层面来说。
主要是利用Innodb的redo log。重写日志, 正如之前说的,MySQL是先把磁盘上的数据加载到内存中,在内存中对数据进行修改,再写回到磁盘上。如果此时突然宕机,内存中的数据就会丢失。 怎么解决这个问题? 简单啊,事务提交前直接把数据写入磁盘就行啊。 这么做有什么问题?
于是,决定采用redo log解决上面的问题。当做数据修改的时候,不仅在内存中操作,还会在redo log中记录这次操作。当事务提交的时候,会将redo log日志进行刷盘(redo log一部分在内存中,一部分在磁盘上)。当数据库宕机重启的时候,会将redo log中的内容恢复到数据库中,再根据undo log和binlog内容决定回滚数据还是提交数据。
文章借鉴:https://interviewguide.cn/notes/03-hunting_job/02-interview/03-02-net.html