本文内容很多来自教材《Mysql 数据库技术与应用(慕课版)》,感谢作者写出了这么优秀的教材。
一.什么事务
事务是单个工作单元,是数据库中不可再分的基本部分.具体来说,事务是由用户定义的一个sql语句序列,在这组sql序列中,每个mysql语句时相互依赖的,整个sql语句组是一个不可分割的整体.如果在这个sql语句组某条sql语句一旦执行失败或产生错误,整个语句将会回滚,即将数据表中的数据返回到这个sql语句组开始执行前的状态.
mysql查看事务自动提交 为true or false
show variables like 'autocommit'
关闭自动提交模式
set autocommit = 0
begin;
执行语句一
执行语句二
commit;
未提交可以用 rollback; 回滚
二.事务的4个属性ACID
1.原子性(Atomicity):事务由一个或一组相互关联的sql语句组成, 这些语句被认为是一个不可分割的单元,对事务进行修改只能是完全提交或完全回滚
简单说:要执行都执行,不执行则都不执行。
2.一致性(Consistency):事务的一致性保含两层意思: 一是从数据的角度来看,事务必须是使数据库从一个一致性变为另一个一致性,一致性与原子性密切相关,在事务开始之前和结束之后,数据库的完整性约束没有被破坏;而是从用户的角度看,事务可确保对数据库修改是一致的,即多个用户查询到的数是一样的.
我理解:一致性就是 从上面的文字理解:从业务角度看 ,一个事务发生后,无论对于多个客户和还是一个客户,无论哪个事件段,数据数据状态都不会变化
3.隔离性(Isolation,孤立性):一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不应该相互干扰,这些通过锁来实现.实际应用中,事务的相互影响程度受到隔离级别的影响.
隔离性是对多个事务操作同一组数据时, 相互不影响彼此,最终数据结果符和逻辑。
4.持久性(Durability):指一个事务一旦提交后,对数据的修改和更新及时永久的.
事务成功后,数据形态及状态永久性发生变化, 直到下次事务发生。
三.事务的控制
start transaction| begin 用于开启一个事务
commit 表示提交一个事务
rollback 表示回滚一个事务
set autocommit = {0|1}表示用于设置提交事务的默认方式,0 表示禁用自动提交事务, 1 表示自动提交事务.and chain 表示会在当前事务结束时立刻启动一个新的事务,并且新事务与刚结束的事务有相同的隔离等级; release 表示在终止了当前事务后,会让服务器断开与当前客户端的连接.如果加上 no,则可以抑制chain 和release的完成.
四.事务的隔离级别
脏读(DIrty Read): 一个事务读取到了另一个事务未提交的的数据操作结果.你修改了数据,但没有提交,数据结果可能就不准确了。我却读到了你修改后的脏数据。不可重复读(Non-repeatable Reads):一个事务对同一行重复数据重复读两次,但却得到了不同的结果,即产生了虚读,也就是当事务读取某一数据后, 事务二对其做了修改,当事务再次读该数据时得到与第一次不同的值.
用我理解的话说:我读了两次, 第一次读和第二次读 的结果不一样,重复度的结果不一样
幻读(Phantom Reads):指事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺少了第一次查询中出现的数据,这是由于在两次查询过程中有另外一个事务更新了数据造成的.
用我的话说:我第一次读到了三条数据,第二次读到两条,让我产生了幻觉。
为了避免上述3种情况的发生,mysql 定义的了不同的隔离级别,以此来保证数据的稳定性。
1.读未提交(Read Uncommitted)
允许事务读取其他事务未提交的结果,是事务隔离级别中等级最低的,能容忍脏数据被读到。
2.读已提交(Read Committed)
允许事务读取其他事务已经提交的结果,该隔离级别可以避免脏读,但不能避免不可重复读和幻读的情况。
3.可重复度(Repeatable Read)
这是Mysql的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时会看到同样的数据行.可以避免脏读和幻读,不能避免幻读。是MySql默认的隔离级别
4.可串行化(Serializable)
这是最高的隔离级别,它通过强制事务排序,使事务只能一个接一个执行,不能并发执行,这样就从根本上阻止了事务之间的相互冲突,从而解决幻读问题.
查询当前会话的隔离级别
select @@tx_isolation
修改事务隔离级别的语法规则:
set[Global|session]Transation isolation level read uncommitted | Read committed | Repeatable read|Serializable ;
Global 表示此语句将应用于在此之后所有session,而当前已经存在的session不受影响."session"表示此语句将应用于在此之后所有session之内的以及之后的所有事务;session表示此语句将应用于包括当前session在内的及其后的所有事务;如果缺省.表示此语句将应用于当前session在内的后面未开始事务."Read uncommitted | Read committed | Repeatable read | Serializable"分别表示设置为读未提交/读以提交,可重复读 和可串行化.
隔离级别的选取
事务的隔离级别越高越能保证数据的完整性和一致性,但是对系统并发性能的影响越大。在选取数据库的隔离级别时,可以参照以下几个原则:
1.首先,需要排除数据脏读的影响,在多个事务之间要避免进行”非授权的读“操作。因为事务的回滚操作或失败将会影响其他的并发事务,第一个事务的回滚会完全将其他事务的操作清楚,这可能导致数据处于一个不一致的状态。
2.其次,数据的幻读可以通过使用悲观锁这种强行使所有事务都序列化执行的方式来解决。
3.对于大部分应用,可以优先考虑可重复读。
五.并发与并行
并发控制是 把时间分成若干的段。让多个线程快速交替轮换执行,使得在宏观上具有多个线程同时执行效果控制方法。
并行指的是同一时刻有多条指令在多个cpu上同时执行,无论从微观上还是宏观上来看,多个线程都是同时执行的。
六 锁机制:
mysql 中多种存储引擎,不同的存储引擎的锁机制之间本质上存在较大的区别。mysql 中常见的InnoDB 引擎 支持行级锁,但有时也会升级为表级锁,而MyISAM 引擎只支持表级锁。
表级锁的特点是开销小,加锁快,不会出现死锁。由于锁粒度大,发生锁冲突的概率较高,抗并发能力较低。
行级锁的特点是开销大,加锁慢,会出现死锁的情况。由于锁粒度小,发生锁冲突概率较低,抗并发能力较高。
实际上,各种隔离级别也是靠锁机制实现的。
InnoDB 锁类型
数据库系统中常见的锁粒度可以划分为表级锁,行级锁和页级锁,行级锁中主要的锁类型有读锁,写锁,而表级锁的锁有意向锁。
1.读锁
读锁又被称为共享锁(Shared Locks ,简称为S)。S锁的粒度是行级或元组级(多个行),多个不同的事务对一个资源共享一把锁。如果事务T1 对行R 加上S锁,会产生以下情况。
1.其他事务T2 T3 ......Tn 只能对行R加上S锁, 不能再加上其他的锁。
2.被加上S锁的数据,用户只能进行读取,不能写入数据(包括修改和删除)
3.如果需要修改数据,必须等所有的共享锁释放完。
Mysql 中共享锁的语法格式如下:
SELECT * FROM 表名 where 条件 Lock in share mode;
2.写锁
写锁又被称为排它锁(Exclusive Locks ,简称为X) X锁也是作用于行或者元组的。如果一个事务T1对行R加上X锁,会产生以下情况。
1.事务T1 可以 对行R 范围内的数据进行读取和写入操作(包括修改和删除)。
2.其他事务都不能对于R施加任何类型的锁,而且无法进行增删改操作,直到事务T1在行R上的X锁被释放。
Mysql 中设置X锁的语法格式如下。
SELECT * FROM 表名 where 条件 for update;
排它锁指的是一个事务为一行数据加上排它锁后,其他事务不能再在其上加其他锁。MySql 的InnoDB 引擎默认的修改语句update , delete, insert 都会自动给涉及的数据加上排它锁,select 语句默认不会加上任何锁。
3.意向锁
在InnoDB 引擎中 ,意向锁 的粒度 为表级。意向锁是数据库自身行为,不需要人工干预,在事务结束后会自行解除。意向锁分为意向共享锁IS, 和意向排它锁IX , 其主要作用是提升存储引擎的的性能。
在InnoDB 引擎中的S锁 和X锁为 行级锁,每当事务到来时,存储引擎需要遍历所有行的锁持有情况,这样会增加系统的性能损耗。因此Mysql 数据库系统引入了意向锁,在检查行级锁之前会先检查意向锁是否存在,如果存在则阻塞线程。
4.间隙锁
间隙锁是InnoDB 引擎在可重复读 的隔离级别下为了解决幻读和数据误删问题而引入的锁机制。
5.锁等待和死锁
锁等待是指在一个事务执行过程中,一个锁需要等上一个事务锁释放后才能可以使用该资源。如果事务一直不释放,就需要持续等待下去,直到超过锁等待时间,此时系统会报出超时错误。
Mysql 中锁等待时间是通过 innodb_lock_wait_timeout 参数控制。
查看锁等待时间
show variables like '%innodb_lock_wait%';
锁的锁监控 与 优化
Mysql 中可以通过 SHOW FULL PROCESSLIST 命令和 SHOW ENGINE INNODB STATUS 命令来监控 事务中锁的情况。也可以通过查询 inormation schema 库下的INNODB TRX INNODB LOCKS 和INNODB LOCK WAITS 这三张表 来获取更加详细的信息。
在使用InnoDB 引擎时, 应该注意以下几点
1.合理设置索引, 尽可能 让所有数据 检索都通过 索引来完成,从而避免InnoDB 引擎因为无法通过索引枷锁 而升级 为表级锁定的现象。
2.减少基于范围的数据检索,避免因间隙锁带来的负面影响而锁定了不该锁定的记录。
3.控制事务的大小,缩减锁定的资源量和锁定时间。
4.在业务允许的情况下,尽量使用较低级别的事务隔离,以减少MySql 实现事务隔离级别的附加成本。
在同一个事务中,尽可能做到一次性锁定需要的所有资源,降低死锁发生的概率。