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
相关推荐
Hello.Reader28 分钟前
Redis热点数据管理全解析:从MySQL同步到高效缓存的完整解决方案
redis·mysql·缓存
是程序喵呀1 小时前
MySQL备份
android·mysql·adb
指尖上跳动的旋律1 小时前
shell脚本定义特殊字符导致执行mysql文件错误的问题
数据库·mysql
一勺菠萝丶1 小时前
MongoDB 常用操作指南(Docker 环境下)
数据库·mongodb·docker
m0_748244832 小时前
StarRocks 排查单副本表
大数据·数据库·python
C++忠实粉丝2 小时前
Redis 介绍和安装
数据库·redis·缓存
wmd131643067123 小时前
将微信配置信息存到数据库并进行调用
数据库·微信
是阿建吖!3 小时前
【Linux】基础IO(磁盘文件)
linux·服务器·数据库
凡人的AI工具箱3 小时前
每天40分玩转Django:Django国际化
数据库·人工智能·后端·python·django·sqlite
ClouGence3 小时前
Redis 到 Redis 数据迁移同步
数据库·redis·缓存