MySQL数据库事务内容详解(一)

发表于:2022-7-11 09:19

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:吃果冻不吐果冻皮    来源:掘金

#
MySQL
分享:
  什么是数据库事务?
  事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库 从一种一致性状态变到另一种一致性状态。事务是逻辑上的一组操作,要么都执行,要么都不执行。
  事务最经典例子就是转账了。假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。
  事物的四大特性(ACID)
  一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。
  原子性: 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
  一致性: 事务开始前和结束后,数据库的完整性约束没有被破坏。比如,A向B转账,不可能A扣了钱,B却没收到。多个事务对同一个数据读取的结果是相同的;
  隔离性: 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
  持久性: 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
  注意:
  在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。
  因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0用来禁止使用当前会话的自动提交。
  事务并发可能出现的情况
  脏读(Dirty Read)
  一个事务读到了另一个未提交事务修改过的数据(脏读只在读未提交隔离级别才会出现),例如:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
  会话B开启一个事务,把id=1的name为武汉市修改成温州市,此时另外一个会话A也开启一个事务,读取id=1的name,此时的查询结果为温州市,会话B的事务最后回滚了刚才修改的记录,这样会话A读到的数据是不存在的,这个现象就是脏读。
  不可重复读(Non-Repeatable Read)
  一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每对该数据进行一次修改并提交后,该事务都能查询得到最新值。(不可重复读在读未提交和读已提交隔离级别都可能会出现),例如:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
  会话A开启一个事务,查询id=1的结果,此时查询的结果name为武汉市。接着会话B把id=1的name修改为温州市(隐式事务,因为此时的autocommit为1,每条SQL语句执行完自动提交),此时会话A的事务再一次查询id=1的结果,读取的结果name为温州市。会话B再此修改id=1的name为杭州市,会话A的事务再次查询id=1,结果name的值为杭州市,这种现象就是不可重复读。
  幻读(Phantom)
  一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来(幻读在读未提交、读已提交、可重复读隔离级别都可能会出现)。例如,系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
  会话A开启一个事务,查询id>0的记录,此时会查到name=武汉市的记录。接着会话B插入一条name=温州市的数据(隐式事务,因为此时的autocommit为1,每条SQL语句执行完自动提交),这时会话A的事务再以刚才的查询条件(id>0)再一次查询,此时会出现两条记录(name为武汉市和温州市的记录),这种现象就是幻读。
  不可重复读与幻读的区别
  不可重复读侧重于修改,幻读侧重于新增或删除
  解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
  MySQL 事务隔离级别
  为了达到事务的四大特性,数据库定义了4种不同的事务隔离级别,由低到高依次为读未提交、读已提交、可重复读以及可串行化,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。MySQL的隔离级别的作用就是让事务之间互相隔离,互不影响,这样可以保证事务的一致性。
  读未提交(READ UNCOMMITTED)
  在读未提交隔离级别下,事务A可以读取到事务B修改过但未提交的数据。可能发生脏读、不可重复读和幻读问题,一般很少使用此隔离级别。
  读已提交/不可重复读(READ COMMITTED)
  在读已提交隔离级别下,事务B只能在事务A修改过并且已提交后才能读取到事务B修改的数据。读已提交隔离级别解决了脏读的问题,但可能发生不可重复读和幻读问题,一般很少使用此隔离级别。
  可重复读(REPEATABLE READ)
  在可重复读隔离级别下,事务B只能在事务A修改过数据并提交后,自己也提交事务后,才能读取到事务B修改的数据。可重复读隔离级别解决了脏读和不可重复读的问题,但可能发生幻读问题。
  提问:为什么上了写锁(写操作),别的事务还可以读操作?
  因为InnoDB有MVCC机制(多版本并发控制),可以使用快照读,而不会被阻塞。
  可串行化(SERIALIZABLE)
  各种问题(脏读、不可重复读、幻读)都不会发生,通过加锁实现(读锁和写锁)。
  读读操作不阻塞
  读写操作阻塞
  写读操作阻塞
  写写操作阻塞
  四种隔离级别的比较
  隔离级别高低比较:可串行化>可重复读>读已提交>读未提交
  隔离级别对性能的影响大小比较:可串行化>可重复读>读已提交>读未提交
  隔离级别越高,所需要消耗的MySQL性能越大(如事务并发严重性),为了平衡二者,一般建议设置的隔离级别为可重复读。
  事务隔离机制的实现基于锁机制和并发调度。
  其中,并发调度使用的是MVVC(多版本并发控制),通过保存修改的旧版本信息来支持并发一致性读和回滚等特性。
  因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是读已提交(不可重复读)内容,但是你要知道的是 InnoDB 存储引擎默认使用可重复读并不会有任何性能损失。InnoDB 存储引擎在分布式事务的情况下一般会用到可串行化隔离级别。
  注意:Oracle 默认采用的读已提交隔离级别。
  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号