文章目录
一、并发控制
锁机制
锁类型:
- 读锁:共享锁,也称为 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会将各种警告和错误信息记录到错误日志文件中。
- log_error
- 这个参数指定了错误日志文件的路径和文件名。
- 默认情况下,MySQL 会将错误日志记录到系统默认的日志目录中。
- log_warnings
- 这个参数控制 MySQL 记录警告信息的级别。
- 取值范围是 0-3,默认为 2。
- 当设置为 0 时,MySQL 只会记录严重错误信息。
- 当设置为 1 或更高时,MySQL 会记录更多的警告信息。
- 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