在操作数据库的时候,可能会由于并发问题而引起的数据的不一致性(数据冲突)。
锁定义:为了解决并发事务带来的资源抢占问题而诞生的,主要是确保数据库中,多条工作线程并行执行时的数据安全性。
事务
事务:最小的不可再分的工作单元,逻辑上是一组操作,要么都执行,要么都不执行。
事务执行出错了就需要rollback回滚,事务处理是一种对必须整批执行的 MySQL 操作的管理机制。
在开启事务之后,执行sql不会立即去执行,只有等到commit操作后才会统一执行(保证原子性)。
因为某一刻不可能总只有一个事务在运行,如果没有采用及时的隔离机制,就会产生并发异常。
并发事务会带来哪些问题?
-
1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
-
2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
-
3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
总结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
为了避免以上出现的各种并发问题,我们就必然要采取一些手段。mysql数据库系统提供了四种事务的隔离级别,用来隔离并发运行各个事务,使得它们相互不受影响,这就是数据库事务的隔离性。
并发控制——解决并发问题
并发控制是指在多进程同时访问数据库时,保证数据库操作的一致性和正确性的一种机制。它解决了在并发访问下可能出现的数据不一致、丢失更新和脏读等问题。
并发控制技术:
- 事务隔离级别(Isolation Levels): 数据库提供了多种隔离级别,如读未提交、读已提交、可重复读和串行化,用于控制事务之间的可见性。
- 锁(Locking): 使用锁机制可以控制对数据的访问,包括共享锁和排他锁,确保在某个事务对数据进行读取或修改时其他事务无法对其进行修改。
- 多版本并发控制(MVCC): 通过保存不同版本的数据来解决并发问题,允许事务在读取数据时不会被其他事务的写操作所阻塞。
- 时间戳(Timestamping): 使用时间戳来记录事务的开始和结束时间,以及数据的版本信息,通过比较时间戳来判断事务的执行顺序。
- 并发控制算法(Concurrency Control Algorithms): 包括基于事务的、基于锁的、基于时间戳的等不同算法来确保并发控制的正确性和效率。
MySQL事务隔离级别
一个事务的执行,本质上就是一条工作线程在执行,当出现多个事务同时执行时,这种情况则被称之为并发事务,所谓的并发事务也就是指多条线程并发执行。
多线程并发执行自然就会出问题,也就是脏写、脏读、不可重复读及幻读问题。而对于这些问题又可以通过调整事务的隔离级别来避免,那为什么调整事务的隔离级别后能避免这些问题产生呢?这是因为不同的隔离级别中,工作线程执行SQL语句时,用的锁粒度、类型不同。
用例子说明各个隔离级别的情况
1、读未提交:
- (1)打开一个客户端A,并设置当前事务模式为read uncommitted(未提交读),查询表account的初始值
- (2)在客户端A的事务提交之前,打开另一个客户端B,更新表account400-50=350
- (3)这时,虽然客户端B的事务还没提交,但是客户端A就可以查询到B已经更新的数据
- (4)一旦客户端B的事务因为某种原因回滚,所有的操作都将会被撤销,那客户端A查询到的数据其实就是脏数据
2、读已提交
- (1)打开一个客户端A,并设置当前事务模式为read committed(不可重复读),查询表account的所有记录
- (2)在客户端A的事务提交之前,打开另一个客户端B,更新表account
- (3)这时,客户端B的事务还没提交,客户端A不能查询到B已经更新的数据,解决了脏读问题
- (4)客户端B的事务提交commit
- (5)客户端A执行与上一步相同的查询,结果 与上一步不一致,即产生了不可重复读的问题
3、可重复读
- (1)打开一个客户端A,并设置当前事务模式为repeatable read,查询表account的所有记录400
- (2)在客户端A的事务提交之前,打开另一个客户端B,更新表account400-50=350
并提交
- (3)在客户端A查询表account的所有记录,与步骤(1)查询结果400一致,没有出现不可重复读的问题
- (4)