Mysql并发控制和日志

文章目录


一、并发控制

锁机制

锁类型:

  • 读锁:共享锁,也称为 S 锁,只读不可写(包括当前事务)多个读互不阻塞 ,只能读不能写 别人也能看
  • 写锁:独占锁,排它锁,也称为 X 锁,写锁会阻塞其它事务(不包括当前事务)的读和写 写锁 别人看都看不了

锁的特性:

S 锁和 S 锁是兼容 的,X 锁和其它锁都不兼容

举个例子,事务 T1 获取了一个行 r1 的 S 锁,另外事务 T2 可以立即获得行 r1 的 S 锁,此时 T1 和 T2 共同获得行 r1 的 S 锁,此种情况称为锁兼容 ,但是另外一个事务 T2 此时如果想获得行 r1 的 X 锁,则必须等待 T1 对行 r1 锁的释放,此种情况也称为锁冲突

锁粒度:

  • 表级锁:MyISAM
  • 行级锁:InnoDB

实现:

  • 存储引擎:自行实现其锁策略和锁粒度
  • 服务器级:实现了锁,表级锁,用户可显式请求

分类:

  • 隐式锁:由存储引擎自动施加锁
  • 显式锁:用户手动请求

锁策略:

在锁粒度及数据安全性寻求的平衡机制

bash 复制代码
update students set teacherid=1 where stuid=6;   
同时在两个窗口执行只有一个能成功



加锁

bash 复制代码
LOCK TABLES 表名 [[AS] alias] 锁的类别  [, tbl_name [[AS] alias] lock_type] ...

锁的类别一共有两种:读锁和写锁。

bash 复制代码
lock tables students  read;
给表students加读锁。
unlock  tables;
释放锁。注意释放锁是把所有人为加的的锁去除。
flush tables  with  read  lock;   
整个数据库加锁

事务(transactions)

事务的概念

  • 事务是一种机制、一个操作序列,包含了一组数据库操作命令,并且把所有的命令作为一个整体一起向系统提交或撤销操作请求,即这一组数据库命令要么都执行,要么都不执行。
  • 事务是一个不可分割的工作逻辑单元,在数据库系统上执行并发操作时,事务是最小的控制单元。
  • 事务适用于多用户同时操作的数据库系统的场景,如银行、保险公司及证券交易系统等等。
  • 事务通过事务的整体性以保证数据的一致性。
  • 事务能够提高在向表中更新和插入信息期间的可靠性。

ACID特性: 特别注意

A:atomicity 原子性;整个事务中的所有操作要么全部成功执行,要么全部失败后回滚。

C:consistency一致性;数据库总是从一个一致性状态转换为另一个一致性状态,类似于质量守恒定律。(A有1w ,B 没有 。A给 B转1w ,始终保持A+B=1w。)

I:Isolation隔离性;一个事务所做出的操作在提交之前,是不能为其它事务所见。

D:durability持久性;一旦事务提交,其所做的修改会永久保存于数据库中。

mysql一般都是自动提交事务。

bash 复制代码
SELECT @@autocommit;查看是否自动提交事务。

为1自动提交,为0关闭自动提交。

set autocommit=0

关闭自动提交事务。

bash 复制代码
set autocommit=0
begin 开启事务
insert teachers values(null,'wyf',30,'M');
增加一个条目
rollback;回滚,begin之后的命令都不生效。
commit;输入commit命令则将命令执行结果写入磁盘。

注意:

create drop alter 这些命令是立即生效,rollback不可以撤回。

死锁

两个或多个事务在同一资源相互占用,并请求锁定对方占用的资源的状态。

bash 复制代码
BEGIN;
#开启事务
update students set classid=10;
#终端1

update students set classid=20;
#终端2

解决死锁问题

SHOW ENGINE INNODB STATUS;查看当前死锁信息。

KILL CONNECTION <connection_id>;;结束指定的数据库连接,从而强制释放该连接持有的锁资源。你需要先通过 SHOW PROCESSLIST 命令获取连接 ID。

一般情况下,数据库引擎会自动解决死锁问题,只需要设置相对应的等待超时时间。

事务隔离级别

bash 复制代码
select @@tx_isolation;
系统隔离级别,是系统自带的变量。


如何修改隔离级别?

bash 复制代码
vim  /etc/my.cnf
transaction-isolation='READ-UNCOMMITTED|READ-COMMITTED|REPEATABLE-READ|SERIALIZABLE'

退出重启即可。

MySQL 支持四种隔离级别,事务隔离级别从上至下更加严格。

