MySQL 学习笔记四【事务和锁】

============================================

MySQL学习笔记【第四部分】

============================================

一. 事务

1.概述

数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作; 事务是一组不可再分割的操作集合(工作逻辑单元)

2.事务的ACID特性

- 原子性(Atomicity)

- 一致性(Consistency)

- 隔离性(Isolation)

- 持久性(Durability)

3.事务并发带来的问题

  • 脏读
  • 不可重复读
  • 幻读

4.事务隔离级别

- Read Uncommitted(未提交读) —解决并发问题【事务未提交对其它事务也是可见的,脏读】
- Read Committed(提交读) —解决脏读问题【一个事务开始之后,只能看到自己提交事务所做的修改,不可重复读】
- Repeatable Read(可重复读) —解决不可重复读问题【在同一个事务中多次读取同样的数据结果一样的,未定义解决幻读问题】
- Serialiazable(串行化) —解决所有问题【最高的隔离级别,通过强制事务的串行执行】

5.InnoDB引擎对隔离级别的支持程度

在这里插入图片描述

二. 锁

1.理解表锁、行锁

在这里插入图片描述

2.InnoDB锁类型

  • 共享锁(行锁):Shared Locks
  • 排它锁(行锁):Exclusive Locks
  • 意向共享锁(表锁):Intension Shared Locks
  • 意向排它锁(表锁):Intension Exclusive Locks
  • 自增锁:AUTO-INC Locks

行锁算法:

  • 记录锁 Record Locks
  • 间隙锁 Gap Locks
  • 临键锁 Next-key Locks

3.共享锁、排它锁

共享锁:

共享锁又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。
加锁释锁方式:

select * from users WHERE id=1 LOCK IN SHARE MODE;
 commit/rollback

排它锁:

排它锁又称为写锁,简称X锁,排它锁不能与其他锁共存,如一个事务获得了一个数据行的排它锁,其他事务就不能在获取该行的锁(共享锁,排它锁),只有获取了排它锁的事务是可以对数据进行读取和修改的(其它事务读取数据可来自于快照)
加锁释锁方式:

delete / update / insert 默认加上X锁 
SELECT * FROM table_name WHERE ... FOR UPDATE 
commit/rollback

InnoDb-行锁到底锁了什么

InnoDB的行锁是通过给索引上的索引项加锁来实现的。
只有通过索引条件进行数据检索,InnoDB才使用行级锁,否则,InnoDB 将使用表锁(锁住索引的所有记录)
表锁:lock tables xx read/write;

4.意向共享锁(IS)、意向排它锁(IX)

意向共享锁:

表示事务准备给数据行加入共享锁,即一个数据行加共享锁前必须先取得该表的IS锁, 意向共享锁之间是可以相互兼容的。

意向排它锁:

表示事务准备给数据行加入排他锁,即一个数据行加排他锁前必须先取得该表的IX锁, 意向排它锁之间是可以相互兼容的。

意义

当事务想去进行锁表时,可以先判断意向锁是否存在,存在时则可快速返回该表不能 启用表锁

意向锁(IS、IX)是InnoDB数据操作之前自动加的,不需要用户干预

5.自增锁AUTO-INC Locks

针对自增列自增长的一个特殊的表级别锁

show variables like 'innodb_autoinc_lock_mode';

默认取值1,代表连续,事务未提交ID永久丢失

6.记录锁(Record)、间隙锁(Gap)、临键锁(Next-Key)

Next-Key Locks

锁住记录+区间(左开右闭)
当sql执行按照索引进行数据的检索时,查询条件为范围查找(between and、<、>等)并有数 据命中则此时SQL语句加上的锁为Next-key locks,锁住索引的记录+区间(左开右闭)
在这里插入图片描述

Gap Locks

锁住数据不存在的区间(左开右开)
当sql执行按照索引进行数据的检索时,查询条件的数据不存在,这时SQL语句加上的锁即为 Gap locks,锁住索引不存在的区间(左开右开)
在这里插入图片描述
Record Locks
锁住具体的索引项
当sql执行按照唯一性(Primary key、Unique key)索引进行数据的检索时,查询条件等值匹 配且查询的数据是存在,这时SQL语句加上的锁即为记录锁Record locks,锁住具体的索引项
在这里插入图片描述

7.解决脏读、不可重复读、幻读

1 利用X锁解决脏读
在这里插入图片描述

2 利用S锁解决不可重复读
在这里插入图片描述
3 利用Next-Key解决幻读
在这里插入图片描述

8.死锁

死锁介绍:

  • 多个并发事务(两个以上)
  • 每个事务都持有锁(或者是已经在等待锁)
  • 每个事务都需要再继续持有锁
  • 事务之间产生加锁的循环依赖,形成死锁

死锁的避免:

  • 类似的业务逻辑以固定的顺序访问表和行。
  • 大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。
  • 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概 率。
  • 降低隔离级别,如果业务允许,将隔离级别调低也是较好的选择
  • 为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添 加上锁(或者说是表锁)

9.MVCC

查看MySQL的设置的事务隔离级别

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

MVCC概述

多版本并发控制(Multiversion concurrency control),并发访问(读或写)数据库时,对正在事务内处理的数据做 多版本的管理。以达到用来避免写操作的堵塞,从而引发读操 作的并发问题。

