MySql---事务/锁

《mysql 技术内幕》 读书笔记
 

一,认识事务

    1.概述:事务可由一条非常简单的sql组成,也可以是复杂的sql组成。事务是访问并更新数据中数据的一个程序指向单元。它的特点就是全部完成,全部失败,构成这个特点要满足四个特性:
  • 原子性:不可分割的工作单位
  • 一致性:就是不破坏原本的规则,就是一致,比如主键是唯一的,你事务处理修改主键,主键最后变成了不唯一的,就打破了规则,破坏了一致性。
  • 隔离性:并发控制,可串行化,锁,都是这个隔离性,这个事务对其他东西是不可见的,不能被插一脚。
  • 持久性:事务一旦提交,是永久性的,能够被恢复。
说明:A 原子性:C 一致性:I 隔离性:D 持久性:
    从5.5开始,不需要手动begin开启事务,只要你执行DML,会自动加上begin命令。
    事务的结束:当事务提交,submit,那么就征明完成了ACID特性。rollback回滚。
2.事务,线程,会话的区别和关系
    会话可以创建多个事务,事务可以由多个线程完成,也可以由一个线程完成,自然线程可以完成多个事务,他们是多对多的关系,但是同一时刻,一个线程只能做一个业务。
    他们的关系就如同:会话=你走到银行vip业务室;    线程就是银行的员工,事务就是你需要办理的业务,比如先给这个卡存50万,你拿了现金过来,你还想让银行兑现1万元单钱,你还想办理一个理财,那么我们就理解为三个事务,可能会让三个员工(线程)去处理,也可能让一个员工一个一个处理。总之,关于钱的事情,对于一个单独事务中,不能出错一个步骤,不然就失败。
3.分类-四种
  • 扁平事务:最简单的一种,使用最为频繁,它的操作通过三个命令:begin work;commit work; rollabck work;代表了开始,提交,回滚。回滚就回滚到begin wordk时候的状态,但是这里存在一些大型的事务,回滚到原点,会产生很大的开销,于是产生了一个保存点,可以指定回滚到保存点,对于begin word 其实也是一个保存点,称为保存点0,我们可以再加保存点,它的顺序是递增的,比如1,2,3.我们使用rollback wordk 3,就可以回滚到保存点3,回滚之后,出了0号,其他的事务任然是开启的,所以,任然可以回滚。
  • 链事务:保存点事务的变种,当带保存点的事务,在面临系统崩溃重启的时候,只能恢复到开始点,保存点消失了。链事务的思想:提交一个事务的时候,把必要的信息传给下一个事务,(将一个事务的提交和下一个事务的启动合并为一个原子操作),所以链事务的回滚就是直接回滚一个事务,不存在保存点(自然也不存在保存点丢失),而且commit伴随着锁的释放,第一种不会对锁操作(释放锁自认能提高并发)
  • 嵌套事务:是一个层次结构框架,树形结构,叶子节点就是扁平事务,而且只有叶子节点才会执行事务操作,InnoDB不支持嵌套事务,但是可以使用保存点扁平事务实现嵌套事务,高层的事务只是进行逻辑控制,决定合适调用相关的子事务。
  • 分布式事务:随着业务发展高并发下,就需要多个数据库之间通信了,比如银行跨行转账,(两个银行的数据库不可能在一起吧),那你一个银行的钱-100万,另外一个银行的卡没有+100万怎么办??这就需要分布式业务了。!很重要。(这里没有说基本实现是什么)
 

二,事务的实现

    

    redo log称为重做日志,保证事务的原子性和持久性;undo log用来保证事务的一致性。   两者不是互逆的,redo是恢复提交事务修改页的操作,undo是回滚行记录到某个特定版本。所以两者记录的内容不同,redo是物理日志,记录的是页的修改操作,undo是逻辑日志,根据每行记录进行记录。

 1.redo
    基本概念:redo分为两部分:重做日志缓冲(redo log buffer),重做日志文件(redo log file),前者是易丢失的,后者是持久的。
    InnoDB在实现commit操作的时候,必须将该事务的所有日志写入到redo log file里面(磁盘中)进行持久化,然后commit完成才算真的完成了事务。提交的日志就是保存在redo log buffer里面的信息。redo log都是顺序写的,不需要读操作,所以比较快。(为什么需要这个操作,那就是因为,当一个被修改,如果直接把内存中的页更新到磁盘中,那么是很费事的,因为这个表最小操作单位都是页,而我们把单纯的操作写入磁盘快得多)为了确保缓冲中的都写入了file中,每次InnoDb都需要在写入后调用一次fsync操作,而fsync操作取决于磁盘的性能,所以磁盘的性能决定了事务提交的性能。
    log buffer按一定的规则将内容提交到log file中:1.commit时;2.当buffer有一半的内存空间被占用时;3.checkpoint时。(在InnoDB中,mysql里面有两个50M的redo file,用来存放,两个进行循环使用)