隔离级别 脏读 可重复读 幻读 加读锁
读未提交 可以出现 可以出现 可以出现
读提交 不允许出现 可以出现 可以出现
可重复读 不允许出现 不允许出现 可以出现
序列化 不允许出现 不允许出现 不允许出现
  • READ UNCOMMITTED 未提交可读
    可读取到未提交数据,产生脏读。即事务A在操作这个时候,事务B可以读取到A修改的数据。
  • READ COMMITTED 提交可读
    可读取到提交数据,但未提交数据不可读,产生不可重复读,即可读取到多个提交数据,导致每次读取数据不一致可读。
  • REPEATABLE READ 幻读
    可重复读,多次读取数据都一致,产生幻读,即读取过程中,即使有其它提交的事务修改数据,仍只能读取到未修改前的旧数据。此为MySQL默认设置。
  • SERIALIZABLE 串读
    可串行化,未提交的读事务阻塞修改事务(加读锁,但不阻塞读事务),或者未提交的修改事务阻塞其它事务的读写(加写锁,其它事务的读,写都不可以执行)。会导致并发性能差。

MVCC和事务的隔离级别:

MVCC(多版本并发控制机制)只在READ COMMITTED和REPEATABLE READ两个隔离级别下工作。其他两个隔离级别都和MVCC不兼容,因为READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据行。而SERIALIZABLE则会对所有读取的行都加锁。

二、日志

MySQL 支持丰富的日志类型,如下:

  • 事务日志:transaction log

    事务日志的写入类型为"追加",因此其操作为"顺序IO";通常也被称为:预写式日志 write ahead logging事务日志文件: ib_logfile0, ib_logfile1

  • 错误日志 error log

  • 通用日志 general log

  • 慢查询日志 slow query log

  • 二进制日志 binary log

  • 中继日志 reley log,在主从复制架构中,从服务器用于保存从主服务器的二进制日志中读取的事件

事务日志

事务日志:transaction log

  • redo log:实现 WAL(Write Ahead Log) ,数据更新前先记录redo log。
  • undo log:保存与执行的操作相反的操作,用于实现rollback。

事务型存储引擎自行管理和使用,建议和数据文件分开存放。如果硬盘损坏,不会所有数据都没有。

bash 复制代码
show variables like '%innodb_log%';

1.innodb_log_buffer_size: 该参数设置了 InnoDB 日志缓冲池的大小,默认为 16 MB。这个缓冲池用于存储将要写入磁盘的日志数据。较大的缓冲池可以减少磁盘 I/O 操作,从而提高写入性能。

2.innodb_log_file_size: 该参数设置了每个 InnoDB 日志文件的大小,默认为 48 MB。较大的日志文件可以减少日志文件切换的频率,从而提高性能。但是过大的日志文件会占用更多磁盘空间。

3.innodb_log_files_in_group: 该参数设置了 InnoDB 日志组中的日志文件数量,默认为 2 个。日志组中的多个日志文件可以提高写入性能和容错性。

4.innodb_log_group_home_dir: 该参数指定了 InnoDB 日志文件的存储路径,默认为当前目录 ./。即安装目录。

5.innodb_log_write_ahead_size: 该参数设置了在写入日志之前要预读的字节数,默认为 8192 字节。这有助于减少磁盘 I/O 操作。

事务日志性能优化

bash 复制代码
select @@innodb_flush_log_at_trx_commit;
日志写入磁盘的默认方式。

修改日志写入磁盘的方式,在配置文件中修改。

bash 复制代码
innodb_flush_log_at_trx_commit=0|1|2
  • 1 此为默认值,日志缓冲区将写入日志文件,并在每次事务后执行刷新到磁盘。 这是完全遵守ACID特性
  • 0 提交时没有写磁盘的操作; 而是每秒执行一次将日志缓冲区的提交的事务写入刷新到磁盘。
    这样可提供更好的性能,但服务器崩溃可能丢失最后一秒的事务
  • 2 每次提交后都会写入OS的缓冲区,但每秒才会进行一次刷新到磁盘文件中。 性能比0略差一些,但操作系统或停电可能导致最后一秒的交易丢失
级别 0 1 2
安全性 较高 最高 最高
性能 最高 最差 较高

高并发业务行业最佳实践,是第三种配置,使其为2。

1.配置为2和配置为0,性能差异并不大,因为将数据从Log Buffer拷贝到OS cache,虽然跨越用户态与内核态,但毕竟只是内存的数据拷贝,速度很快。

2.配置为2和配置为0,安全性差异巨大,操作系统崩溃的概率相比MySQL应用程序崩溃的概率,小很多,设置为2,只要操作系统不奔溃,也绝对不会丢数据。

