============================================
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条军规