1-MySQL事务特性

事务解释

事务是数据库系统提供出来方便应用系统做编程的。事务是数据库系统区别于文件系统的重要特征之一,事务具备的能力是应用程序迫切需要的。同时,不同存储引擎对事务的支持粒度完全不同,有的存储引擎甚至不支持事务,本文是以MySQL innodb引擎为对象进行说明的。

在SQL标准中,定义事物的语句有3条:
BEGIN TRANSACTION
COMMIT
ROLLCACK

各数据库系统会去实现数据库事物语意背后的实际操作。一般而言,我们会说数据库事务有4个特性:
原子性 atomicity
一致性 consistency
隔离性 isolation
持久性 durability

事务四个特性

如果说这四个特性中只让你选择一个特性用以保全事务功能,你会选哪一个?​​​​​​​
答案是一致性。
所谓一致,必须是有2个或2个以上的对象之间作比较,事务的一致性也是一样,他是前后2次不同的数据状态之间所作的比较。一致性要求事务的执行结果必须是将数据从一个一致性状态转移到另一个一致性状态。这个语义是非常抽象的,他从事务执行后数据状态正确性上给事务提出要求。而原子性是对事务包含的一连串操作的执行提出要求,原子性是事务对具体实现提出的规定。而隔离性是事务在面对多个事务并发时提出的约束,持久性则是事务对数据修改结果存储提出的要求。可见事务的四个特性是从各个角度对事务提出要求,给事务的实现作出明确指示,让应用系统能够方便使用事务。

事务的四个特性中,一致性是个较为抽象的概念,他是从数据逻辑状态对数据提出要求,他没有规定如何操作,总体来说,原子性、隔离性、持久性都是从具体操作上规定事务,而一致性只是从数据状态上提出约束。

数据库为什么要提供事务功能?

事务提供最基本的能力就是将一连串sql操作封装为原子操作,保证其不会被部分打断,原子性是我们使用事务最直观的需求,其次是隔离性。数据库为什么要提供事务能力?因为业务功能的需求,实际使用场景中,我们很多表是关联设计的,也就是数据是有联动关系的,所以在进行数据操作时,许多组合操作必须要一起完成,不能只完成一部分,如果完成一部分时出现错误,那就只能回滚之前所作的修改,这就是事务最基本的能力,事务能够简化我们的编程模型,不需要我们去考虑各种各样的潜在错误和并发问题。事务本质是为了应用服务的,并不是伴随数据库系统天生的。

MySQL的一个查询是事务吗?

是的,MySQL有个变量autocommit,分为会话级别和系统级别,查询方式分别如下:
show session variables like 'autocommit';
show global variables like 'autocommit';
设置方式分别如下:
set session autocommit=0;
set global autocommit=0;
需要注意的是,设置全局变量会在实例重启后失效。要想一直有效需要在配置文件中配置:
[mysqld] 
autocommit=0

mysql默认是开启自动提交的。

当mysql autocommit=1时是自动提交,这样设置以后,如果不显式指定事务开始和结束,那么每一个sql语句就是一个独立的事务,也就是上一个事务提交后,自动到了下一个事务的开始。如果设置autocommit=0,那每次会话开启了,就是事务的开始,直到手动commit,commit完成之时,也就是下一个事务begin之时。

隔离级别

在MySQL的众多存储引擎中,只有InnoDB支持事务,所有这里讨论的事务隔离级别指的是MySQL InnoDB下的事务隔离级别。事务隔离级别描述的是多个事务之间的一种作用效果,我们知道,每个sql一定在某个事务中,所以几乎可以这么任务,事务的隔离存在于你的每一条sql中,不知你是否有意识到。

一般而言,隔离级别分为:
读未提交:一个事务可以读取到另一个事务未提交的修改。这会带来脏读、幻读、不可重复读问题,这个级别会导致很多问题,从性能上说,不会比其他级别好很多,很少使用这个级别。
读已提交:一个事务只能读取另一个事务已经提交的修改,重复读取时可能读到另外事务执行前和执行后的数据,且2次数据不一致,所以他也叫不可重复读,其避免了脏读,但仍然存在不可重复读和幻读问题。不可重复读是个可大可小的问题,比如业务逻辑是根据查询值判断,在判断完后,条件成立与否发生改变,那这样就会出现违反判断的逻辑出现。
可重复读:同一个事务中多次读取相同的数据返回的结果是一样的。但是在读取某个范围的数据时,可能读到新增的记录。其避免了脏读和不可重复读问题,但幻读依然存在。
串行化:事务串行执行。通过强制事务串行执行,避免了以上所有问题,实际使用中,很少用到这个隔离级别,除非是需要确保数据的一致性且可以接受没有并发的情况。