错误日志

错误日志

  • mysqld启动和关闭过程中输出的事件信息
  • mysqld运行中产生的错误信息
  • event scheduler运行一个event时产生的日志信息
  • 在主从复制架构中的从服务器上启动从服务器线程时产生的信息

错误文件路径

bash 复制代码
SHOW GLOBAL VARIABLES LIKE 'log_error' ;

mysql会将各种警告和错误信息记录到错误日志文件中。

  1. log_error
  • 这个参数指定了错误日志文件的路径和文件名。
  • 默认情况下,MySQL 会将错误日志记录到系统默认的日志目录中。
  1. log_warnings
  • 这个参数控制 MySQL 记录警告信息的级别。
  • 取值范围是 0-3,默认为 2。
  • 当设置为 0 时,MySQL 只会记录严重错误信息。
  • 当设置为 1 或更高时,MySQL 会记录更多的警告信息。
  1. log_error_verbosity
  • 这个参数控制 MySQL 记录错误信息的详细程度。
  • 取值范围是 1-3,默认为 3。
  • 当设置为 1 时,MySQL 只会记录最基本的错误信息。
  • 当设置为 2 时,MySQL 会记录更多的诊断信息。
  • 当设置为 3 时,MySQL 会记录最详细的错误信息。

通用日志

通用日志开启日志功能后,mysql会记录以下信息。

  • 客户端连接和断开连接的时间
  • 每个客户端执行的SQL语句
  • 每个SQL语句的执行时间
  • 每个SQL语句的结果及信息

通用日志可以保存在:file(默认值)或 table(mysql.general_log表)。

通用日志相关设置

bash 复制代码
general_log=ON|OFF
general_log_file=HOSTNAME.log
log_output=TABLE|FILE|NONE
bash 复制代码
select @@general_log;  
默认没有开启
set global general_log=1; 
开启
SHOW GLOBAL VARIABLES LIKE 'log_output';默认通用日志存放在文件中。
select @@general_log_file;
通用日志存放的文件路径。

慢查询日志

MySQL 的慢查询日志(Slow Query Log)是一种用于记录执行时间超过设定阈值的查询语句的日志功能。这对于分析和优化数据库性能非常有帮助。

相关变量:

bash 复制代码
slow_query_log=ON|OFF
开启或关闭慢查询,支持全局和会话,只有全局设置才会生成慢查询文件
long_query_time=N
慢查询的阀值,单位秒,默认为10s
slow_query_log_file=HOSTNAME-slow.log 
慢查询日志文件
log_slow_filter = admin,filesort,filesort_on_disk,full_join,full_scan,
query_cache,query_cache_miss,tmp_table,tmp_table_on_disk 
上述查询类型且查询时长超过long_query_time,则记录日志
log_queries_not_using_indexes=ON 
不使用索引或使用全索引扫描,不论是否达到慢查询阀值,都记录。
log_slow_verbosity= Query_plan,explain 
当设置了Query_plan 时,慢查询日志会记录查询的执行计划信息。
这些信息包括 MySQL 选择的索引、表扫描类型、join 类型等,可以帮助分析查询性能瓶颈。
当设置了 explain 时,慢查询日志会记录查询语句的 EXPLAIN 结果。

二进制日志 备份

  • 记录导致数据改变或潜在导致数据改变的SQL语句
  • 记录已提交的日志
  • 不依赖于存储引擎类型

MySQL 的二进制日志(Binary Log)是一个非常重要的日志功能,它主要用于以下两个方面:
复制(Replication)

  • 二进制日志记录了数据库的所有变更操作,从主库到从库的复制就是依靠这些日志实现的。
  • 从库通过读取主库的二进制日志来保持数据的一致性。

审计(Audit)

  • 二进制日志可以用于数据库的审计和恢复。
  • 通过分析二进制日志,可以查看数据库中发生的所有变更操作,并根据需要回滚某些操作。

注意:建议二进制日志和数据文件分开存放。

二进制日志记录三种格式

  • 基于"语句"记录:statement,记录语句,默认模式( MariaDB 10.2.3 版本以下 ),日志量较少。
  • 基于"行"记录:row,记录数据,日志量较大,更加安全,建议使用的格式,MySQL8.0默认格式。
  • 混合模式:mixed, 让系统自行判定该基于哪种方式进行,默认模式( MariaDB 10.2.4及版本以上)。
bash 复制代码
show variables like 'binlog_format';

二进制日志相关的服务器变量:

