关于事务的四个特性、事务的隔离级别、事务的并发问题

关于事务的四个特性、事务的隔离级别、事务的并发问题

事务的四个特性

MySQL事务,首先要提他的四大特性(ACID),正是这些特性,才保证了数据库事务的安全性。

  • 原子性(Atomicity)
  • 一致性(Consistent)
  • 隔离性(Isolation)
  • 持久性(Durable)

原子性

原子性是指一个事务是一个不可分割的工作单位,其中的操作要么都做,要么都不做;如果事务中一个sql语句执行失败,则已执行的语句也必须回滚,数据库退回到事务前的状态。

一致性

一致性是指事务执行结束后,数据库的完整性约束没有被破坏,事务执行的前后都是合法的数据状态。

隔离性

与原子性、持久性侧重于研究事务本身不同,隔离性研究的是不同事务之间的相互影响。隔离性是指,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

持久性

持久性是指事务一旦提交,它对数据库的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

事务的并发问题

  • 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
  • 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
  • 幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

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

MySQL的事务隔离级别

  • 读未提交(READ UNCOMMITTED)
  • 读提交 (READ COMMITTED)
  • 可重复读 (REPEATABLE READ)
  • 串行化 (SERIALIZABLE)

从上往下,隔离强度逐渐增强,性能逐渐变差。采用哪种隔离级别要根据系统需求权衡决定,其中,可重复读是 MySQL 的默认级别。

MySQL 的 InnoDB 引擎才支持事务,其中可重复读是默认的隔离级别。

Read uncommitted(未授权读取、读未提交)

如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。这样就避免了更新丢失,却可能出现脏读。也就是说事务B读取到了事务A未提交的数据。

Read committed(授权读取、读提交)

读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。该隔离级别避免了脏读,但是却可能出现不可重复读。事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。

Repeatable read(可重复读取)

可重复读是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,即使第二个事务对数据进行修改,第一个事务两次读到的的数据是一样的。这样就发生了在一个事务内两次读到的数据是一样的,因此称为是可重复读。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。这样避免了不可重复读取和脏读,但是有时可能出现幻象读。(读取数据的事务)这可以通过“共享读锁”和“排他写锁”实现。

Serializable(序列化)

提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。序列化是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻像读。

悲观锁和乐观锁

虽然数据库的隔离级别可以解决大多数问题,但是灵活度较差,为此又提出了悲观锁和乐观锁的概念。

悲观锁

悲观锁就是某事务在更新数据过程中将数据锁定,其他任何事务都不能读取或修改,必须修改完成后才能访问数据(类似于Java的线程同步机制)。悲观锁的特点是具有排他性,通常依赖于数据库的锁机制,一般适合短事务处理。

乐观锁

乐观锁相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以只会在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回用户错误的信息,让用户决定如何去做。乐观锁的特点是并发性较好,事务修改数据时,其他事务仍可以修改数据。

乐观锁的两种实现方式:

  1. 使用版本号:使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。
  2. 使用时间戳: 乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。
    说白了,乐观锁其实根本不是一种数据库锁机制,而是一种冲突检测机制,这种冲突检测机制是依赖软件或应用程序实现的。那乐观锁为何乐观呀,乐观在它的并发性比悲观锁好,一个事务在修改数据时,其他事务仍然可以修改数据。

悲观锁和乐观锁的使用场景

悲观锁的优点是可以保障数据库的数据是绝对安全的,它是依赖数据库的锁机制,能很好的解决数据库访问的并发性问题,但是缺点就是会导致数据库访问性能低下,所以适合短事务(也就是事务执行时间很短)的情况。你想一想,如果事务执行时间很长,那么后面的事务就得一直排队等待嘛。它的使用场景是对数据安全性要求非常高的场景,比如银行系统、金融系统等。

乐观锁的优点是可以保障并发性比较好,也就景数据库访问性能可以,它是依赖软件的冲突检测机制实现的,但是缺点就是并没彻底解决数据库访问的并发性问题,所以数据库的数据不是绝对安全的。它的使用场景是对数据安全性要求不高而对性能要求很高的场景,比如各种信息管理系统等。

Mysql数据库引擎Innodb和Myisam

Innodb和Myisam的区别

1、MyISAM:默认表类型,它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的顺序访问方法) 的缩写,它是存储记录和文件的标准方法。不是事务安全的,而且不支持外键,如果执行大量的select,insert MyISAM比较适合。

2、InnoDB:支持事务安全的引擎,支持外键、行锁、事务是他的最大特点。如果有大量的update和insert,建议使用InnoDB,特别是针对多个并发和QPS较高的情况。

  • innodb 支持事务, myisam 不支持事务
  • innodb 支持外键, myisam 不支持外键
  • innodb 支持行级锁, myisam 支持表级锁
  • myisam 保存了表的总行数count(*), innodb没有保存,需要扫描全表查询

MySQL的两种引擎下的锁机制

1.innodb存储引擎:
行级锁(也兼容了表级锁)
行级锁又分为共享锁和排他锁 (另外还有意向共享锁和意向排他锁,存储引擎会自动加)
执行update、insert、delete语句,引擎会自动加排它锁
执行select,引擎是不加任何锁的
行级锁是基于索引字段的,如果sql语句中没有涉及索引则会使用表级锁。
行级锁内存开销大,锁定数据量小,适合高并发场景

2.myisam存储引擎;
表级锁。
表示锁又分为读锁和写锁
读锁是共享的即其他事务可以同时读,但不能写。
加写锁时,其他事务不能读也不能写
表级锁内存开销小,锁定数据量大,适合存在大量select场景

总结

  1. 数据库的事务默认四个特性:ACID
    1. 原子性(Atomicity)
    2. 一致性(Consistent)
    3. 隔离性(Isolation)
    4. 持久性(Durable)
  2. 数据库访问的并发性问题(更新丢失、脏读、不可重复读、幻象读)会导致的数据的一致性被破坏。
  3. 数据库指定了4种事务的隔离级别,目的是为了解决数据库访问的并发性问题(更新丢失、脏读、不可重复读、幻象读)导致的数据的一致性被破坏。
    1. Read uncommitted(未授权读取、读未提交)
    2. Read committed(授权读取、读提交)
    3. Repeatable read(可重复读取) MySQL 默认隔离级别
    4. Serializable(序列化)
  4. 由于数据库的隔离级别灵活度较差,所以又有了悲观锁和乐观锁,也是用于解决数据库访问的并发性问题。
    1. 悲观锁
    2. 乐观锁
  5. Innodb和Myisam两种引擎
posted @ 2022-04-06 10:44  dawa大娃bigbaby  阅读(221)  评论(0编辑  收藏  举报