以上是SQL-92标准中定义的四种隔离级别。在MySQL中,默认的隔离级别是REPEATABLE-READ(可重复读),并且解决了幻读问题。简单的来说,mysql的默认隔离级别解决了脏读、不可重复读问题。不可重复读重点在于update和delete,而幻读的重点在于insert。在这里,我们只讨论可重复读

事务为什么需要隔离级别特性?

数据库系统为了应用系统编程的便利,将事务功能集成到自身。没有事务的时候,数据库系统只需要保证单条SQL的执行结果,有了事务能力后,数据库系统需要保证多条SQL的执行结果。同时,在有了并发的业务场景后,还需要保证事务与事务之间SQL的同步执行结果。这种多条SQL的原子性以及并发执行的场景就要求事务与事务之间存在一种互斥关系,隔离性由此产生了。

首先说读未提交,这种隔离级别几乎是一种灾难性的隔离级别,因为多数业务场景下,他是存在致命隐患的,比如A事务多条SQL中有一条的效果是修改a=8,B事务中有一条的SQL是修改b=a+9,当B执行了以后,A却回滚了,B读取了一个已经回退的数据做了业务逻辑,这种后果不可预知,在计算机程序中就属于致命逻辑错误。

然后是读已提交,他的做法是没有提交的数据不让其他事务看见,提交了就立马让其他事务看见,由于事务是多条SQL构成的,如果B事务中前后多次读取A事务修改的数据,恰好是A事务执行前后的数据,那么前后读取的同一数据的值就会不一样,这种结果也是会产生致命逻辑错误的,比如事务X的逻辑是当前a>100是就执行a-50,首先是读取a并判断,然后才执行减法,如果读取时a=200,而执行a-50时,a已经不是200而是20,此时执行减法已经是不符合业务需求的,但是读已提交的隔离级别下就会继续执行,这种情况也是致命的错误。

然后是可重复读,可重复读保证事务前后读取的数据值相同,但是后者可能会读到新增的数据,这种情况下也有可能出现业务逻辑错误,但是,已经是比较少的了,因为业务场景往往是根据当前记录来做逻辑。

查看隔离级别

select @@tx_isolation;
select @@​​​​​​global.tx_isolation;

设置隔离级别

设置会话隔离级别
set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;

设置全局隔离级别
set global transaction isolation level read uncommitted;
set global transaction isolation level read committed;
set global transaction isolation level repeatable read;
set global transaction isolation level serializable;

通过配置文件设置
[mysqld]
transaction-isolation = REPEATABLE-READ
transaction-isolation = READ-COMMITTED
transaction-isolation = READ-UNCOMMITTED
transaction-isolation = SERIALIZABLE

这里有些术语需要了解下:
MVCC:multiversion concurrency control的全称是“多版本并发控制”。
这项技术使得InnoDB在事务隔离级别下执行一致性读操作有了保证,换言之,就是为了查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值。这是一个可以用来增强并发性的强大的技术,因为这样的一来的话查询就不用等待另一个事务释放锁。这项技术在数据库领域并不是普遍使用的。一些其它的数据库产品,以及mysql其它的存储引擎并不支持它。
行记录的可见性:MVCC实现了多个并发事务更新同一行记录会时产生多个记录版本,那问题来了,新开始的事务如果要查询这行记录,应该获取到哪个版本呢?即哪个版本对这个事务是可见的。这个问题就是行记录的可见性问题。
InnoDB会给数据库中的每一行增加三个字段,它们分别是DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID。
DB_TRX_ID表示最后一个事务的ID,每开启一个新事务,事务的版本号就会递增;
DB_ROLL_PTR指向当前记录项的undo log信息;
DB_ROW_ID标识插入的新的数据行的id。

1、事务隔离级别为读提交时,写数据只会锁住相应的行
2、事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。
3、事务隔离级别为串行化时,读写数据都会锁住整张表
4、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值