log block:在InnoDB中,重做日志是以512字节进行存储的,所以buffer,file都是以block的方式进行保存,若一个页的重做日志》512B,则需要分成多个块,并且块和磁盘扇区一样大,所以可以保证原子性。
log group:逻辑上的概念,InnoDB中只有一个Log group。
LSN:代表日志序列号,占用八个字节,并且单调递增;( 代表了redo log写入的总量字节数,checkpoint的位置,页的版本),在页中也有一个lsn,存在于页的头部,重做日志记录以页为单位,所以两者的Lsn不一样的时候,在mysql重新载入的时候,就说明事务提交了,需要进行恢复。(为什么会不一样,页中的lsn代表的是写入了恢复到了log file中哪个字节位置了,而log中的lsn代表有多少字节,那么后者比前者大,说明就需要恢复执行。)
恢复,当Lsn追平的时候,触发checkpoint,把内存数据写入磁盘,正常启动。
TXID:事务号,事务的Id,递增的,伴随事务的声明周期。
 
2.undo
    redo是重做,就是对过去的数据库内容+操作来达到->当前的数据库内容。就是重写做了一遍(因为在运行的时候,内存中的数据库以及修改了,而磁盘中的还没有动)
    undo是回滚,它是重做的区别是什么呢?对redo的回滚,redo是把一切操作都记录进来了,而且在高并发的情况下,不管你有没有commit,都会写入到redo file中,如果事务没有commit中间出错了,(那就凉了)这个时候就需要把redo file中间那段进行了一半的事务操作,回滚到原来的状态,这就是undo的操作内容,功能。(redo是前滚)磁盘中的页始终是一个脏的东西,undo记录的不是操作,而是一个时间点的数据状态(相对于快照)
    虽然你感觉undo是把数据库恢复到事务保存点的位置,但是这个时候数据库已经被改变了,例如数据结构已经改变了,可能会有很大的不同。
    除了回滚操作,undo还实现mvcc,当读取的记录被其他事务占用,那么当前线程可以读取记录被事务占用之前的版本(这个可以理解,因为本来就是用来回滚的,只不过这个回滚的时间不同)而且undo log 会伴随着产生redo log。
    当事务提交的时候,InnoDb会做两个事情,1.将undo log放入列表(一个专门存放undo log的链表),以供之后的purge操作,2.判断undo log所在的页是否可以重用,可以就会分配给下个事务。
3.purge:删除可能并不会直接删除原来的数据,只是在索引树种标记一下删除flag。记录并没有被删除,真正的删除操作可能延时到了purge操作上面。InnoDB为什么这样设计?因为它支持mvcc(多版本并发),多个事务访问的时候,这个事务要求删除数据,其他事务可能还在读取数据,为了让其他事务还能读取,所以不会直接删除),这个purge操作可以理解为清除undo log。undo log被存放在一个history list种,后提交的事务存放在后面,所以purge清除会从开头进行,避免随机读取。
4.group commit:这里就是事务提交的时候,把redo 全部写入了redo file,但是里面有的事务还未提交,标记未prepare状态,启动的时候,又必须lsn持平,所以需要undo的回滚操作,既保持Lsn持平,又保证数据的原子性。
    

三,事务的隔离级别

    四种割裂级别是sql标准定义的,而具体的实现,更大数据库都有不同,而且可能不完全支持四种级别。
    InnoDB的实现(在RR级别里面sql标准是不支持幻读的,但是innoDB可以支持避免幻读,而且默认是这个级别)
  • read uncommintted:读未提交,可脏读(直接读内存中的页数据,但是可能没有提交)
  • read commintted:读已提交,别的事务commit,其他马上能读取到(有点像缓存一致性里面嘿嘿),防止脏读,存在幻读。未了控制一致性,可以在sql 末尾加for update保证一致性。
  • repeatable read:可重复读,防止幻读(一会独出来数据是这个,一会是另外一个。。这里的幻读是一个事务里面的幻读,而不是你的全程幻读,为了避免前后数据不一致),需要读取最新数据,那么在当前事务commit之后,再次读取,就可以读取到新数据。它的实现利用的就是undo快照技术。与锁有关系。
  • serializable:串行化,无法并发(效率完全不行),防止死锁。
 
