1、事务特性

  • 事务四大特性:原子性、一致性、隔离性、持久性
  • 三个特性(原子性,隔离性,持久性):通过预写日志redolog,undo日志保证
原子性:一个基本操作单元,要门全部执行,要么全部不执行
	A,B账户转账,A-100,B+100两个事情捆绑操作
	
持久性:事务执行成功后必须全部写入磁盘,一旦commit就保证数据被改变
	
隔离性:并发事务之间不会互相影响。由锁机制和MVCC机制来实现

一致性:事务执行请后都是稳定的,以上三条决定了一致性
	:唯一索引,主/外键约束
1.1、事物原子性如何保证的?
1、每一个写事务,都会修改BufferPool,产生对应的Redo/Undo日志,这些日志会被记录到日志文件中;
2、在mysql中,任何buffer pool中的页被刷到磁盘之前,都先回写到日志文件中
	:如果buffer pool中的脏页数据没有刷新成功,数据库挂了,数据库再次启动,可以通过redo日志将其恢复;
		commit之后数据库挂掉(redo重做恢复)
	:如果脏页数据刷新成功,数据库挂了,就需要undo来实现了;
		commit之前数据库挂掉(undo回滚恢复到历史版本)
*脏页:内存数据页跟磁盘数据页内容不一致时候,会产生脏页
1.2、事务的持久性如何实现的?
一旦commit,redologbuffer就会落盘成redolog
	:mysql修改数据时,同时在内存和redo log记录着此操作
	:commit之后数据库挂掉,数据库重启之后通过redolog将其改变
1.3、事物的隔离性如何实现,事务的隔离级别有哪些?
隔离性使用锁和多版本控制保证事物的隔离级别
	锁:
	MVCC:多版本并发控制,读取数据时通过一种类似快照的方式将数据保存下来,这样读锁和写锁就不冲突了,不同事物的session会看到自己特定版本的数据,版本链
	MVCC作用:某条纪录被修改,则可以并发控制读取该记录的历史版本而不必阻塞等待读锁的释放,即读取UndoLOG的历史版本,Read view保证是事物的取得是哪个版本
  • 事务的隔离级别

java事务与锁表 事务锁mysql_java事务与锁表

脏读:脏读指事务A读取到了事务B更新了但是未提交的数据,然后事务B由于某种错误发生回滚,那么事务A读取到的就是脏数据。

幻读:事务A在查询完记录总数后,事务B执行了新增数据的操作,事务A再次查询记录总数,发现两次查询的结果不一致,平白无故的多了几条记录,这种现象称为幻读。

不可重复读:不可重复读指在数据库访问时,一个事务在前后两次相同的访问中却读到了不同的数据内容。

提交覆盖:

***MYSQL采用RR(可重复读)的隔离级别,在间隙里采用GAP防止幻读
1.4、快照读与当前读的区别
快照读:读取的是记录的可见版本,不用加锁且不堵塞;

当前读:读取的是记录的历史版本,并且返回当前读返回的记录,都会加上锁,保证其他事务不会再并发控制这条记录
1.5、一致性是如何实现的?
一致性分类:约束一致性、数据一致性

约束一致性:创建表时的约束,主/外键,唯一索引等

数据一致性:通过原子性、持久性、隔离性保证

2、锁机制

  • 锁:计算机协调多个进程或线程并发访问控制某一资源的机制。
  • 锁使用独占方式来保证在只有一个版本情况的情况下事物之间相互隔离,所以锁可以理解为单版本控制。
2.1、Mysql支持的锁有哪些?有哪些使用场景?

(1)锁的分类

1、锁的粒度:表级锁和页级锁 

2、锁的操作:读锁和写锁
	
3、实现方式:乐观锁和悲观锁

使用场景:
	:1、修改表结构自动加上业级锁
	:2、更新数据未使用索引,行级锁上升为表级锁
	:3、更新数据使用索引会使用行级锁

java事务与锁表 事务锁mysql_死锁_02

表锁 - Mysqlserver
	read lock:加读锁后可以加读锁,不能加写锁
	write lock:加写锁后不能加读锁,也不能加写锁
	:r和r不互斥,w和w互斥,r和w互斥
	
元数据锁 - Mysqlserver
	:表结构发生变化
	CURD:增删改查(DDL)数据的时候加读锁;
	DDL:修改表结构的时候加写锁;

行级锁 - InnoDB
	共享读锁:手动加 - select ... lock in share mode
	排他写锁:自动加 - DML(insert,update,delete)
		   :select ... from update
		   
select 语句不加锁,可以通过MVCC读取历史版本;

(2)什么是读写锁,什么是排他锁?

读写锁:可以让读和读并行

排他锁:读和写、写和读、写和写
	:并行事务之间涉及到相同数据项时,会使用排他锁,先进入的事务独占数据项后,其他事务被阻塞,等待前面的事务释放锁

(3)行锁

  • 行锁原理
行锁:innoDB存储引擎实现,每次操作锁住一行数据,基于索引实现。锁定粒度最小,并发度最高
	有记录锁和间隙锁
  • 行锁分类
共享读锁:允许一个事务去读一行,组织其他事务获得相同数据集的排他锁。

排他写锁:允许获得排他写锁的事务更新数据,组织其他食物取得相同的数据集和共享读锁和派他写锁

(4)innoDB存储引擎的锁算法

Record lock:单个行记录上的锁
Gap lock:间隙锁,锁定一个范围,不包括记录本身
Next-key lock:record+gap锁定一个范围,包含记录本身
  • 唯一键加锁:行记录锁

java事务与锁表 事务锁mysql_数据库_03

  • 非唯一键加锁 - 记录锁和间隙锁

java事务与锁表 事务锁mysql_死锁_04

  • 无索引加锁
行锁升级为表锁,所有记录都被加记录锁,所有记录的间隙都被加间隙锁

java事务与锁表 事务锁mysql_数据库_05

2.2、死锁是如何产生的?
死锁:两个事务的锁发生发生冲突,互相等待对方的锁释放,不能继续执行事务逻辑,就会产生死锁

死锁的现象:表锁死锁、行锁死锁、共享锁转排他锁

(1)表锁死锁

产生原因
	:用户A由于用户B已经锁住表B,必须等待用户B释放表B才能释放,同样用户B要等待用户A释放表A才能继续,这样死锁就产生了

(2)行锁死锁

产生原因
	:两个事务分别想拿到特定的锁互相等待,于是产生死锁

(3)共享锁转排他锁

产生原因:
	:事务A查询一条记录,然后更新该条记录,此时事务B也更新该条记录
		:事务A会查询时有一个共享锁,事务B更新时会产生一个排他锁
		:事务A查询完毕后共享锁无法转化为排他锁,因为B已经有排他锁,故无法授予该请求
		:而事务B等待事务A释放其共享锁,故产生死锁

(4)死锁解决方式

在生产环境,sql查询出哪个spid处于wait状态,然后用killspid来干掉

(5)死锁如何避免

(1).按同一顺序访问对象。(注:避免出现循环)
(2).避免事务中的用户交互。(注:减少持有资源的时间,较少锁竞争)
(3).保持事务简短并处于一个批处理中。(注:同(2),减少持有资源的时间)