bash 复制代码
sql_log_bin=ON|OFF:
是否记录二进制日志,默认ON,支持动态修改,系统变量,而非服务器选项
log_bin=mysql-bin      默认是关闭
指定文件位置;默认OFF,表示不启用二进制日志功能,上述两项都开启才可以
binlog_format=STATEMENT|ROW|MIXED:
二进制日志记录的格式,mariadb5.5默认STATEMENT
max_binlog_size=1073741824:
单个二进制日志文件的最大体积,到达最大值会自动滚动,默认为1G
说明:文件达到上限时的大小未必为指定的精确值
binlog_cache_size=4m 
此变量确定在每次事务中保存二进制日志更改记录的缓存的大小(每次连接)
max_binlog_cache_size=512m 
限制用于缓存多事务查询的字节大小。
sync_binlog=1|0:
设定是否启动二进制日志即时同步磁盘功能,默认0,由操作系统负责同步日志到磁盘。
expire_logs_days=N:
二进制日志可以自动删除的天数。 默认为0,即不自动删除

注意:

sync_binlog

  • 这个参数控制着二进制日志刷新到磁盘的频率。
  • 当设置为 1 时,每次事务提交后,都会立即将二进制日志刷新到磁盘。
  • 这种设置可以确保即使服务器宕机,也不会丢失最新的二进制日志数据,但会对性能有一定影响。

二进制日志文件格式

有两类文件:

1.日志文件:mysql|mariadb-bin.文件名后缀,二进制格式,如: on.000001,mariadb-bin.000002

2.索引文件:mysql|mariadb-bin.index,文本格式,记录当前已有的二进制日志文件列表

注意:要给mysql的修改的权限。

验证是否生成二进制日志:

在线查看二进制

bash 复制代码
SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]

SHOW BINLOG EVENTS

这是命令的核心部分,用于显示二进制日志中的事件信息。

IN 'log_name'

这个参数用于指定要查看的二进制日志文件名称。

如果省略此参数,则默认查看当前正在写入的二进制日志文件。

FROM pos

这个参数用于指定从二进制日志的某个位置开始显示事件。

pos 表示事件在日志文件中的偏移量。

LIMIT [offset,] row_count

这个参数用于限制显示的事件数量。

offset 表示从第几个事件开始显示,row_count 表示最多显示多少个事件。

离线查看二进制日志

mysqlbinlog:二进制日志的客户端命令工具,支持离线查看二进制日志

命令格式:

bash 复制代码
mysqlbinlog [OPTIONS] log_file...
 --start-position=# 指定开始位置
 --stop-position=#
 --start-datetime=  #时间格式:YYYY-MM-DD hh:mm:ss
 --stop-datetime= 
 --base64-output[=name]
        -v -vvv

二进制日志事件的格式:

bash 复制代码
# at 328
#151105 16:31:40 server id 1 end_log_pos 431   Query   thread_id=1     
exec_time=0     error_code=0
use `mydb`/*!*/;
SET TIMESTAMP=1446712300/*!*/;
CREATE TABLE tb1 (id int, name char(30))
/*!*/;  
事件发生的日期和时间:151105 16:31:40
事件发生的服务器标识:server id 1
事件的结束位置:end_log_pos 431
事件的类型:Query 
事件发生时所在服务器执行此事件的线程的ID:thread_id=1
语句的时间戳与将其写入二进制文件中的时间差:exec_time=0
错误代码:error_code=0
事件内容:
GTID:Global Transaction ID,mysql5.6以mariadb10以上版本专属属性:GTID
相关推荐
Karoku06633 分钟前
【企业级分布式系统】ELK优化
运维·服务器·数据库·elk·elasticsearch
小技与小术2 小时前
数据库表设计范式
数据库·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验三 数据操作
运维·服务器·数据库·sql·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验九 触发器
数据库·sql·mysql·oracle·实验报告
Loganer2 小时前
MongoDB分片集群搭建
数据库·mongodb
LKID体2 小时前
Python操作neo4j库py2neo使用之创建和查询(二)
数据库·python·neo4j
刘大浪2 小时前
后端数据增删改查基于Springboot+mybatis mysql 时间根据当时时间自动填充,数据库连接查询不一致,mysql数据库连接不好用
数据库·spring boot·mybatis
一只爱撸猫的程序猿2 小时前
简单实现一个系统升级过程中的数据平滑迁移的场景实例
数据库·spring boot·程序员
无敌岩雀2 小时前
MySQL中的索引
数据库·mysql
a_安徒生3 小时前
linux安装TDengine
linux·数据库·tdengine