(从上到下,隔离级别越高,锁越高,效率越低)
 
==================================================================
 

一,什么是锁

    应用为了提高,高并发,又要保证数据安全,所以锁的设计很重要,什么是锁,锁是控制数据处理权限的一种手段,由于sql的存在,所以感觉关系型数据库都大同小异,但是对于锁的实现,每个数据库给出的方案都有很大不同。所以这里要注意区分学习。

    对于MYISAM引擎,实现的是表锁设计,并发插入时性能差一些,微软的sql server是页锁,并发性能有所提高,但是对于热点数据无能为力。后来退出了乐观锁和悲观锁,乐观锁是行级锁了。而且锁还会升级

    InnoDB锁的实现于Oracle数据库相似,提供一致性的非锁定读,行级锁。

二,lock和latch

    latch:门锁,轻量级的锁,(锁的粒度要小,锁的时间短,这样才能支持高并发),在InnoDb中,又分为mutex(互斥量)和rwlock(读写锁)。对象是线程。无死锁机制。

    lock:对象是事务,用来锁数据库中的对象,并且lock锁住的对象一般在事务提交或者回滚之后数方。有死锁机制。

三,InnoDB存储引擎中的锁

    1,锁的类型:InnoDB实现了两种标准的行级锁:

  • 共享锁(S lock):允许事务读一行数据。

  • 排他锁(X lock):允许事务删除或更新一行数据。

    S只和S兼容,其他两个锁存在,都不兼容的。什么是兼容,就是当t1事务获取r行的共享锁(S),那么t2事务可以获取r行的共享锁,但是不能获得排他锁,要想获得排他锁,就要等待其他事务把r行的锁释放完,才能进行加索。这里就存在阻塞。

    对于MyISAM的表锁:上了读锁,本事务只能读取,不能写入,而且不能操作其他表。其他事务只是不能对读锁的表进行写,其他都可以操作,写不会报错,只会阻塞。

    InnoDB还支持多粒度锁定,在表,页,记录上面加锁,这种方式称为意向锁(Intention Lock),对行加X锁,需要对库,表,页加上IX锁,最后对行加上X锁。

    2.一致性非锁定读:当读取到一个事务在进行update或者delete的时候,不会去等待锁的释放,而是去读该行的快照数据。由undo段完成,

    3.一致性锁定读:就是在锁定的情况下,加入..for update 开启一致性。

    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL 中的并发控制和事务隔离级别是很重要的概念。在多个用户同时访问同一个数据库的情况下,如果不进行并发控制,就会出现数据不一致的问题。而事务隔离级别是指在多个事务同时执行的情况下,如何保证每个事务之间的数据隔离性。MySQL 支持多种隔离级别,包括: 1. 读未提交(Read Uncommitted):最低的隔离级别,允许一个事务读取另一个事务尚未提交的数据。这种隔离级别会导致脏读、不可重复读和幻读的问题。 2. 读已提交(Read Committed):允许一个事务只能读取另一个事务已经提交的数据。这种隔离级别可以解决脏读的问题,但是可能会出现不可重复读和幻读的问题。 3. 可重复读(Repeatable Read):允许一个事务读取另一个事务已经提交的数据,并且在事务结束之前,其他事务不能修改这些数据。这种隔离级别可以解决脏读和不可重复读的问题,但是可能会出现幻读的问题。 4. 串行化(Serializable):最高的隔离级别,确保每个事务都独立运行,没有并发问题。但是串行化会导致性能下降,因为它会定所有读取的数据。 在 MySQL 中,默认的隔离级别是可重复读。可以使用 SET TRANSACTION ISOLATION LEVEL 命令来设置隔离级别。同时,可以使用行级和表级来实现并发控制。行级可以定单独的行,而表级可以定整个表。在实际应用中,需要根据实际情况选择合适的隔离级别和的类型来保证数据的一致性和性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值