5.ロック
5.1 概要
ロックは、コンピュータが複数のプロセスまたはスレッドによるリソースへの同時アクセスを調整するためのメカニズムです。データベースでは、コンピューティング リソース (CPU、RAM、I/O) をめぐる従来の競争に加え、データは多くのユーザーによって共有されるリソースでもあります。データへの同時アクセスの一貫性と有効性をどのように確保するかは、すべてのデータベースが解決しなければならない問題です。ロックの競合も、データベースへの同時アクセスのパフォーマンスに影響を与える重要な要素です。この観点から見ると、ロックはデータベースにとって特に重要かつ複雑です。
MySQL のロックは、ロックの粒度に応じて次の 3 つのカテゴリに分類されます。
- グローバル ロック: データベース内のすべてのテーブルをロックします。
- テーブルレベルのロック: 操作ごとにテーブル全体をロックします。
- 行レベルのロック: 各操作は、対応する行データをロックします。
5.2 グローバルロック
5.2.1 はじめに
グローバル ロックとは、データベース インスタンス全体をロックすることです。ロック後、インスタンス全体は読み取り専用状態になります。更新された後続の DML (データ操作言語) 書き込みステートメント、DDL (データ定義言語) ステートメント、およびトランザクション コミット ステートメントは、ブロックされます。
その一般的な使用シナリオは、データベース全体の論理バックアップを作成し、すべてのテーブルをロックして一貫したビューを取得し、データの整合性を確保することです。
データのバックアップ: データベース内のデータを SQL ファイルにバックアップし、それをディスクにバックアップすることを指します。
データベース全体の論理バックアップを完全にロックする必要があるのはなぜですか?
A. まず、グローバル ロックを追加せずに考えられる問題を分析してみましょう。
データベースに 3 つのテーブル (tb_stock 在庫テーブル、tb_order 注文テーブル、tb_orderlog 注文ログ テーブル) があるとします。
- データのバックアップを実行する場合、最初に tb_stock インベントリ テーブルがバックアップされます。
- 次に、ビジネス システムでは、注文操作が実行され、在庫が差し引かれ、注文が生成されます (tb_stock テーブルが更新され、tb_order テーブルが挿入されます)。
- 次に、tb_order テーブルをバックアップするロジックを実行します。
- 業務で注文ログ挿入操作を実行します。
- 最後に、tb_orderlog テーブルがバックアップされました。
現時点でバックアップされたデータに問題があります。バックアップされたデータのため、tb_stock テーブルと tb_order テーブルのデータは矛盾しています (最新の操作の注文情報はありますが、在庫は減っていません)。
では、この問題を回避するにはどうすればよいでしょうか? 現時点では、MySQL のグローバル ロックを使用して解決できます。
B. グローバル ロックを追加した後の状況を分析してみましょう。
データベースの論理バックアップを実行する前に、まずデータベース全体にグローバル ロックを追加します。グローバル ロックを追加すると、他の DDL (定義言語) と DML (追加、削除、変更) はすべてブロックされますが、DQL (クエリ) はブロックされます。ステートメントは読み取り専用状態で実行でき、データのバックアップはクエリ操作です。データの論理バックアップのプロセス中、データベース内のデータは変更されないため、データの一貫性と整合性が確保されます。
ロック後は読み取りのみ可能ですが、書き込みはできません。
5.2.2 構文
1).グローバルロックを追加
#对当前数据库实例加上全局锁
#登录Mysql之后执行
flush tables with read lock ;
2).データのバックアップ
#借助mysql当中提供的一个工具mysqldump 指定备份时访问数据库的用户名和密码
#itcast :你要备份的哪个数据库
#itcast.sql:把备份的数据存到哪一个sql文件当中
#此命令不能登录mysql之后执行,只能是在外面没有登录的窗口格式中执行
mysqldump -uroot –p1234 itcast > itcast.sql
データのバックアップに関連する手順については、後の MySQL 管理の章で詳しく説明します。
3). グローバルロックを解除します。
#登录Mysql之后执行
unlock tables ;
5.2.3 デモ: グローバル ロックによるデータ バックアップ
sqlyog を使用して、Windows システムにローカルにインストールされたデータベースを開きます
正確なデータベース
データの準備: 学生テーブルとコース スケジュールは多対多の関係なので、中間テーブルの学生コース スケジュールもあります
create table student(
id int auto_increment comment '主键ID' primary key,
name varchar(10) null comment '姓名',
no varchar(10) null comment '学号'
)comment '学生表';
INSERT INTO student (name, no) VALUES ('黛绮丝', '2000100101');
INSERT INTO student (name, no) VALUES ('谢逊', '2000100102');
INSERT INTO student (name, no) VALUES ('殷天正', '2000100103');
INSERT INTO student (name, no) VALUES ('韦一笑', '2000100104');
create table course(
id int auto_increment comment '主键ID' primary key,
name varchar(10) null comment '课程名称'
)comment '课程表';
INSERT INTO course (name) VALUES ('Java');
INSERT INTO course (name) VALUES ('PHP');
INSERT INTO course (name) VALUES ('MySQL');
INSERT INTO course (name) VALUES ('Hadoop');
create table student_course(
id int auto_increment comment '主键' primary key,
studentid int not null comment '学生ID',
courseid int not null comment '课程ID',
constraint fk_courseid foreign key (courseid) references course (id),
constraint fk_studentid foreign key (studentid) references student (id)
)comment '学生课程中间表';
INSERT INTO student_course (studentid, courseid) VALUES (1, 1);
INSERT INTO student_course (studentid, courseid) VALUES (1, 2);
INSERT INTO student_course (studentid, courseid) VALUES (1, 3);
INSERT INTO student_course (studentid, courseid) VALUES (2, 2);
INSERT INTO student_course (studentid, courseid) VALUES (2, 3);
INSERT INTO student_course (studentid, courseid) VALUES (3, 4);
3 つの Dos ウィンドウを開く: 3 つのセッションをシミュレートします。
最初のウィンドウ: バックアップ前にグローバル ロックを追加します。
#先登录上mysql
mysql -uroot -proot
#加上全局锁
flush tables with read lock ;
2 番目のウィンドウ: グローバル ロックを追加すると、他のクライアントは読み取りのみ可能になり、書き込みはできなくなります。
mysql -uroot -proot
use db01;
#可以查询
select * from student;
#不可以更新:此时光标一直处于阻塞状态
update student set name ='A' where id = 2;
3 番目のウィンドウ: データのバックアップ
#mysqldump是mysql提供的一个工具不是sql语句,所以不能再mysql的命令行中执行,需要在windows命令行中执行。
#如果访问的不是本机数据库 还要加上-h指定主机地址
mysqldump -uroot –proot db01> D:/db01.sql
最初のウィンドウのロックを解除します
unlock tables ;
2 番目のウィンドウで、update ステートメントを再度実行することで更新できます。
update student set name ='A' where id = 2;
5.2.4 機能
データベースへのグローバル ロックの追加は比較的負荷の高い操作であり、次の問題があります。
- メインデータベースでバックアップを行った場合、バックアップ期間中は更新ができず、基本的に業務が停止します。
- スレーブ データベースでバックアップを実行すると、スレーブ データベースはバックアップ期間中にマスター データベースから同期されたバイナリ ログ (binlog) を実行できず、マスターとスレーブ間の遅延が発生します。
- 企業のデータベースがマスター・スレーブ構造で読み書きが分離されている場合、マスターデータベースへの書き込み時にはスレーブデータベースからバックアップできるため、このときの書き込み操作がブロックされることはありませんが、スレーブ データベースに書き込むと、スレーブ データベースからバックアップできるようになりますが、バックアップ期間中、スレーブ ライブラリはマスター ライブラリから同期されたバイナリ ログを実行できず、マスターとスレーブの遅延が発生するという新たな問題が発生します。
InnoDB エンジンでは、バックアップ中にパラメータを追加して--single-transaction
非ロックを完了し、データの一貫したバックアップを確保できます。
意味: このパラメータの追加は実際には Mysql InnoDB エンジンの一番下で行われ、実際にはスナップショット読み取りによって実装されます。
#在备份的时候加上--single-transaction这个参数
mysqldump --single-transaction -uroot –p123456 itcast > itcast.sql
注: この方法では、グローバル ロックを追加する必要はありません。
5.2.5 デモ: スナップショットによるデータのバックアップ
最初のステップ: データを準備します。以前の db01 データベースを引き続き使用します。
ステップ 2: 新しい dos ウィンドウを開いてコマンドを入力します。
mysqldump --single-transaction -uroot –proot db01> D:/db02.sql
5.3 テーブルレベルのロック
5.3.1 はじめに
テーブルレベルのロックでは、操作ごとにテーブル全体がロックされます。ロックの粒度は大きく、ロック競合の可能性は最も高く、同時実行性は最も低くなります。MyISAM、InnoDB、BDB などのストレージ エンジンに適用されます。
テーブルレベルのロックの場合、主に次の 3 つのカテゴリに分類されます。
- テーブルロック
- メタデータロック(MDL)
- インテンションロック
5.3.2 テーブルロック
テーブル ロックの場合、次の 2 つのカテゴリに分類されます。
- テーブル共有読み取りロック (読み取りロック): 読み取りロック
- テーブル排他書き込みロック(ライトロック):書き込みロック
文法:
- ロック: テーブルをロック テーブル名...読み取り/書き込み
- 複数のテーブルを一度にロックできる
- 読み取りロックですか、それとも書き込みロックですか?
- ロックを解放します: テーブルのロックを解除し、クライアントを切断します。
特徴:
A. 読み取りロック
処理: クライアント 1 はこのテーブルに読み取りロックを追加します。この時点で、クライアント 1 はこのテーブルのデータを読み取ることができますが、このテーブルに書き込むことはできません。クライアント 2 は、このテーブルのデータを読み取ることはできますが、書き込むことはできません。クライアント 1 は、このビジネス ロジックの実行を完了した後、unlock tables ステートメントを通じてテーブル ロックを解放します。
左側はクライアント 1 で、指定されたテーブルに読み取りロックが設定されています。読み取りのみ可能ですが、書き込みはできません。右側のクライアント 2 の読み取りには影響しませんが、右側のクライアントの書き込みはブロックされます。 。
テスト:
学生テーブルの構造:
2 つのセッション ウィンドウを開き、どちらも mysql にログインし、db01 データベースに切り替えます。
最初のセッションウィンドウ
mysql -uroot -proot
use db01;
#加上读锁
lock tables student read;
#读取是没有问题的
select * from student ;
#写操作不能够执行
update student set name = "bb" where id = 2;
#释放锁
unlock tables;
2番目のセッションウィンドウ
mysql -uroot -proot
use db01;
#读取是没有问题的
select * from student ;
#写操一直作处于阻塞状态,一旦第一个会话窗口释放了锁就可以执行成功了
update student set name = "bb" where id = 2;
B. 書き込みロック
プロセス: クライアント 1 は、このテーブルに書き込みロックを追加します。クライアント 1 は読み取りと書き込みの両方ができますが、クライアント 2 は読み取りも書き込みもできません。その後、テーブルのロックを解除すると、ロックが解放されます。
左側のクライアント 1 は、指定されたテーブルに対して読み取りと書き込みの両方が可能な書き込みロックを持っています。これにより、右側のクライアント 2 は読み取りと書き込みがブロックされます。
テスト:
最初のウィンドウ
mysql -uroot -proot
use db01;
#加上写锁
lock tables student write;
# 可以读
select * from student ;
#可以写
update student set name = "小米" where id = 4;
#释放锁
unlock tables;
2番目のウィンドウ
mysql -uroot -proot
use db01;
# 不可以读
select * from student ;
#不可以写,一直处于阻塞状态,一旦客户端1的窗口释放了锁就可以执行了。
update student set name = "小米" where id = 4;
結論: 読み取りロックは他のクライアントの読み取りをブロックしませんが、書き込みをブロックします。書き込みロックは、他のクライアントによる読み取りと書き込みの両方をブロックします。
5.3.3 メタデータのロック
メタデータ ロック、メタデータ ロック、略称 MDL。
MDL ロック プロセスは、システムによって自動的に制御されます。ロックなどのキーワードを明示的に使用して手動でロックする必要はありません。テーブルにアクセスすると、メタデータ ロックが自動的に追加されます。MDL ロックの主な機能は、テーブル メタデータのデータ整合性を維持することです。テーブルにアクティブなトランザクションがある場合、メタデータを書き込むことはできません。DML (crud) と DDL (データ定義言語: create table) の間の競合を避けるために、読み取りと書き込みが正確であることを確認してください。
ここでのメタデータは、単純にテーブルのテーブル構造として理解できます。つまり、あるテーブルにコミットされていないトランザクションが含まれる場合、そのテーブルのテーブル構造を変更することはできません。
MDL は MySQL 5.5 で導入されました。テーブルが追加、削除、変更、チェックされると、MDL 読み取りロック (共有) が追加され、テーブル構造が変更されると、MDL 書き込みロック (排他的) が追加されます。
- 読み取りロックには互換性がありますが、書き込みロック、および書き込みロックと読み取りロックは相互に排他的です。
一般的な SQL 操作中に追加されるメタデータ ロック:
SQLに対応 | ロックタイプ | 説明する |
---|---|---|
lock tables xxx read / write (特定のテーブルに読み取りロックまたは書き込みロックを追加) | SHARED_READ_ONLY / SHARED_NO_READ_WRITE (対応するメタデータ ロックを追加します) | |
select、select … 共有モードでロック (クエリを実行するか共有ロックを追加) | SHARED_READ (メタデータ ロックに読み取りロック/共有ロックを自動的に追加します) | SHARED_READ、SHARED_WRITE と互換性あり、EXCLUSIVE とは相互に排他的 |
更新のために挿入、更新、削除、選択… | SHARED_WRITE (メタデータ ロックに書き込みロックが自動的に追加されます。実際には、メタデータ ロックの読み取りロック/共有ロックでもあります) | SHARED_READ、SHARED_WRITE と互換性あり、EXCLUSIVE とは相互に排他的 |
alter table… (テーブル構造を変更するという意味) | EXCLUSIVE (メタデータ ロックに書き込みロック/排他ロックが自動的に追加されます) | 他の MDL と相互排他的 |
- SHARED_READ および SHARED_WRITE 共有ロックは相互に互換性があります
- SHARED_READ、SHARED_WRITE、および EXCLUSIVE 排他ロックは相互に排他的です
デモ:
他のステートメントを実行するとSELECT、INSERT、UPDATE、DELETE
、メタデータ共有ロックが追加されます(SHARED_READ / SHARED_WRITE)
。共有ロックには互換性があるため、2 つのクライアントは任意の方法でそれを実行できます。
つまり、クライアント 1 にはこの時点で共有ロックがあり、クライアント 2 にもこの時点では共有ロックがあります。共有ロックには互換性があるため、2 つのクライアントは必要なものを何でも実行できます。
クライアント 1:
mysql -uroot -proot
use db01;
#开启事务
begin;
#查询操作
select * from student;
#提交事务
commit;
クライアント 2:
mysql -uroot -proot
use db01;
#开启事务
begin;
#查询操作
select * from student;
#提交事务
commit;
SELECT ステートメントが実行されると、メタデータ共有ロック ( SHARED_READ
) が追加され、メタデータ排他ロック ( EXCLUSIVE
) がブロックされます。これらは相互に排他的です。
つまり、クライアント 1 はこの時点で共有ロックを持ち、クライアント 2 はこの時点で排他的ロックを持っています。共有ロックと排他的ロックは相互に排他的であるため、クライアント 2 はブロッキング状態になります。メタデータのロックは、クライアント 1 がトランザクションをコミットするまで解放されるため、クライアント 2 はテーブル構造を更新できます。
クライアント1
#开启事务
begin;
#查询操作
select * from student;
#提交事务
commit;
クライアント2
#开启事务
begin;
#修改表结构:往表中新添加一个字段,处于阻塞状态,直到客户端1提交事务此时元数据锁就释放了,
# 这样客户端2就可以更新表结构了。
alter table student add column java int;
次の SQL を使用して、データベース内のメタデータのロック状況を確認できます。
注:
- mysql8 以降のバージョンに適用されます。mysql5 バージョンにはこのmetadata_locks テーブルがありません。
- トランザクションが送信されると、メタデータ ロックは発生しません。メタデータ ロックは、トランザクション クエリが送信されない場合にのみ表示されます。
#查看当前数据库表当中,所涉及到的元数据锁。
#这条sql语句实际上查询的是我们系统表当中的metadata_locks这张表,在这张表当中
# 就记录了我们当前数据库实例当中的元数据锁。
select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema.metadata_locks ;
操作中に、上記の SQL ステートメントを通じてメタデータ ロックのロック ステータスを確認できます。
5.3.4 インテンションロック
1 はじめに
DML の実行時に追加される行ロックとテーブル ロックの間の競合を回避するために、 InnoDB ではインテンション ロックが導入され、テーブル ロックでデータの各行がロックされているかどうかを確認する必要がなくなります。インテンション ロックはテーブル ロックのチェックを減らすために使用されます。これによりパフォーマンスが向上します。
インテンション ロックがない場合、クライアントがテーブルのペアに行ロックを追加した後、クライアント 2 はどのようにテーブル ロックをテーブルに追加しますか? 概略図を使って簡単に分析してみましょう。
まず、クライアント 1 がトランザクションを開き、次に DML 操作を実行します。DML ステートメントが実行されると、関係する行に行ロックが追加されます。
クライアント 2 が同時操作を実行し、このテーブルにテーブル ロックを追加したい場合、テーブル内の行にはすでに行ロックが追加されているため、このテーブルにテーブル ロックを直接追加することはできません。 table を table にロックすると、行ロックとテーブル ロックの間で競合が発生します。したがって、クライアント 2 がテーブル ロックを追加するときは、まず現在のテーブルに対応する行ロックがあるかどうかを確認します。このとき、データの最初の行から最後の行まで行ロックがあるかどうかを確認します。そうでない場合は、テーブル ロックを追加します。
DML ステートメントを実行する際の行ロックとテーブル ロックの間の競合を解決するために、InnoDB にインテンション ロックが導入されました。これにより、テーブル ロックはチェック時にデータの各行がロックされているかどうかをチェックする必要がなくなります。インテンション ロックは次の目的で使用されます。テーブルのロック チェックを減らすことで、パフォーマンスが向上します。
インテンションロックを取得した後:
クライアント 1 は、DML 操作を実行するときに、関係する行に行ロックを追加します同时也会对该表加上意向锁
。
他のクライアントがこのテーブルにテーブル ロックを追加すると、会根据该表上所加的意向锁来判定是否可以成功加表锁
(このテーブルのインテンション ロックが現在のテーブル ロックと互換性がある場合、直接ロックされます。このテーブルのインテンション ロックが現在のテーブル ロックと互換性がある場合)、追加されたテーブルロックは互換性がないため、クライアント 1 がトランザクションをコミットして行ロックと意図ロックを解放するまでブロック状態のままになります。その後、ブロック状態が解除され、テーブル (テーブル ロック) が取得されます。行ロックの状況を行ごとに確認します。
2) 分類
- 意図共有ロック (IS): select ... lock in share mode ステートメントを実行すると自動的に追加されます。
- テーブル ロックの共有ロック (読み取り) と互換性があり、テーブル ロックの排他ロック (書き込み) とは相互に排他的です。
- 意図排他ロック (IX): 更新ステートメントの挿入、更新、削除、選択... を実行するときに自動的に追加されます。
- 共有ロック (読み取り) と排他的ロック (書き込み) はテーブル ロックと相互排他的ですが、インテンション ロックは相互排他的ではありません。
トランザクションがコミットされると、インテンション共有ロックとインテンション排他ロックは自動的に解放されます。
インテンションロックと行ロックのロック状態は、以下のSQLで確認できます。
#操作的是data_locks表
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;
3) デモンストレーション:
A. インテンション共有ロックとテーブルロックの互換性
クライアント 1:
begin;
#在select 语句后面加上lock in share mode表示,它会加上这一行行锁的共享锁,
# 同时为student 这张表加上意向共享锁。
select * from student where id=1 lock in share mode;
commit;
クライアント 2:
#查看这张表的行锁和意向锁是否加上
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;
#为student这张表加上读锁
# 成功:因为意向共享锁与读锁兼容
lock tables student read;
#为student这张表加上写锁
# 阻塞状态:因为意向共享锁与读锁互斥,如果客户端1提交事务就会释放行锁和表锁,这样表锁的写锁也就添加成功了
lock tables student write;
B. インテント排他ロック、テーブル読み取りロック、および書き込みロックは相互に排他的です。
クライアント 1:
begin;
#在执行update语句时会自动为这一行加上行锁,与此同时为这张表加上意向排他锁
update student set name="ccc" where id =2 ;
commit;
クライアント 2:
#查看这张表的行锁和意向锁是否加上
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;
#为student这张表加上读锁
# 阻塞:因为意向排他锁与读锁互斥,如果客户端1提交事务就会释放行锁和表锁,这样表锁的读锁也就添加成功了
lock tables student read;
5.4 行レベルのロック
5.4.1 はじめに
行レベルのロックでは、各操作に対応する行データがロックされます。ロックの粒度は最も小さく、ロックの競合の可能性は最も低く、同時実行性は最も高くなります。InnoDB ストレージ エンジンに適用されます。
InnoDB のデータはインデックスに基づいて編成され、行ロックは索引上的索引项加锁
レコードのロックではなくペアを通じて実装されます。行レベルのロックの場合、主に次の 3 つのカテゴリに分類されます。
InnoDB データはインデックスに基づいて編成されます。インデックス結果の b+tree 構造、InnoDB ストレージ エンジンの分類されたクラスター化インデックスとセカンダリ インデックス、クラスター化インデックスのハング行データのリーフ ノード、セカンダリ インデックスのリーフ ノード主キーをハングします。行データはクラスター化インデックスに基づいて保存されるため、InnoDB と呼ばれるデータはインデックスに基づいて編成されます。
-
行ロック/レコード ロック (レコード ロック) :
锁定单个行记录的锁
他のトランザクションがこの行を更新および削除できないようにします。RC (コミットされた読み取り: ダーティ読み取りをサポートしません、非反復読み取りをサポート、およびファントム読み取りをサポートします) および RR (反復可能読み取り: ダーティー読み取りをサポートしません、非反復読み取りをサポートしません、およびファントム読み取りをサポートします) でサポートされます。読み取り)分離レベル。
-
ギャップ ロック:
锁定索引记录的间隙
(このレコードを除く) インデックス レコードのギャップが変更されないようにし、他のトランザクションがこのギャップに挿入されてファントム読み取りが発生するのを防ぎます。RR 分離レベルでサポートされます。ギャップ: 2 レコード間の範囲、6 と 12 の間のギャップ、16 と 18 の間のギャップ。
-
Next-Key Lock :
行锁和间隙锁组合
データを同時にロックし、データの前のギャップをロックします。RR 分離レベルでサポートされます。例: 34 に一時キー ロックを追加します。これにより、34 行のレコードがロックされ、34 レコードの前のギャップがロックされます。
5.4.2 行ロック
1 はじめに
InnoDB は、次の 2 種類の行ロックを実装します。
- 共有ロック (S): 1 つのトランザクションが行を読み取ることを許可し、他のトランザクションが同じデータ セットに対して排他ロックを取得できないようにします。
- つまり、共有ロックと共有ロックの主キーは互換性があり、共有ロックと排他的ロックは相互に排他的です。
- 排他ロック (X): 排他ロックを取得するトランザクションがデータを更新できるようにし、他のトランザクションが同じデータ セットに対して共有ロックや排他ロックを取得できないようにします。
- つまり、このオブジェクトがこのデータ行の排他ロックを取得すると、この時点でデータを更新できます。最初のものが特定のデータ行の排他ロックを取得すると、他のものはこのデータ行の共有ロックと排他ロックを取得できなくなります。
2 つの行ロックの互換性は次のとおりです。
- 共有ロックと共有ロック間:互換性あり
- トランザクション a は共有ロックを取得し、トランザクション b も引き続きこのデータ行の共有ロックを取得できます。
- 共有ロックと排他ロックの間: 競合
- トランザクション a がこのデータ行の共有ロックを取得すると、トランザクション b はこのデータ行の排他ロックを取得できなくなります。
- 排他ロックと排他ロックの間: 競合
一般的な SQL ステートメントが実行される場合、追加される行ロックは次のとおりです。
SQL | 行ロックの種類 | 説明する |
---|---|---|
入れる … | 排他ロック | 自動ロック |
アップデート … | 排他ロック | 自動ロック |
消去 … | 排他ロック | 自動ロック |
セレクト(通常) | 不加任何锁 |
|
選択 … 共有モードでロック | 共有ロック | SELECT の後に LOCK IN SHARE MODE を手動で追加する必要がある |
…を選択して更新してください | 排他ロック | SELECT の後に FOR UPDATE を手動で追加する必要があります |
2). デモンストレーション デフォルト
では、InnoDB は REPEATABLE READ デフォルトのトランザクション分離レベルで実行され、ファントム リードを防ぐために検索およびインデックス スキャンにネクスト キー キー ロックを使用します。
- ケース 1:一意のインデックスに対して取得する場合、既存のレコードに対して同等の一致を実行する場合、一時キー ロックは行ロックに自動的に最適化されます。
- つまり、SELECT ステートメントは一意のインデックスと等しい値の一致を満たしている必要があり、Huawei の対応する行レベルの共有ロックと行レベルの排他ロックを取得するには、LOCK IN SHARE MODE と FOR UPDATE を追加する必要があります。
- SELECT ステートメントに 2 つのキーワード (LOCK IN SHARE MODE と FOR UPDATE) しかなく、一意のインデックスと等しい値の一致を満たさない場合、それは行ロックではありません。
- 状況 2: InnoDB の行ロックはインデックスのロックです。インデックス条件を通じてデータが取得されない場合、InnoDB はテーブル内のすべてのレコードをロックします (つまり、テーブル ロック)
此时就会升级为表锁
。
インテンションロックと行ロックのロック状態は、以下のSQLで確認できます。
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from
performance_schema.data_locks;
サンプルデモンストレーション
データの準備:这张表只有一个主键索引
CREATE TABLE `stu` (
`id` int NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int NOT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4;
INSERT INTO `stu` VALUES (1, 'tom', 1);
INSERT INTO `stu` VALUES (3, 'cat', 3);
INSERT INTO `stu` VALUES (8, 'rose', 8);
INSERT INTO `stu` VALUES (11, 'jetty', 11);
INSERT INTO `stu` VALUES (19, 'lily', 19);
INSERT INTO `stu` VALUES (25, 'luci', 25);
行ロックをデモンストレーションする場合は、上記の表を使用してデモンストレーションします。
A. 通常の select ステートメントは実行時にロックされません。
客户端1:
mysql -uroot -p1234
use db01;
begin;
#简单地select语句不会加任何行锁
select * from stu where id = 1;
客户端2:
#通过以下SQL,查看意向锁及行锁的加锁情况
#查询结果为空,说明当前没有加锁
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;
#既然都没有加锁,此时在开启一个事务去查询相同的stu表当中id为1的数据
#可以查询,因为这条语句不会加锁
begin;
#简单地select语句不会加任何行锁
select * from stu where id = 1;
B.選択...共有モードでロック、共有ロックを追加、共有ロックは共有ロックと互換性があります。
客户端1:
#对id为1的这条记录,加上共享锁
select * from stu where id = 1 LOCK IN SHARE MODE;
客户端2:
#此时会有2个锁,不看这个TABLE IS意向共享锁,看的是下面这个行锁共享锁 没有间隙
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;
#再次执行相同的sql,发现执行成功:共享锁和共享锁之间是兼容的
select * from stu where id = 1 LOCK IN SHARE MODE;
#再次查询锁情况发现:id为1的这条记录加了2个共享锁
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;
クライアント 1:
クライアント 2:
共有ロックと排他ロックは相互に排他的です。
客户端2:
commit;
begin;
#提交事务就会释放掉客户端2的共享锁,此时开启一个新的事物查看就只剩下客户端1的共享锁了(id为1的数据)
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;
#共享锁与排他锁之间互斥
#给id=3的记录添加排它锁,成功,因为客户端1是给id=1的记录添加的共享锁
update stu set name = "java" where id = 3;
#给id=1的记录添加排他锁,处于阻塞状态
update stu set name = "java" where id = 1;
最后:演示完成后把客户端1和客户端2的事务都进行提交,此时id=1的这条记录的共享锁和排它锁都释放了
commit;
クライアント 1 は、ID 1 の行の共有ロックを取得します。クライアント 2 は、同じデータ行ではないため、ID 3 の行の排他ロックを取得できます。そして、クライアント 2 が ID 1 の行の排他ロックを取得したい場合、共有ロックと排他ロックが相互に排他的であると考えられ、ブロック状態になります。
C. 排他ロックと排他ロックの相互排他
客户端1:
begin;
#添加排它锁
update stu set name = "web" where id = 1;
客户端2:
begin;
#添加排它锁排它锁和排它锁之间互斥,所以处于阻塞状态,直到客户端1提交了事务释放了这行记录的排他锁
# 此时客户端2的这个语句就可以执行了。
update stu set name = "web" where id = 1;
クライアント 1:
クライアント 2:
クライアント 1 が更新ステートメントを実行すると、ID 1 のレコードに排他ロックが追加されます。クライアント 2 も更新ステートメントを実行して ID 1 のデータを更新すると、ID のデータにも排他ロックが追加されます。 1 ですが、クライアントは排他ロックが相互に排他的であるため、2 番目の端末はブロック状態になります。この行の行ロックは、クライアント 1 がトランザクションをコミットするまで解放されません。この時点で、クライアント 2 のブロックは解除されます。
D. インデックスのない行ロックはテーブル ロックにアップグレードされます。
stu テーブルのデータは次のとおりです。
select * from stu;
両方のクライアントで次の操作を実行します。
客户端1:
begin;
#更新正常情况下添加的是行锁排它锁,但是name字段没有索引所以会升级为表锁
update stu set name = "xiaohei" where name= "lily";
客户端2:
begin;
#按理说此时操作不同的记录添加行锁排它锁是成功的,但是由于升级为表锁所以处于阻塞状态。
# 直到客户端1提交事务释放表锁,此时就可以执行成功了。
update stu set name = "xiaohei" where id= 1;
クライアント 1:
クライアント 2:
クライアント 1 でトランザクションを開始し、更新ステートメントを実行して、Lily という名前のデータ、つまり ID 19 のレコードを更新します。次に、クライアント 2 では、ID 3 のレコードが更新されますが、直接実行することはできず、ブロックされます。なぜでしょうか?
その理由は、この時点でクライアントが名前フィールドに基づいて更新するとき、名前フィールドにはインデックスがないためです。インデックスがない場合、この時点で行ロックがテーブル ロックにアップグレードされます (行ロックが存在しないため)。 lock はインデックス項目に対するロックであり、name にはインデックスがありません)。
次に、名前フィールドにインデックスを作成します。インデックスが確立された後、別のテストを実行します。
客户端1:
#给name字段创建索引
CREATE INDEX idx_stu ON stu(name);
begin;
#更新:添加的是行锁排它锁
update stu set name = "xiaohei" where name= "lily";
客户端2:
begin;
#操作不同的记录添加行锁排它锁是成功的
update stu set name = "xiaohei" where id= 1;
クライアント 1:
クライアント 2:
この時点で、クライアントがトランザクションを開始し、名前に基づいて更新していることがわかります。クライアント 2 が ID 3 のデータを更新したとき、更新は成功し、ブロッキング状態にはなりませんでした。これは、インデックス フィールドに基づいて更新操作を実行することにより、行ロックがテーブル ロックにアップグレードされるのを回避できることを示しています。
5.4.3 ギャップロック&キーロック
デフォルトでは、InnoDB は REPEATABLE READ トランザクション分離レベルで実行され、検索とインデックス スキャンにネクスト キー キー ロックを使用して、ファントム リードを防ぎます。
- インデックス上の同等のクエリ ( ) は、
并且这个索引是:唯一索引
存在しないレコードをロックするときのギャップ ロック用に最適化されています。- つまり、一意のインデックスに対して同等のクエリを実行するには、主キー インデックスが一意のインデックスになります。
- インデックス上の同等のクエリ (
并且这个索引是:非唯一普通索引,即二级索引)
右への移動時に最後の値がクエリ要件を満たさない場合、ネクスト キー ロックはギャップ ロックに縮退します。 - インデックスの範囲クエリ ()
并且这个索引是:唯一索引
----条件を満たさない最初の値までアクセスし、一時的なキー ロックが追加されます。
知らせ:
间隙锁唯一目的是防止其他事务插入间隙,造成幻读现象。间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁。
- ギャップ ロックや一時キー ロックを覚えておく必要はなく、特定の SQL ステートメントを分析して、このロックを追加する必要がある理由を確認するだけで済みます。
サンプルデモンストレーション
現在のテーブルのレコード:
A. インデックスに対する同等のクエリ (このインデックスが唯一のインデックス) では、存在しないレコードをロックする場合、ギャップ ロックに最適化されます。
客户端1:
begin;
#正常情况是行级排他锁
#id是主键即唯一索引、做等值查询、id为5的这条记录不存在,所以此时在2和8之间添加的是间隙锁
update stu set age= 10 where id= 5;
客户端2:
#RECORD:行级锁 x:排它锁 GAP:间隙锁 8:代表锁的是8之前的间隙,不包含3和8这2条记录,锁的只是3和8之间的间隙
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;
begin;
#插入id为7的记录,处于阻塞状态:因为间隙锁锁住了3和8之间的间隙,直到客户端1提交了事务释放了间隙锁,此时
# 插入操作的行级排他锁就可以执行成功了。
insert into stu values(7,"xiaogang",7);
クライアント 1:
クライアント 2:
B. インデックス上の同等のクエリ (一意でない通常のインデックス)。右へのトラバース時に最後の値がクエリ要件を満たさない場合、ネクスト キー ロックは在这里插入代码片
ギャップ ロックに縮退します。
導入して分析しましょう:
InnoDB の B+ ツリー インデックスには、順序付けされた二重リンク リストとしてリーフ ノードがあることがわかっています。このセカンダリ インデックスに基づいて値 18 のデータをクエリし、共有ロックを追加する場合、行 18 のみをロックできますか?
いいえ、18 より前の他のトランザクションはフィールド値 18 のレコードを挿入する可能性があり、18 より後の他のトランザクションはフィールド値 18 のレコードを挿入する可能性があります。一意ではないインデックスであるため、この構造には複数の 18 が存在する可能性があります。 . が存在するため、ロックすると、後から検索が続けられ、条件を満たさない値 (現在の場合は 29) が見つかります。このとき、18にはキーロックが追加され(18のレコードと18より前のギャップをロック)、29より前のギャップにはロックが追加されます(29より前のギャップをロック)。
客户端1:
#给stu表的age字段加上二级索引
CREATE INDEX idx_stu_age ON stu(age);
begin;
#加上行级共享锁:满足非唯一索引、等值查询---》共享锁会转化为间隙锁
select * from stu where age =3 LOCK IN SHARE MODE;
客户端2:
#3:对现有的这条记录加上行锁
#3,3:临建锁,把3这条记录以及3之前的间隙锁住
#7,7:把3和7之间的间隙锁住
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;
クライアント 1:
クライアント 2:
C. インデックスに対する範囲クエリ (一意のインデックス) - 条件を満たさない最初の値にアクセスするまで、一時的なキー ロックが追加されます。
客户端1:
begin;
#加上行级共享锁:满足唯一索引、范围查询---》共享锁会转化为临建锁
select * from stu where id>=19 LOCK IN SHARE MODE;
客户端2:
#19:对19记录加上行锁
#25:临键锁,锁的是25以及25之间的间隙
#supremum pseu:正无穷,在25到正无穷之间加了个临键锁
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;
クエリ条件は id>=19 で、共有ロックが追加されます。この時点で、データベース テーブル内の既存のデータに基づいて、データを 3 つの部分に分割できます。
-
[19]
-
(19,25]
-
(25,+∞]
したがって、データベース データがロックされると、行ロックが 19、隣接キー ロックが 25 (25 と 25 の間のギャップを含む)、および正の無限大 (正の無限大の前のギャップ) の隣接キー ロックが追加されます。
5.5 概要
6.InnoDBエンジン
6.1 論理ストレージ構造
InnoDB の論理ストレージ構造を次の図に示します。
1).テーブルスペース
テーブル スペースは、InnoDB ストレージ エンジンの論理構造の最上位レベルです。ユーザーがパラメータ innodb_file_per_table (バージョン 8.0 ではデフォルトで有効) を有効にすると、各テーブルにテーブル スペース (xxx.ibd) が割り当てられ、1 つの mysql インスタンスが作成されます。複数のテーブルに対応し、レコードやインデックスなどのデータを格納するために領域が使用されます。
2).セグメント
セグメントはデータ セグメント (リーフ ノード セグメント)、インデックス セグメント (非リーフ ノード セグメント)、ロールバック セグメント (ロールバック セグメント) に分かれています。InnoDB はインデックス構成テーブルです。データ セグメントは B+ ツリーのリーフ ノードであり、インデックス セグメントは B+ であり、ツリーの非葉ノードです。セグメントは複数のエクステント(領域)を管理するために使用されます。
3).地区
エリアは、表スペースの単位構造であり、各エリアのサイズは1Mです。デフォルトでは、InnoDB ストレージ エンジンのページ サイズは 16K です。つまり、1 つの領域に 64 の連続したページがあります。
4).ページ
ページは InnoDB ストレージ エンジンのディスク管理の最小単位であり、各ページのデフォルト サイズは 16KB です。ページの継続性を確保するために、InnoDB ストレージ エンジンは毎回ディスクから 4 ~ 5 つの領域を適用します。
5).OK
行、InnoDB ストレージ エンジンのデータは行ごとに保存されます。
デフォルトでは、連続して 2 つの非表示フィールドがあります。
- Trx_id: レコードが変更されるたびに、対応するトランザクション ID が trx_id 非表示列に割り当てられます。
- Roll_pointer: 特定のインデックス レコードが変更されるたびに、古いバージョンが UNDO ログに書き込まれます。したがって、この隠し列は、レコード以前の情報を見つけるためのポインターに相当します。
6.2 アーキテクチャ
6.2.1 概要
MySQL バージョン 5.5 以降、InnoDB ストレージ エンジンがデフォルトで使用され、トランザクション処理に優れ、クラッシュ回復機能があり、日常の開発で広く使用されています。以下は InnoDB のアーキテクチャ図で、左側がメモリ構造、右側がディスク構造です。
6.2.2 メモリ構造
左側のメモリ構造は主に、バッファ プール、変更バッファ、アダプティブ ハッシュ インデックス、およびログ バッファの 4 つの主要なブロックに分かれています。次にこの4つのパートを紹介します。
1).バッファプール
InnoDB ストレージ エンジンはディスク ファイル ストレージに基づいています。物理ハードディスクへのアクセスとメモリ内でのアクセスには速度に大きな違いがあります。両者の I/O 効率の差をできるだけ補うために、頻繁に使用するデータをバッファ プールにロードする必要があるため、アクセスごとにディスク I/O が回避されます。
InnoDB のバッファ プールには、インデックス ページとデータ ページがキャッシュされるだけでなく、アンドゥ ページ、挿入キャッシュ、アダプティブ ハッシュ インデックス、InnoDB ロック情報などが含まれます。
バッファプールとは、ディスク上で頻繁に操作される実データをキャッシュできるメインメモリ上の領域で、追加、削除、変更、クエリなどの操作を行う際には、まずバッファプール内のデータが操作されます(データがない場合)。バッファ プールでは、ディスクとキャッシュからロードされ、一定の頻度でディスクに更新されるため、ディスク IO が削減され、処理が高速化されます。
バッファー プールはページ ページに基づいており、基礎となるレイヤーはリンク リスト データ構造を使用してページを管理します。ステータスに応じて、ページは次の 3 つのタイプに分類されます。
- フリーページ:フリーページ、未使用。
- クリーンページ: ページは使用されており、データは変更されていません。
- ダーティ ページ: ダーティ ページは使用済みのページであり、データは変更されており、ページ内のデータはディスク上のデータと矛盾しています。
専用サーバーでは、mysql の実行効率を向上させるために、物理メモリの最大 80% をバッファ プールに割り当てるのが一般的です。
パラメータ設定: 'innodb_buffer_pool_size' のような変数を表示します。
2).バッファの変更
変更バッファ、変更バッファ (非一意のセカンダリ インデックス ページ用)、DML ステートメントの実行時に、これらのデータ ページがバッファ プールにない場合、ディスクは直接操作されませんが、データ変更は変更バッファに保存されます。変更 バッファーでは、今後データが読み取られるときに、データがマージされてバッファー プールに復元され、マージされたデータがディスクに更新されます。変更バッファの意味は何ですか?
まず図を見てみましょう。これは二次インデックスの構造図です。
クラスター化インデックスとは異なり、セカンダリ インデックスは通常、一意ではなく、比較的ランダムな順序でセカンダリ インデックスに挿入されます。同様に、削除や更新はインデックス ツリー内の隣接していないセカンダリ インデックス ページに影響を与える可能性があり、毎回ディスクを操作すると大量のディスク IO が発生します。ChangeBuffer を使用すると、バッファー プールでマージ処理を実行し、ディスク IO を削減できます。
3).適応型ハッシュインデックス
アダプティブ ハッシュ インデックスは、バッファ プール データのクエリを最適化するために使用されます。MySQL の innoDB エンジンはハッシュ インデックスを直接サポートしていませんが、アダプティブ ハッシュ インデックスと呼ばれる機能を提供します。前に述べたように、同等のマッチングを実行する場合、ハッシュ インデックスのパフォーマンスは一般に B+ ツリーのパフォーマンスよりも高くなります。これは、ハッシュ インデックスは通常 1 つの IO のみを必要とするのに対し、B+ ツリーは複数の一致を必要とする場合があるため、ハッシュ インデックスの効率は高いですが、ハッシュ インデックスは範囲クエリやあいまい一致などには適していません。
InnoDB ストレージ エンジンは、テーブル上の各インデックス ページのクエリを監視し、特定の条件下でハッシュ インデックスによって速度が向上することが確認された場合は、適応ハッシュ インデックスと呼ばれるハッシュ インデックスを確立します。
アダプティブ ハッシュ インデックスは手動介入を必要とせず、状況に応じてシステムが自動的に完了します。
パラメータ:adaptive_hash_index、デフォルトはオンです
4).ログバッファ
ログ バッファ: ログ バッファは、ディスクに書き込まれるログ データ (REDO ログ、UNDO ログ) を保存するために使用されます。デフォルトのサイズは 16MB です。ログ バッファ内のログは定期的にディスクに更新されます。トランザクションで多くの行の更新、挿入、または削除が必要な場合、ログ バッファ サイズを増やすとディスク I/O を節約できます。
パラメータ:
innodb_log_buffer_size: バッファ サイズ (デフォルト 16777216)
innodb_flush_log_at_trx_commit: ログをディスクにフラッシュするタイミング。値には主に次の 3 つが含まれます: (デフォルトは 1)
- 1: ログは、トランザクションのコミットごとにディスクに書き込まれ、フラッシュされます (デフォルト値)。
- 0: 1 秒に 1 回、ログをディスクに書き込み、フラッシュします。
- 2: ログは各トランザクションのコミット後に書き込まれ、1 秒に 1 回ディスクにフラッシュされます。
6.2.3 ディスク構造
次に、InnoDB アーキテクチャの右側の部分、つまりディスク構造を見てみましょう。
1).システムテーブルスペース
システム テーブルスペースは、変更バッファの記憶領域です。テーブルがテーブルごとのファイルや一般的なテーブルスペースではなくシステムテーブルスペースに作成された場合は、テーブルとインデックスのデータが含まれる場合もあります。(MySQL5.x バージョンには InnoDB データディクショナリ、アンドゥログなども含まれています)
パラメータ: innodb_data_file_path
システム テーブル スペース。デフォルトのファイル名は ibdata1 です。
2).File-Per-Table テーブルスペース
innodb_file_per_table スイッチがオンになっている場合、各テーブルのファイル テーブル スペースには単一の InnoDB テーブルのデータとインデックスが含まれ、ファイル システム上の単一のデータ ファイルに保存されます。
スイッチパラメータ: innodb_file_per_table、このパラメータはデフォルトで有効になっています。
つまり、テーブルを作成するたびに、図に示すようにテーブルスペースファイルが生成されます。
3).一般的なテーブルスペース
一般的なテーブルスペースは、CREATE TABLESPACE 構文を使用して作成する必要があり、テーブルの作成時に指定できます。(作成しない場合、デフォルトでは何もありません)
A.テーブルスペースを作成する
#指定表空间的名字 指定表空间关联的表空间文件 指定存储引擎
CREATE TABLESPACE ts_name ADD DATAFILE 'file_name' ENGINE = engine_name;
B. テーブルの作成時にテーブルスペースを指定する
# 需要先选择数据库,才能执行这条语句
CREATE TABLE xxx ... TABLESPACE ts_name;
4).元に戻すテーブルスペース
Undo テーブル スペース: MySQL インスタンスが初期化されると、UNDO ログを保存するために 2 つのデフォルトの UNDO テーブル スペース (初期サイズ 16M) が自動的に作成されます。
5).一時テーブルスペース
InnoDB は、セッション一時テーブルスペースとグローバル一時テーブルスペースを使用します。ユーザーが作成した一時テーブルなどのデータを保存します。
6).バッファファイルの二重書き込み
二重書き込みバッファ: innoDB エンジンは、データ ページをバッファ プールからディスクに更新する前に、システム異常時のデータ回復を容易にするために、まずデータ ページを二重書き込みバッファ ファイルに書き込みます。
7).やり直しログ
REDO ログは、トランザクションの耐久性を実現するために使用されます。ログ ファイルは、REDO ログ バッファと REDO ログ ファイルの 2 つの部分で構成され、前者はメモリ内に、後者はディスク上にあります。トランザクションがコミットされると、すべての変更情報がログに保存され、ダーティ ページをディスクにフラッシュするときにエラーが発生した場合のデータ回復に使用できます。
REDO ログ ファイルはラウンドロビン方式で書き込まれ、次の 2 つのファイルが含まれます。
先ほど、InnoDB のメモリ構造とディスク構造を紹介しましたが、メモリ内で更新したデータはどのようにしてディスクに更新されるのでしょうか? この時点で、一連のバックグラウンド スレッドが関与しています. 次に、InnoDB に関与するいくつかのバックグラウンド スレッドを紹介します。
6.2.4 バックグラウンドスレッド
InnoDB のバックグラウンド スレッドは、マスター スレッド、IO スレッド、パージ スレッド、ページ クリーナー スレッドの 4 つのカテゴリに分類されます。
1).マスタースレッド
コア バックグラウンド スレッドは、他のスレッドのスケジュールを担当し、また、ダーティ ページのリフレッシュ、キャッシュのマージと挿入、アンドゥ ページのリサイクルなど、データの一貫性を維持するためにバッファ プール内のデータをディスクに非同期的にリフレッシュする役割も担います。
2).IOスレッド
AIO (非同期ノンブロッキング) は、IO リクエストを処理するために InnoDB ストレージ エンジンで広く使用されており、データベースのパフォーマンスを大幅に向上させることができます。IO スレッドは主にこれらの IO リクエストのコールバックを担当します。
ねじの種類 | デフォルトの番号 | 責任 |
---|---|---|
スレッドを読む | 4 | 読み取り操作を担当します |
書き込みスレッド | 4 | 書き込み操作を担当します |
ログスレッド | 1 | ログバッファをディスクにフラッシュする役割を果たします。 |
バッファスレッドを挿入 | 1 | 書き込みバッファの内容をディスクにフラッシュする役割を果たします。 |
次のコマンドを使用して、IO スレッド情報を含む InnoDB のステータス情報を表示できます。
#登录mysql后执行
show engine innodb status;
3).スレッドのパージ
主にトランザクションで送信されたアンドゥログを再利用するために使用されますが、トランザクションコミット後はアンドゥログが使用できなくなる可能性があるため、再利用するために使用してください。
4).ページクリーナースレッド
マスター スレッドによるダーティ ページのディスクへのフラッシュを支援するスレッド。マスター スレッドの作業負荷を軽減し、ブロッキングを軽減します。
6.3 取引の原則(ポイント)
6.3.1 トランザクションの基本
1).事務
トランザクションは一連の操作であり、分割できない作業単位です。トランザクションは、システム全体に対して操作リクエストを送信または取り消します。つまり、これらの操作は同時に成功するか、同時に失敗します。
2).特徴
- アトミック性: トランザクションは、すべてが成功するかすべてが失敗する、分割できない最小の操作単位です。
- 一貫性: トランザクションが完了すると、すべてのデータが一貫した状態になる必要があります (一貫性は制約の前後でも保証される必要があります)。
- 分離: データベース システムによって提供される分離メカニズムにより、トランザクションは外部の同時操作の影響を受けない独立した環境で実行されます。
- 耐久性: トランザクションがコミットまたはロールバックされると、データベース内のデータに対する変更は永続的になります。
- トランザクションがコミットされている限り、データはディスクに保存される必要があります。
実際、トランザクションの原理を研究するとき、MySQL の InnoDB エンジンがトランザクションのこれら 4 つの特性をどのように保証するかを研究します。
この4つの大きな特徴ですが、実は大きく2つに分かれています。実際、原子性、一貫性、永続性は、InnoDB 内の 2 つのログ (REDO ログと UNDO ログ) によって保証されています。分離は、データベース ロックと MVCC マルチバージョン同時実行制御によって保証されます。
トランザクションの原理を説明するときは、主に redolog、undolog、MVCC について学習します。
ロックは学習されました。
6.3.2 やり直しログ やり直しログ
REDO ログは、トランザクションがコミットされたときのデータ ページの物理的な変更を記録し、トランザクションの耐久性を実現するために使用されます。
ログ ファイルは、REDO ログ バッファと REDO ログ ファイルの 2 つの部分で構成され、前者はメモリ内に、後者はディスク上にあります。トランザクションがコミットされた後、すべての変更情報はログ ファイルに保存され、ダーティ ページがディスクにフラッシュされてエラーが発生した場合のデータ回復に使用できるため、耐久性が確保されます。
redolog がない場合、どのような問題が発生する可能性がありますか? 一緒に分析してみましょう。
InnoDB エンジンのメモリ構造では、メイン メモリ領域はバッファ プールであり、多くのデータ ページがバッファ プールにキャッシュされていることがわかっています。トランザクションで複数の追加、削除、変更操作を実行すると、InnoDB エンジンはまずバッファ プール内のデータを操作します。バッファ内に対応するデータがない場合は、バックグラウンド スレッドを通じてディスクからデータをロードし、バッファ領域にデータを格納し、バッファ プール内のデータを変更します。変更されたデータ ページはダーティ ページと呼ばれます。ダーティ ページは、バッファとディスク内のデータの一貫性を確保するために、特定の機会にバックグラウンド スレッドを通じてディスクにフラッシュされます。バッファ内のダーティ ページ データはリアルタイムではリフレッシュされませんが、バッファ内のデータは一定期間後にディスクにリフレッシュされます。ディスクへのリフレッシュのプロセスでエラーが発生した場合は、ユーザーに次のメッセージが表示されます。トランザクションは正常に送信されましたが、データが永続化されない場合、トランザクションの耐久性が保証されないため、問題が発生します。
では、上記の問題をどのように解決すればよいでしょうか? InnoDB は REDO ログを提供します。次に、REDOLOG を使用してこの問題を解決する方法を分析してみましょう。
redolog では、バッファ内のデータが追加、削除、または変更されると、操作されたデータ ページの変更がまず REDO ログ バッファに記録されます。トランザクションがコミットされると、REDO ログ バッファ内のデータが REDO ログ ディスク ファイルにフラッシュされます。一定の時間が経過した後、バッファのダーティ ページをディスクにフラッシュするときにエラーが発生した場合は、REDO ログを使用してデータを回復できるため、トランザクションの耐久性が確保されます。ダーティ ページがディスクに正常にフラッシュされた場合、または関連するデータがディスクに書き込まれた場合、現時点では REDO ログは影響を及ぼさず、削除できるため、既存の 2 つの REDO ログ ファイルがループで書き込まれます。
では、トランザクションがコミットされるたびに、バッファ プール内のダーティ ページを直接ディスクにフラッシュするのではなく、REDO ログをディスクにフラッシュする必要があるのはなぜでしょうか。
ビジネスの運用では、通常、ディスク データを順番にではなくランダムに読み書きするためです。REDO ログはディスク ファイルにデータを書き込みますが、ログ ファイルなのでシーケンシャルに書き込まれます。シーケンシャル書き込みの効率は、ランダム書き込みの効率よりもはるかに優れています。この最初にログを書き込む方法は、WAL (Write-Ahead Logging) と呼ばれます。
6.3.3 アンドゥログ ロールバックログ
ロールバック ログは、データが変更される前の情報を記録するために使用され、ロールバック (トランザクションの原子性の保証)と MVCC (複数バージョンの同時実行制御) の 2 つの機能があります。
アンドゥログは、物理ログ(主にデータページの内容を記録)を記録するリドゥログとは異なり、論理ログ(主に各ステップでどのような操作が行われたかを記録)です。レコードが削除されると、対応する挿入レコードがアンドゥ ログに記録され、逆に、レコードが更新されると、対応する更新レコードが記録されると考えることができます (このデータ行は、アップデートが実行されます)。ロールバックを実行すると、変更前の状態からアンドゥログの論理レコードを読み出し、変更前の状態にロールバックするため、トランザクションのアトミック性が確保されます。
アンドゥ ログの破棄: アンドゥ ログはトランザクションの実行時に生成されますが、トランザクションがコミットされても、アンドゥ ログは MVCC にも使用される可能性があるため、すぐには削除されません。
UNDOログの保存:UNDOログはセグメント単位で管理・記録されており、先ほど紹介したロールバックセグメントに保存されており、内部には1024個のUNDOログセグメントが含まれています。
6.4 MVCCのマルチバージョン同時実行制御(ポイント)
6.4.1 基本概念
1) 現在の測定値
読み取られるのは最新バージョンのレコードです。読み取り時には、他の同時トランザクションが現在のレコードを変更できないようにする必要があり、読み取られたレコードはロックされます。日常的な操作では、共有モードでの select ... ロック (行レベルの共有ロック)、更新のための select ...、更新、挿入、削除 (行レベルの排他ロック) はすべて現在の読み取りです。
テスト:
客户端1:
begin;
select * from stu;
#没有任何锁
#客户端2执行更新语句并且提交事务后,客户端1也不能查询到最新的数据(不能读取客户端2更新的数据)
#因为当前默认的隔离级别是可重复读读:在这个事物持续期间可以重复多次读取此字段,不允许其它事务更新此字段。
#当前select 语句不是当前读
select * from stu;
#加上行级共享锁,此时就可以读取到最新的数据(可以读取到客户端2更新的数据)
#因为客户端2提交了事务所以不存在共享锁和排他锁阻塞现象
#这就是当前读
select * from stu lock in share mode;
客户端2:
begin;
# 添加行级排他锁
update stu set name = 'Jsp' where id = 1;
commit;
テストでは、共有モードの共有ロックのロックがクエリ ステートメントの後に追加されるため、デフォルトの RR 分離レベルでも、トランザクション A はトランザクション B の最新の送信コンテンツを読み取ることができることがわかります。読み取り操作。もちろん、排他ロックを追加すると、それが現在の読み取り操作にもなります。
2) スナップショット読み取り
単純な選択 (ロックなし) は、 スナップショット読み取り です。スナップショット読み取りは、記録されたデータの表示可能なバージョン (履歴データである可能性があります) を読み取ります。ロックなしの場合は、ノンブロッキング読み取りです。
- Read Committed は、コミットされたデータを読み取ります。選択するたびに、スナップショット読み取りが生成されます。
- 反復読み取り (デフォルト): トランザクション開始後の最初の選択ステートメントで、スナップショットが読み取られます。続いて実行される select ステートメントは、実際には以前に生成されたスナップショット データを直接チェックします。
- シリアル化可能なシリアル化: スナップショット読み取りは現在の読み取りに縮退し、各読み取り操作はロックされます。
テスト:
客户端1:
begin;
select * from stu;
#没有任何锁
#客户端2执行更新语句并且提交事务后,客户端1也不能查询到最新的数据(不能读取客户端2更新的数据)
#因为当前默认的隔离级别是可重复读读:在这个事物持续期间可以重复多次读取此字段,不允许其它事务更新此字段。
#当前select 语句不是当前读,是快照读:即使客户端2提交了事务,客户端1也读取不到最新的数据,读取的是历史版本
select * from stu;
客户端2:
begin;
# 添加行级排他锁
update stu set name = 'Jsp' where id = 1;
commit;
テストでは、トランザクション B がデータを送信したとしても、トランザクション A ではそのデータをクエリできないことがわかりました。その理由は、通常の選択はスナップショット読み取りであり、現在のデフォルトの RR 分離レベルでは、トランザクション開始後の最初の選択ステートメントでスナップショットが読み取られるためです。後で実行される同じ選択ステートメントはスナップショットからデータを取得するため、最新のデータではないため、繰り返し読み込むことができます。
3)MVCC
正式名称は、Multi-Version Concurrency Control、マルチバージョン同時実行制御です。読み取りおよび書き込み操作で競合がないように、データの複数のバージョンを維持することを指します。スナップショット読み取りは、MySQL が MVCC を実装するためのノンブロッキング読み取り機能を提供します。MVCC の特定の実装もデータベース レコードに依存する必要があります三个隐式字段、undo log日志、readView
。
次に、MVCC の原理を紹介するために、InnoDB エンジンのテーブルに含まれる隠しフィールド、undolog および readview を紹介します。
6.4.2 隠しフィールド
6.4.2.1 はじめに
上記のテーブルを作成すると、テーブル構造を見ると、これら 3 つのフィールドが明示的に表示されます。実際、これら 3 つのフィールドに加えて、InnoDB は 3 つの隠しフィールドを自動的に追加します。その意味は次のとおりです。
隠しフィールド | 意味 |
---|---|
DB_TRX_ID | 最近変更されたトランザクション ID は、このレコードに挿入されたレコード、またはレコードが最後に変更されたときのトランザクション ID です。 |
DB_ROLL_PTR | ロールバック ポインタは、このレコードの前のバージョンを指し、元のバージョンを指すために元に戻すログとともに使用されます。 |
DB_ROW_ID | 非表示の主キー: テーブル構造で主キーが指定されていない場合、この非表示フィールドが生成されます。 |
説明する:
- DB_TRX_ID: この行の最後に変更されたレコードのトランザクション ID。レコードを挿入するか、最後に変更すると、ストレージ エンジンは自動的に値を DB_TRX_ID に割り当てます。
- DB_ROW_ID: 非表示の主キー。このフィールドはテーブルごとに生成されるわけではありません。テーブルに主キーがない場合、この非表示フィールドは非表示の主キーとして自動的に生成されます。テーブルに主キーがある場合、この非表示フィールドは表示されません。
上記の最初の 2 つのフィールドは必ず追加されます。最後のフィールド DB_ROW_ID を追加するかどうかは、現在のテーブルに主キーがあるかどうかによって決まります。主キーがある場合、隠しフィールドは追加されません。
6.4.2.2 テスト
1).主キーを持つテーブル stu を表示します。
サーバーに /var/lib/mysql/itcast/ と入力し、stu のテーブル構造情報を表示し、次のコマンドを渡します。
#mysql的数据存储在此目录下
cd /var/lib/mysql/
#查看的是itcast数据库下的表,所以就切换到itcast,里面是一个个的xxx.ibd独立表空间文件
cd /itcast/
#ibd文件是二进制文件不能直接打开,借助此命令进行打开
#stu.ibd:想要打开的ibd文件名
ibd2sdi stu.ibd
表示されたテーブル構造情報には、列の列があります。そこには、テーブルの作成時に指定したフィールドに加えて、DB_TRX_ID と DB_ROLL_PTR という 2 つの追加フィールドがあることがわかります。テーブルには主キーがあるためです。 、DB_ROW_ID 隠しフィールドはありません。
2).主キーのないビューテーブルemployee
テーブル作成ステートメント:
#这个表是在itcast数据库下创建的,登录mysql后执行
create table employee (id int , name varchar(10));
この時点で、次のコマンドを使用してテーブル構造とそのフィールド情報を表示できます。
#mysql的数据存储在此目录下
cd /var/lib/mysql/
#查看的是itcast数据库下的表,所以就切换到itcast,里面是一个个的xxx.ibd独立表空间文件
cd /itcast/
#ibd文件是二进制文件不能直接打开,借助此命令进行打开
#employee.ibd:想要打开的ibd文件名
ibd2sdi employee.ibd
表示されたテーブル構造情報には列の列があり、テーブルの作成時に指定したフィールドに加えて、DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID という 3 つの追加フィールドがあることがわかります。従業員テーブルは主キー。
6.4.3 アンドゥログ ロールバックログ
6.4.3.1 はじめに
ロールバック ログ。データのロールバックを容易にするために挿入、更新、削除中に生成されるログ。
挿入時に生成される元に戻すログは、ロールバック中にのみ必要となり、トランザクションがコミットされた直後に削除できます。
更新および削除の場合、生成される Undo ログはロールバック時だけでなく、スナップショットの読み取り時にも必要となるため、すぐには削除されません。
6.4.3.2 バージョンチェーン
元のデータを含むテーブルがあります。
- DB_TRX_ID: 最近変更されたトランザクション ID を表します。このレコードを挿入したトランザクション ID、またはこのレコードを最後に変更したトランザクション ID は自動的にインクリメントされます。
- DB_ROLL_PTR: このデータは挿入されたばかりで更新されていないため、このフィールドの値は null です。
次に、このテーブルに同時にアクセスする 4 つの同時トランザクションがあります。
A.最初のステップ
トランザクション 2 が最初の変更ステートメントを実行すると、データ変更前の外観を記録するために Undo ログが記録され、その後レコードが更新され、この操作のトランザクション ID とロールバック ポインタが記録されます。ロールバック ポインタは、指定するために使用されます。ロールバックが発生した場合は、ロールバックするバージョンを指定します。
B. 第 2 ステップ
トランザクション 3 が最初の変更ステートメントを実行すると、データ変更前の外観を記録するために Undo ログも記録されます。その後、レコードが更新され、この操作のトランザクション ID とロールバック ポインタが記録されます。ロールバック ポインタは次の目的で使用されます。ロールバックした場合に何が起こるか、どのバージョンにロールバックするかを指定します。
C.第3ステップ
トランザクション 4 が最初の変更ステートメントを実行すると、データ変更前の外観を記録するために Undo ログも記録されます。その後、レコードが更新され、この操作のトランザクション ID とロールバック ポインタが記録されます。ロールバック ポインタは次の目的で使用されます。ロールバックした場合に何が起こるか、どのバージョンにロールバックするかを指定します。
- 最後に、異なるトランザクションまたは同じトランザクションによって同じレコードが変更されると、レコードのアンドゥログによってレコード バージョンのリンク リストが生成されることがわかりました。リンク リストの先頭は最新の古いレコードであり、リンクされたリストの末尾はlist は最も古い古いレコードです。
- アンドゥログ バージョン チェーンに記録されるのは、現在のバージョン チェーンがすべての履歴記録バージョンを記録するということです。
- では、クエリを実行するとどのバージョンが返されるのでしょうか? ? ? ? ?
- これは実際には、undolog バージョン チェーンによって制御されるのではなく、mvcc の 3 番目のコンポーネントである readview によって制御されます。
6.4.4 リードビュー
ReadView は、SQL の実行時に MVCC がデータを抽出するための基盤であり、システムの現在アクティブな (コミットされていない)トランザクション ID を記録して維持します。快照读
ReadView には 4 つのコア フィールドが含まれています。
分野 | 意味 |
---|---|
m_ids | 現在アクティブなトランザクション ID のコレクション |
min_trx_id | 最小アクティブトランザクションID |
max_trx_id | 事前に割り当てられたトランザクション ID、現在の最大トランザクション ID + 1 (トランザクション ID は自動インクリメントされるため、次に割り当てられるトランザクション ID は何になります) |
クリエーター_trx_id | ReadView作成者のトランザクションID |
バージョン チェーン データのアクセス ルールは、readview で規定されています。
trx_id は、現在のアンドゥログ バージョン チェーンに対応するトランザクション ID (現在のトランザクションの ID) を表します。
過去のバージョンデータを取得する場合、どのバージョンを取得するかは、現在のトランザクションのIDと上記のReadViewの4つの属性を比較することで取得されます。
状態 | アクセス可能ですか? | 説明する |
---|---|---|
trx_id == 作成者_trx_id | このバージョンにアクセスできます | 確立され、現在のトランザクションによってデータが変更されたことを示します。そうすれば、更新したばかりのレコードを確実に読むことができます。 |
trx_id < min_trx_id | このバージョンにアクセスできます | 確立され、データが送信されたことを示します。 |
trx_id > max_trx_id | このバージョンにはアクセスできません | 確立され、ReadView が生成された後にトランザクションが開始されたことを示します。 |
min_trx_id <= trx_id<= max_trx_id | 如果trx_id不在m_ids中, 是可以访问该版本的 | 成立,说明数据已经提交。 |
不同的隔离级别,生成ReadView的时机不同:
- READ COMMITTED (读已提交):在事务中每一次执行快照读时生成ReadView。
- REPEATABLE READ(可重复读):仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。
6.4.5 原理分析
6.4.5.1 RC隔离级别(读已提交)
RC隔离级别下,在事务中每一次执行快照读时生成ReadView。
我们就来分析事务5中,两次快照读读取数据,是如何获取数据的?
在事务5中,查询了两次id为30的记录,由于隔离级别为Read Committed,所以每一次进行快照读都会生成一个ReadView,那么两次生成的ReadView如下。
解释:
- 这个图代表的是多个事务并发操作,从上往下看
- 第一个ReadView:
- m_ids:{3,4,5},执行当前快照读的时候当前活跃的事务ID集合。在执行第一个查询id为30的记录这条sql时,事务2不是活跃的id因为他已经提交了,事务3、事务4和事务5此时都还没有提交事务,所以是活跃的事务ID。
- min_trx_id:3,所以此时最小的活动事务id就是3.
- max_trx_id:6,预分配的下一个事务id,就是当前最大活跃事务id+1,所以为6。
- creator_trx_id:5,执行这条更新sql,也就是快照读的时候,会生成ReadView,那么它的创建事务的id就是5.
- 第二个ReadView:同理
- m_ids:{4,5}
- min_trx_id:4
- max_trx_id:6
- creator_trx_id:5
那么这两次快照读在获取数据时,就需要根据所生成的ReadView以及ReadView的版本链访问规则, 到undolog版本链中匹配数据,最终决定此次快照读返回的数据。
A.先来看第一次快照读具体的读取过程:
在进行匹配时,会从undo log的版本链,从上到下进行挨个匹配:
-
先匹配这条记录,这条记录对应的trx_id为4,也就是将4带入右侧的匹配规则中。 ①不满足 ②不满足 ③不满足 ④也不满足 , 都不满足,则继续匹配undo log版本链的下一条。
-
再匹配第二条 ,这条记录对应的trx_id为3,也就是将3带入右侧的匹配规则中。①不满足 ②不满足 ③不满足 ④也不满足 ,都不满足,则继续匹配undo log版本链的下一条。
-
再匹配第三条 ,这条记录对应的trx_id为2,也就是将2带入右侧的匹配规则中。①不满足 ②满足 终止匹配,此次快照读,返回的数据就是版本链中记录的这条数据。
B.再来看第二次快照读具体的读取过程:
在进行匹配时,会从undo log的版本链,从上到下进行挨个匹配:
-
先匹配 这条记录,这条记录对应的trx_id为4,也就是将4带入右侧的匹配规则中。 ①不满足 ②不满足 ③不满足 ④也不满足 , 都不满足,则继续匹配undo log版本链的下一条。
-
再匹配第二条 ,这条记录对应的trx_id为3,也就是将3带入右侧的匹配规则中。①不满足 ②满足 。终止匹配,此次快照读,返回的数据就是版本链中记录的这条数据。
6.4.5.2 RR隔离级别(可重复读)
RR隔离级别下,仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。 而RR 是可重复读,在一个事务中,执行两次相同的select语句,查询到的结果是一样的
。
那MySQL是如何做到可重复读的呢? 我们简单分析一下就知道了
我们看到,在RR隔离级别下,只是在事务中第一次快照读时生成ReadView,后续都是复用该ReadView,那么既然ReadView都一样, ReadView的版本链匹配规则也一样, 那么最终快照读返回的结果也是一样的
。
所以呢,MVCC的实现原理就是通过 InnoDB表的隐藏字段、UndoLog 版本链、ReadView来实现的。而MVCC + 锁,则实现了事务的隔离性。 而一致性则是由redolog 与 undolog保证。
解释一致性则是由redolog 与 undolog共同保证:数据在执行之前和执行之后是一致的,也就是说这个事务执行失败我要全部回滚,保证数据前后一致。数据一旦提交一定要保证数据是更新过来了。
6.5 总结
7.MySQL管理
7.1 系统数据库
Mysql数据库安装完成后,自带了以下四个数据库,具体作用如下:
数据库 | 含义 |
---|---|
mysql | 存储MySQL服务器正常运行所需要的各种信息 (时区、主从、用户、权限等) |
information_schema | 提供了访问数据库元数据的各种表和视图,包含数据库、表、字段类型及访问权限等 |
performance_schema | 为MySQL服务器运行时状态提供了一个底层监控功能,主要用于收集数据库服务器性能参数 |
sys | 包含了一系列方便 DBA 和开发人员利用 performance_schema性能数据库进行性能调优和诊断的视图 |
7.2 常用工具
7.2.1 mysql
该mysql不是指mysql服务,而是指mysql的客户端工具。
作用:登录mysql数据库系统
语法 :
#mysql 选项 数据库名
mysql [options] [database]
选项 :
-u, --user=name #指定用户名
-p, --password[=name] #指定密码
-h, --host=name #指定服务器IP或域名
-P, --port=port #指定连接端口 (注意P是大写)
-e, --execute=name #执行SQL语句并退出
-e
选项可以在Mysql客户端执行SQL语句,而不用登录进MySQL数据库再执行,对于一些批处理脚本, 这种方式尤其方便。
示例:
#连接的本机并且端口号是3306,那么-h -p可以省略。
#需要指定连接的数据库,表明是那个数据库执行这个sql
mysql -uroot -p1234 db01 -e "select * from stu";
7.2.2 mysqladmin
mysqladmin 是一个执行管理操作的客户端程序。可以用它来检查服务器的配置和当前状态、创建并删除数据库等。
通过帮助文档查看后面可以跟什么选项,每个选项的作用是什么:
mysqladmin --help
语法:
#options:可以跟上选项
#command:可以写指令,比如创建数据库、删除数据库、刷新权限等等
mysqladmin [options] command ...
选项:
-u, --user=name #指定用户名
-p, --password[=name] #指定密码
-h, --host=name #指定服务器IP或域名
-P, --port=port #指定连接端口
示例:
#查看当前数据库的版本(因为要管理数据库所以要先连接数据库)
mysqladmin -uroot -p1234 version;
#创建数据库
mysqladmin -uroot -p1234 create db02;
#删除数据库
mysqladmin -uroot -p1234 drop db02;
7.2.3 mysqlbinlog
由于服务器生成的二进制日志文件以二进制格式保存,如果想要检查这些文本的文本格式就很不方便,因为他不是具体的文本文件,此时就可以使用到mysqlbinlog 日志管理工具查看这个二进制日志文件。
这个指令和二进制日志文件有关,二进制日志文件在mysql运维篇中详细讲解。
语法 :
# 选项 日志文件名1 日志文件名2
mysqlbinlog [options] log-files1 log-files2 ...
选项 :
-d, --database=name 指定数据库名称,只列出指定的数据库相关操作。
-o, --offset=# 忽略掉日志中的前n行命令。
-r,--result-file=name 将输出的文本格式日志输出到指定文件。
-s, --short-form 显示简单格式, 省略掉一些信息。
--start-datatime=date1 --stop-datetime=date2 指定日期间隔内的所有日志。
--start-position=pos1 --stop-position=pos2 指定位置间隔内的所有日志。
示例:
A. 查看 binlog.000008这个二进制文件中的数据信息
#找到二进制日志存放的位置
cd /var/lib/mysql
#如果是文本文件直接可以使用cat指令查看,但现在是二进制文件所以会显示乱码
cat binlog.000001
#解决:使用mysqlbinlog指令查看
mysqlbinlog binlog.000001
上述查看到的二进制日志文件数据信息量太多了,不方便查询。 我们可以加上一个参数 -s 来显示简单格式。
mysqlbinlog -s binlog.000001
7.2.4 mysqlshow
mysqlshow 客户端对象查找工具,用来很快地查找存在哪些数据库、数据库中的表、表中的列或者索引。
语法 :
# 选项 哪一个数据库 哪一张表 哪一个字段
mysqlshow [options] [db_name [table_name [col_name]]]
选项 :
--count #显示数据库及表的统计信息(数据库,表 均可以不指定)
-i #显示指定数据库或者指定表的状态信息
示例:
#查询test库中每个表中的字段数,及行数(同样需要先连接上mysql才能进行操作)
mysqlshow -uroot -p2143 --count test
#查询test库中book表的详细情况
mysqlshow -uroot -p2143 --count test book
示例:
A.查询每个数据库的表的数量及表中记录的数量
#没有写数据库名,统计的是所有数据库
mysqlshow -uroot -p1234 --count
B.查看数据库db01的统计信息
#统计指定数据库的信息
mysqlshow -uroot -p1234 --count db01
C.查看数据库db01中的course表的信息
#统计指定数据库下的具体表的信息
mysqlshow -uroot -p1234 --count db01 course
D.查看数据库db01中的course表的id字段的信息
#统计指定数据库下的具体表下的具体字段的信息
mysqlshow -uroot -p1234 --count db01 course id
7.2.5 mysqldump
mysqldump 客户端工具用来备份数据库或在不同数据库之间进行数据迁移。备份内容包含创建表,及插入表的SQL语句。
语法 :
#options选项:分为连接选项和输出输出选项
# 备份指定的数据库下的指定表
mysqldump [options] db_name [tables]
# 通过--database或者-B指定备份哪几个数据库
mysqldump [options] --database/-B db1 [db2 db3...]
# 备份所有的数据库使用--all-databases或者-A
mysqldump [options] --all-databases/-A
连接选项 :
-u, --user=name 指定用户名
-p, --password[=name] 指定密码
-h, --host=name 指定服务器ip或域名
-P, --port=# 指定连接端口
输出选项:
--add-drop-database 在每个数据库创建语句前加上drop database语句
--add-drop-table 在每个表创建语句前加上drop table语句,默认开启;不开启(--skip-add-drop-table)
-n, --no-create-db 不包含数据库的创建语句
-t, --no-create-info 不包含数据表的创建语句
-d --no-data 不包含数据
-T, --tab=name 自动生成两个文件:一个.sql文件,创建表结构的语句;一个.txt文件,数据文件
示例:
A.备份db01数据库
#备份db01数据库,并且把备份出的数据放到db01.sql文件中
#执行完毕后就会在当前目录下出现db01.sql文件
mysqldump -uroot -p1234 db01 > db01.sql
#查看目录结构:
ll
可以直接打开db01.sql,来查看备份出来的数据到底什么样。
#查看此文件内容
cat db01.sql
备份出来的数据包含:
- 删除表的语句
- 创建表的语句
- 数据插入语句
如果我们在数据备份时,不需要创建表,或者不需要备份数据,只需要备份表结构,都可以通过对应的参数来实现。
B.备份db01数据库中的表数据,不备份表结构(-t)
#不包含建表语句
mysqldump -uroot -p1234 -t db01 > db02.sql
ll
打开 db02.sql ,来查看备份的数据,只有insert语句,没有备份表结构。
cat db02.sql
C.将db01数据库的表的表结构与数据分开备份(-T)
#自动生成两个文件:一个.sql文件,创建表结构的语句;一个.txt文件,数据文件
#/root:表示把这2个文件存在root目录下
#db01 stu:备份的是哪一个数据库下的哪一张表
# 发现报错:
mysqldump -uroot -p1234 -T /root db01 stu
cd /root
#发现只生成了一个.sql文件
ll
执行上述指令,会出错,数据不能完成备份(只生成了一个.sql文件),原因是因为我们所指定的数据存放目录/root,MySQL认 为是不安全的,需要存储在MySQL信任的目录下。那么,哪个目录才是MySQL信任的目录呢,可以查看 一下系统变量 secure_file_priv 。执行结果如下:
mysql -uroot -p1234
#登录进mysql才能执行这个命令
#结果为:/var/lib/mysql-files/
show variables like '%secure_file_priv%';
#往mysql信任的目录存放文件
#打开另一个会话窗口,这是没有登录mysql时执行的命令
mysqldump -uroot -p1234 -T /var/lib/mysql-files/ db01 stu
cd /var/lib/mysql-files/
#发现此时就有了2个文件
ll
上述的两个文件 score.sql 中记录的就是表结构文件,而 score.txt 就是表数据文件,但是需要注意表数据文件,并不是记录一条条的insert语句,而是按照一定的格式记录表结构中的数据。如 下:
cat stu.sql
cat stu.txt
7.2.6 mysqlimport / ソース
1)mysqlimport
mysqlimport はクライアント データ インポート ツールで、-T パラメーターを使用して mysqldump によってエクスポートされたテキスト ファイルをインポートするために使用されます。
つまり、 7.2.5 で使用されているようにmysqldump -uroot -p1234 -T /var/lib/mysql-files/ db01 stu
、db01 データベース テーブルのテーブル構造とデータは 2 つのファイル、stu.sql と stu.txt に個別にバックアップ (-T) されます。この時点で、次のコマンドを使用して、txt ファイルをデータベース テーブル構造にインポートし直します。
语法 :
# 选项 数据库的名字 导回的txt文件
mysqlimport [options] db_name textfile1 [textfile2...]
示例 :
mysqlimport -uroot -p2143 test /tmp/city.txt
テスト:
まずstuテーブルのデータを削除します
#清空表,表示清空表中的所有数据,但是表结构保留。
TRUNCATE TABLE stu;
SELECT * FROM stu;
ll
pwd
#会报错:
#把txt文件中的数据导入到表结构当中,把数据恢复出来
#直接写txt文件仍然会报错:原因是直接写stu.txt文件表示当前目录,需要使用mysql信任的目录进行导入
# 即便我们已经进入到这个/var/lib/mysql-files mysql所信任的目录下但是他不识别,必须在执行命令的时候
# 加上此mysql所信任的目录
mysqlimport -uroot -p1234 db01 stu.txt
#解决:加上此mysql所信任的目录
mysqlimport -uroot -p1234 db01 /var/lib/mysql-files/stu.txt
stu テーブルを再度クエリすると、データが得られます。
2)出典
SQL ファイルをインポートする必要がある場合は、mysql でsource ディレクティブを使用できます。
语法 :
#需要先登录mysql后才能执行此命令
#导入什么目录下的sql文件
source /root/xxxxx.sql
テスト:
まず、db01 データベースの下にあるすべてのテーブルを削除します。
以前に生成された db01.sql ファイル
次に、コマンドを使用してSQLファイルをインポートします。
mysql -uroot -p1234
use db01;
#之前学习7.2.5把db01数据库备份到了/var/lib/mysql/目录下,生成了db01.sql文件
source /var/lib/mysql/db01.sql
データベースを更新すると、データが復元されたことがわかります。