MVCC逻辑流程-插入
在这里插入图片描述
MVCC逻辑流程-删除
在这里插入图片描述
MVCC逻辑流程-修改
在这里插入图片描述
MVCC逻辑流程-查询
在这里插入图片描述
Undo log
undo意为取消,以撤销操作为目的,返回指定某个状态的操作undolog指事务开始之前,在操作任何数据之前,首先将需操作的数据备份到一个地方(UndoLog)
UndoLog是为了实现事务的原子性而出现的产物
UndoLog实现事务原子性
事务处理过程中如果出现了错误或者用户执行了ROLLBACK语句,Mysql可以利用UndoLog中的备份将数据恢复到事务开始之前的状态
UndoLog在Mysqlinnodb存储引擎中用来实现多版本并发控制
Undolog实现多版本并发控制:
事务未提交之前,Undo保存了未提交之前的版本数据,Undo中的数据可作为数据旧版本快照供其他并发事务进行快照读
在这里插入图片描述

快照读:

SQL读取的数据是快照版本,也就是历史版本,普通的SELECT就是快照读
innodb快照读,数据的读取将由cache(原本数据)+undo(事务修改过的数据)两部分组成

当前读:

SQL读取的数据是最新版本。通过锁机制来保证读取的数据无法通过其他事务进行修改UPDATE、DELETE、INSERT、SELECT…LOCKINSHAREMODE、SELECT…FORUPDATE都是当前读。

Redo log
Redo,顾名思义就是重做。以恢复操作为目的,重现操作;
Redolog指事务中操作的任何数据,将最新的数据备份到一个地方(RedoLog)Redolog的持久:
不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo中。具体的落盘策略可以进行配置
RedoLog是为了实现事务的持久性而出现的产物

Undolog实现多版本并发控制:
事务未提交之前,Undo保存了未提交之前的版本数据,Undo中的数据可作为数据旧版本快照供其他并发事务进行快照读

在这里插入图片描述

Redo log补充

  • 指定Redolog记录在{datadir}/ib_logfile1&ib_logfile2可通过innodb_log_group_home_dir配置指定目录存储

  • 一旦事务成功提交且数据持久化落盘之后,此时Redolog中的对应事务数据记录就失去了意义,所以Redolog的写入是日志文件循环写入的

  • 指定Redolog日志文件组中的数量innodb_log_files_in_group默认为2

  • 指定Redolog每一个日志文件最大存储量innodb_log_file_size默认48M指定Redolog在cache/buffer中的buffer池大小innodb_log_buffer_size默认16M

  • Redobuffer持久化Redolog的策略,Innodb_flush_log_at_trx_commit:

  • 取值0每秒提交Redobuffer–>RedologOScache–>flushcachetodisk[可能丢失一秒内的事务数据]

  • 取值1默认值,每次事务提交执行Redobuffer–>RedologOScache–>flushcachetodisk [最安全,性能最差的方式]

  • 取值2每次事务提交执行Redobuffer–>RedologOScache再每一秒执行->flushcacheto disk操作

3.配置优化

MySQL服务器参数类型

基于参数的作用域:
全局参数setglobalautocommit=ON/OFF;
会话参数(会话参数不单独设置则会采用全局参数):setsessionautocommit=ON/OFF;
注意:
全局参数的设定对于已经存在的会话无法生效
会话参数的设定随着会话的销毁而失效
全局类的统一配置建议配置在默认配置文件中,否则重启服务会导致配置失效

mysql--help寻找配置文件的位置和加载顺序
Defaultoptionsarereadfromthefollowingfilesinthegivenorder:
/etc/my.cnf/etc/mysql/my.cnf/usr/etc/my.cnf~/.my.cn
fmysql--help|grep-A1'Defaultoptionsarereadfromthefollowing filesinthegivenorder'

全局配置文件配置

最大连接数配置:max_connections
系统句柄配置:/etc/security/limits.confulimit-a
MySQL句柄数配置:/usr/lib/systemd/system/mysqld.service

常见全局配置文件配置

port=3306
socket=/tmp/mysql.sock
basedir=/usr/local/mysql
datadir=/data/mysql
pid-file=/data/mysql/mysql.pid
user=mysql
bind-address=0.0.0.0
max_connections=2000
lower_case_table_names=0#表名区分大小写
server-id=1
tmp_table_size=16
Mtransaction_isolation=REPEATABLE-READ
ready_only=1
...

MySQL内存参数配置
每一个connection内存参数配置:

  • sort_buffer_sizeconnection排序缓冲区大小:建议256K(默认值)->2M之内当查询语句中有需要文件排序功能时,马上为connection分配配置的内存大小
  • join_buffer_sizeconnection关联查询缓冲区大小:建议256K(默认值)->1M之内当查询语句中有关联查询时,马上分配配置大小的内存用这个关联查询,所以有可能在一个查询语句中会分配很多个关联查询缓冲区
  • 上述配置4000连接占用内存:4000*(0.256M+0.256M)=2G

Innodb_buffer_pool_size
innodbbuffer/cache的大小(默认128M)Innodb_buffer_pool

  • 数据缓存
  • 索引缓存
  • 缓冲数据
  • 内部结构
    大的缓冲池可以减小多次磁盘I/O访问相同的表数据以提高性能
    参考计算公式:Innodb_buffer_pool_size=(总物理内存-系统运行所用-connection所用)*90%

MySQL其他参数配置

  • wait_timeout:服务器关闭非交互连接之前等待活动的秒数

  • innodb_open_files:限制Innodb能打开的表的个数

  • innodb_write_io_threads:innodb使用后台线程处理innodb缓冲区数据页上的读写I/O(输入输出)请求

  • innodb_read_io_threads:innodb使用后台线程处理innodb缓冲区数据页上的读写I/O(输入输出)请求

  • innodb_lock_wait_timeout:InnoDB事务在被回滚之前可以等待一个锁定的超时秒数

4.数据库设计

在这里插入图片描述
在这里插入图片描述

注:希望读者如果有时间的话可以去了解一下58同城的30条军规

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章