MVCC
Multiversion concurrency control (多版本并发控制)
并发访问(读或写)数据库时,对正在事务内处理的数据做多版本的管理。以达到用来避免写操作的堵塞,从而引发读操作的并发问题。
这里看一个案例
begin
// 这里默认是加上X锁的,在未做commit/rollback操作之前
update users set lastUpdate=now() where id =1;
// 在其他的事务我们能不能进行对应数据的查询 但是我这时查询是能查到的当前时间这条记录
select * from users where id = 1;
先来看看MVCC的处理机制
插入数据
同一个事务,事务行版本号相同
删除数据
![](https://i-blog.csdnimg.cn/blog_migrate/fc30529af23856ec1a078db6adf8df22.png)
![](https://i-blog.csdnimg.cn/blog_migrate/347742de24b35d1fdcd9b05ac740fd50.png)
![](https://i-blog.csdnimg.cn/blog_migrate/da80381e4023d785d8d92413a9f43fb7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4ddf5a9bdf01941d1569e11bbfbf419c.png)
那这些数据时怎么来的呢
Undo Log
- undo意为取消,以撤销操作为目的,返回指定某个状态的操作
- UndoLog是为了实现事务的原子性而出现的产物
- Undo Log实现事务原子性:事务处理过程中如果出现了错误或者用户执行了 ROLLBACK语句,MySQL可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。
- UndoLog在MySQL innodb存储引擎中用来实现多版本并发控制
- Undo log实现多版本并发控制:事务未提交之前,Undo保存了未提交之前的版本数据,Undo 中的数据可作为数据旧版本快照供其他并发事务进行快照读
执行流程
这就是为什么加了X锁的数据我们还能查询的原因,他实际上是读取undo log里面的数据进行快照读
当前读与快照读的区别
Innodb引擎的普通select都是快照读。只有增删改和加了锁的才是当前读
Redo Log
- Redo,顾名思义就是重做。以恢复操作为目的,重现操作;
- Redo log指事务中操作的任何数据,将最新的数据备份到一个地方 (Redo Log)
- Redo log的持久:不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo 中。具体的落盘策略可以进行配置
- RedoLog是为了实现事务的持久性而出现的产物
- Redo Log实现事务持久性:防止在发生故障的时间点,尚有脏页未写入磁盘,在重启MySQL服务的时候,根据redo log进行重做,从而达到事务的未入磁盘数据进行持久化这一特性。
执行流程
![](https://i-blog.csdnimg.cn/blog_migrate/ec4dfd4e1739b4cb5c1c5d9753f34510.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0e592415a47fb0adf4fe2022ccab77fe.png)
指定Redo log 记录在{datadir}/ib_logfile1&ib_logfile2 可通过innodb_log_group_home_dir 配置指定目录存储
一旦事务成功提交且数据持久化落盘之后,此时Redo log中的对应事务数据记录就失去了意义,所以Redo log的写入是日志文件循环写入的
指定Redo log日志文件组中的数量 innodb_log_files_in_group 默认为2
指定Redo log每一个日志文件最大存储量innodb_log_file_size 默认48M
指定Redo log在cache/buffer中的buffer池大小innodb_log_buffer_size 默认16M
Redo buffer 持久化Redo log的策略, innodb_flush_log_at_trx_commit:
取值 0 每秒提交 Redo buffer --> Redo log OS cache -->flush cache to disk[可能丢失一秒内的事务数据]
取值 1 默认值,每次事务提交执行Redo buffer --> Redo log OS cache -->flush cache to disk[最安全,性能最差的方式]
取值 2 每次事务提交执行Redo buffer --> Redo log OS cache 再每一秒执行 ->flush cache to disk操作
配置优化
改配置说明
如果是docker可以通过启动选择配置文件启动
如果不想重启的话可以利用 set global
set global 参数=?
寻找配置文件位置和加载顺序
mysql --help | grep -A 1 'Default options are read from the following files in the given order'
这是我docker中MySQL的配置文件位置和加载顺序
MySQL服务器参数类型
全局参数
set global autocommit = ON/OFF;
会话参数(<font color=red >会话参数不单独设置则会采用全局参数</font>)
set session autocommit = ON/OFF;
注意:
全局参数的设定对于已经存在的会话无法生效
会话参数的设定随着会话的销毁而失效
全局类的统一配置建议配置在默认配置文件中,否则重启服务会导致配置失效
全局配置文件配置
最大连接数配置(如果连接数过大会有约束,就需要考虑改句柄数了)
max_connections
系统句柄数配置
/etc/security/limits.conf
ulimit -a
MySQL句柄数配置
/usr/lib/systemd/system/mysqld.service
常用配置说明
port = 3306 #端口号
socket = /tmp/mysql.sock #为MySQL客户程序与服务器之间的本地通信指定一个套接字文件
basedir = /usr/local/mysql #安装 MySQL 的安装路径
datadir = /data/mysql #数据库文件路径
pid-file = /data/mysql/mysql.pid #记录当前MySQL进程的pid
user = mysql #表示MySQL的管理用户
bind-address = 0.0.0.0 #MySQL服务器的IP地址。如果MySQL服务器所在的计算机有多个IP地址,这个选项将非常重要
max_connections=2000 #MySQL服务器同时处理的数据库连接的最大数量
lower_case_table_names = 0 #表名区分大小写
server-id = 1 #数据库id号一般主从复制的时候会用到
tmp_table_size=16M #临时表大小
transaction_isolation = REPEATABLE-READ #隔离级别
ready_only=1 #0是读写1是只读
其他参数配置
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事务在被回滚之前可以等待一个锁定的超时秒数