MySQL 過去を振り返り、新しいことを学ぶ -- Innodb ストレージ エンジンのロック

黄舟
リリース: 2017-02-16 11:57:56
オリジナル
1351 人が閲覧しました

最近、ロックの問題にたくさん遭遇したので、それらを解決した後、ロックに関する本を注意深く読みました。それらは次のように構成されています:

1
、ロックの種類

Innodb ストレージ エンジンは、次の 2 の標準行レベル ロックを実装しています:

? 共有ロック (S ロック) により、トランザクションは 1 行のデータを読み取ることができます。

? 排他的ロック(X ロック)。トランザクションがデータ行を削除または更新できるようにします。

トランザクションが行 r の共有ロックを取得すると、読み取りによって行 が変更されないため、別のトランザクションもすぐに行 r の共有ロックを取得できます。 この場合、rのデータはロック対応です。ただし、トランザクションが行 r の排他ロックを取得したい場合は、トランザクションが行 r を解放するまで待つ必要があります。この場合、ロックは互換性がありません。次の表に示すように、この 2 つは互換性がありません:

排他ロックと共有ロックの互換性

競合

競合

S 共有ロック

競合

互換性があります

2、ロック拡張

Innodb ストレージ エンジンは、行レベルでのロックとテーブル レベルでのロックを同時に許可する多粒度ロックをサポートしています。時間が存在する。さまざまな粒度でのロック操作をサポートするために、InnoDB ストレージ エンジンは、インテンション ロックという追加のロック方法をサポートしています。インテンション ロックは、主にトランザクション内の次の行に要求されるロックの種類を明らかにするために設計されたテーブル レベルのロックです。また、2 つのタイプに分けられます:

? 意図された共有ロック (IS Lock)、トランザクションはテーブル内の特定の行の共有ロックを取得したいと考えています。

? 意図的な排他ロック (IX Lock)、トランザクションはテーブル内の特定の行に対して排他ロックを取得しようとしています。

InnoDB は行レベルのロックをサポートしているため、インテンション ロックはテーブル全体 scan 以外のリクエストを実際にはブロックしません。共有ロック、排他ロック、意図共有ロック、意図排他ロックはすべて相互に互換性があります/相互に排他的な関係は、互換性マトリックスで表すことができます(yは互換性を意味し、n は互換性がないことを意味します)、以下に示すように:

競合

IS

意図共有ロック

Clash

S

シェアロック

互換性

競合

互換性

IX 意図排他ロック

紛争

紛争

互換性あり

互換性あり

インテント共有ロック

競合

互換性あり

互換性あり

対応

それらの間の関係はすべて互換性があります。つまり、それらはすべて単に「意図的」であり、まだ YY ステージで実際には何もしていないので、互換性があります。 残りは XIX S これら 4 つの関係セットは、関係から派生します。

簡単に言うと、の関係なぜ?なぜなら、トランザクションは IX ロックを取得した後、X ロックを取得する権利を有するからです。 XIXが互換性がある場合、両方のトランザクションがを取得する状況が発生します。相互排他は矛盾するため、XIXは相互排他のみ可能です。残りの 3 セットの関係は類似しており、同じ方法で導出できます。 3、ロックシーンをシミュレートします

InnoDB Pluginを導入する前は、SHOW FULL PROCESSLISSHOW ENGINE INNODB STATUSを介して現在のデータベースリクエストを表示し、トランザクション内のロック状況を判断することしかできませんでした。新しいバージョンの InnoDB プラグイン では、3 テーブル、INNODB_LOCKSINNODB_TRXinformation_schema に追加されましたライブラリINNODB_LOCK_WAITS。これらの 3 テーブルを使用すると、現在のトランザクションをより簡単に監視し、考えられるロックの問題を分析できます。データベースが正常に実行されている場合、これらの 3 テーブルはレコードがなく空になります。

3.1

、オープントランザクションt1t2、シミュレートロック

オープン

2セッション ウィンドウを開いて 2 トランザクション を開きますt1t2

最初のウィンドウでトランザクションを開きます

t1次のようにロック操作を実行しますt1トランザクションウィンドウインターフェース:

mysql> set autocommit =0;
Query OK, 0 rows affected (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
  开始执行锁定操作
mysql> select * from test.t1 where a<5 for update;
+---+----+----+
| a | b  | c  |
+---+----+----+
| 1 | c2 | c2 |
| 2 | a  |    |
| 3 | r5 | r3 |
| 4 | r4 | r5 |
+---+----+----+
4 rows in set (0.00 sec)
ログイン後にコピー


mysql>

这个时候,事务t1已经锁定了表t1的所有a<5的数据行,然后去第二个窗口开启第二个事务t2,如下,会看到update语句一直在等待事务t1释放锁资源,过了几秒后,会有报错信息,如下t2事务窗口界面:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
 
mysql> update test.t1 set b=&#39;t2&#39; where a=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>
ログイン後にコピー


3.2,通过3个系统表来查看锁信息

l 1INNODB_TRX

先看下表的重要字段以及记录的信息

a) trx_idinnodb存储引擎内部事务唯一的事务id

b) trx_state: 現在のトランザクションのステータス。

c) trx_started: トランザクションが開始された時刻。

d) trx_requested_lock_id: トランザクション id のステータスが LOCK WAIT の場合、この値は占有されているロック リソース現在のトランザクションidtrx_stateLOCK WAITでない場合、この値はnullです。 e) trx_wait_started

: トランザクションの開始を待機している時間。 f) trx_weight

: トランザクションの重みは、トランザクションによって変更およびロックされた行の数を反映します。 innodbのストレージエンジンでは、デッドロックが発生してロールバックが必要な場合、innodbストレージエンジンはロールバックの値が最も小さいトランザクションを選択します。

g) trx_mysql_thread_id:正在运行的mysql中的线程idshow full processlist显示的记录中的thread_id

h) trx_query:事务运行的sql语句,在实际中发现,有时会显示为null值,当为null的时候,就是t2事务中等待锁超时直接报错(ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction)后,trx_query就显示为null

……

因为前面模拟了事务锁场景,开启了t1t2事务,现在去查看这个表信息,会有2条记录如下:

mysql> select * from INNODB_TRX\G
*************************** 1. row ***************************
                    trx_id: 3015646
                 trx_state: LOCK WAIT
               trx_started: 2014-10-07 18:29:39
     trx_requested_lock_id: 3015646:797:3:2
          trx_wait_started: 2014-10-07 18:29:39
                trx_weight: 2
       trx_mysql_thread_id: 18
                 trx_query: update test.t1 set b=&#39;t2&#39; where a=1
       trx_operation_state: starting index read
         trx_tables_in_use: 1
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 376
           trx_rows_locked: 1
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: READ COMMITTED
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 10000
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
*************************** 2. row ***************************
                    trx_id: 3015645
                 trx_state: RUNNING
               trx_started: 2014-10-07 18:29:15
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 2
       trx_mysql_thread_id: 17
                 trx_query: NULL
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 0
          trx_lock_structs: 2
     trx_lock_memory_bytes: 376
           trx_rows_locked: 4
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: READ COMMITTED
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 10000
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
2 rows in set (0.00 sec)
 
mysql>
ログイン後にコピー


これは、トランザクションt2が実行中であるtrx_query: update test.t1 set b='t2' where a=1sqlステートメント、など、現在実行中のトランザクションの一部のみを記録します。 t1が先に実行されるので trx_state: RUNNING 最初に適用されたリソースは常に実行中、t2は後から実行されるので trx_state: LOCK WAIT in Wait t1が完了した後にリソースが解放されるようにします。 ただし、ロックの一部の詳細を慎重に判断することはできません。INNODB_LOCKS テーブル データを再度確認する必要があります。

l

2INNODB_LOCKSテーブルa)

lock_id

: ロックされたidとロックされたスペースID、番号、ページ数、数量B) Lock_trx_id

: ロックトランザクション

IDc) lock_mode

: ロックモード。

d) lock_type:锁的类型,表锁还是行锁

e) lock_table:要加锁的表。

f) lock_index:锁的索引。

g) lock_spaceinnodb存储引擎表空间的id号码

h) lock_page:被锁住的页的数量,如果是表锁,则为null值。

i) lock_rec:被锁住的行的数量,如果表锁,则为null值。

j) lock_data:被锁住的行的主键值,如果表锁,则为null值。

mysql> select * from INNODB_LOCKS\G
*************************** 1. row ***************************
    lock_id: 3015646:797:3:2
lock_trx_id: 3015646
  lock_mode: X
  lock_type: RECORD
 lock_table: `test`.`t1`
 lock_index: PRIMARY
 lock_space: 797
  lock_page: 3
   lock_rec: 2
  lock_data: 1
*************************** 2. row ***************************
    lock_id: 3015645:797:3:2
lock_trx_id: 3015645
  lock_mode: X
  lock_type: RECORD
 lock_table: `test`.`t1`
 lock_index: PRIMARY
 lock_space: 797
  lock_page: 3
   lock_rec: 2
  lock_data: 1
2 rows in set (0.00 sec)
 
mysql>
ログイン後にコピー


owren現在のロック情報を見ることができます。2。トランザクションはロックされています。同じデータを見てください

Lock_space:797Lock_Page:3Lock_rec:2トランザクションt1およびトランザクションt2同じlnodbdataブロックにアクセスしてから、lock_datafieldinformationlock_data:1を渡すと、データのロックが表示されます行はすべて主キー 1 を持つデータ レコードです。2 トランザクション t1t2 が同じリソースに適用されていることがわかります。そのため、それらはロックされ、トランザクションが待機中です。 lock_modeからも確認できます:

PS: 範囲クエリの更新を実行する場合、この lock_data の値は完全には正確ではありません。範囲更新を実行すると、lock_data は、現在のリソースがロックされている場合、同時にページがロックされているため、最初に見つかった最初の行の主キー値のみを返します id; InnoDB ストレージ エンジンのバッファ プールの容量により、INNODB_LOCKS テーブルを表示すると、この lock_data の値が表示されます。 InnoDB ストレージ エンジンはディスクからの別のルックアップを実行しないことを意味します。 INNODB_LOCK_WAITS テーブル

トランザクション量が比較的少ない場合は直感的に確認できますが、トランザクション量が非常に大きくロック待ちが頻繁に発生する場合は、

INNODB_LOCK_WAITS

テーブルを使用してさらに多くのことを行うことができます現在のロック待機状況を直感的に反映します:

INNODB_LOCK_WAITS テーブルのメインフィールドは次のとおりです:

1) requesting_trx_id:申请锁资源的事务id

2) requested_lock_id:申请的锁的id

3) blocking_trx_id:阻塞的事务id

4) blocking_lock_id:阻塞的锁的id

去看下当前锁等待信息,如下所示:

mysql> select * from INNODB_LOCK_WAITS\G
*************************** 1. row ***************************
requesting_trx_id: 3015646
requested_lock_id: 3015646:797:3:2
  blocking_trx_id: 3015645
 blocking_lock_id: 3015645:797:3:2
1 row in set (0.00 sec)
mysql>
ログイン後にコピー


这里我们可以看到事务t1(3015646)申请了锁资源,而事务t2(3015645)则阻塞了事务t1的申请。我们管理其他表,得到更直观的详细信息,如下所示:

mysql> SELECT it2.`trx_id` AS waiting_trx_id, it2.`trx_mysql_thread_id` AS waiting_thread,it2.`trx_query` AS waiting_query,  it1.`trx_id` AS blocking_trx_id, it1.`trx_mysql_thread_id` blocking_thread, it1.`trx_query` blocking_query FROM `information_schema`.`INNODB_LOCK_WAITS` ilw, `information_schema`.`INNODB_TRX` it1,`information_schema`.`INNODB_TRX` it2 WHERE it1.`trx_id`=ilw.`blocking_trx_id` AND it2.`trx_id`=ilw.`requesting_trx_id`;
+----------------+----------------+-------------------------------------+-----------------+-----------------+----------------+
| waiting_trx_id | waiting_thread | waiting_query                       | blocking_trx_id | blocking_thread | blocking_query |
+----------------+----------------+-------------------------------------+-----------------+-----------------+----------------+
| 3015647        |             18 | update test.t1 set b=&#39;t2&#39; where a>2 | 3015645         |              17 | NULL           |
+----------------+----------------+-------------------------------------+-----------------+-----------------+----------------+
1 row in set (0.00 sec)
 
mysql>
ログイン後にコピー


4 原理分析一貫性 非ロック行読み取り (一貫性のある非ロック読み取り

CNRと呼ばれる) は、InnoDBを参照します ストレージ エンジンが電流を読み取る行マルチバージョン管理 (マルチバージョン管理) による実行 タイムデータベースで実行されるデータ。読み取り行が deleteupdate

操作を実行している場合、読み取り操作は行ロックが解放されるまで待機しません。逆に、 InnoDB ストレージ エンジンはその行を読み取ります。以下の図に示すように、行のスナップショット データ: Xのリリースを待つ必要がないため、非ロック読み取り。アクセスされた行のロック、スナップショット データ この実装は Undo セグメントを通じて実装され、Undo はトランザクション内のデータをロールバックするために使用されるため、スナップショット自体が使用されます。さらに、履歴データを変更する必要がないため、スナップショットの読み取りにはロックをアップロードする必要がありません。

非ロック読み取りは、InnoDB

ストレージ エンジンのデフォルト設定では、これがデフォルトの読み取り方法であり、読み取りはテーブルのロックを占有したり待機したりしません。 。ただし、トランザクション分離レベルが異なると読み取り方法が異なります。すべてのトランザクション分離レベルで一貫した読み取りが行われるわけではありません。同様に、両方が一貫した読み取りを使用する場合でも、スナップショット データの定義は異なります。

快照数据其实就是当前数据之前的历史版本,可能有多个版本。如上图所示,一个行可能不止有一个快照数据。我们称这种技术为行多版本技术。由此带来的并发控制,称之为多版本并发控制(Multi Version Concurrency ControlMVCC)。

Read CommittedRepeatable Read模式下,innodb存储引擎使用默认的非锁定一致读。在Read Committed隔离级别下,对于快照数据,非一致性读总是读取被锁定行的最新一份快照数据;而在Repeatable Read隔离级别下,对于快照数据,非一致性读总是读取事务开始时的行数据版本。

4.2CNR实例

开启2Session AB

Session  A:
mysql> begin;
Query OK, 0 rows affected (0.01 sec)
 
mysql> select * from t1 where a=1;
+---+----+----+
| a | b  | c  |
+---+----+----+
| 1 | c2 | c2 |
+---+----+----+
1 row in set (0.00 sec)
 
mysql>
ログイン後にコピー


Session A中事务已经开始,读取了a=1的数据,但是还没有结束事务,这时我们再开启一个Session B,以此模拟并发的情况,然后对Session B做如下操作:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
 
mysql> update t1 set a=111 where a=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
 
mysql>
ログイン後にコピー


Session 中将a=1的行修改为a=111,但是事务同样没有提交,这样a=1的行其实加了一个X锁。这时如果再在Session A中读取a=1的数据,根据innodb存储引擎的特性,在Read CommittedRepeatable Read事务隔离级别下,会使用非锁定的一致性读。回到Session A,节着上次未提交的事务,执行select * from t1 where a=1;的操作,显示的数据应该都是原来的数据:

mysql> select * from t1 where a=1;
+---+----+----+
| a | b  | c  |
+---+----+----+
| 1 | c2 | c2 |
+---+----+----+
1 row in set (0.00 sec)
 
mysql>
ログイン後にコピー


因为当前a=1的数据被修改了1次,所以只有一个版本的数据,接着我们在Session Bcommit上次的事务。如:

mysql> commit;
Query OK, 0 rows affected (0.00 sec)
 
mysql>
ログイン後にコピー


Session B提交事务后,这时再在Session A中运行select * from t1 where a=1;sql语句,在READ-COMMITTEDREPEATABLE-READ事务隔离级别下,得到的结果就会不一样,对于READ-COMMITTED模事务隔离级别,它总是读取行的最新版本,如果行被锁定了,则读取该行的最新一个快照(fresh snapshot)。因此在这个例子中,因为Session B已经commit了事务,所以在READ-COMMITTED事务隔离级别下会得到如下结果,查询a=1就是为null记录,因为a=1的已经被commit成了a=111,但是如果查询a=111的记录则会被查到,如下所示:

mysql> show variables like &#39;tx_isolation&#39;;
+---------------+----------------+
| Variable_name | Value          |
+---------------+----------------+
| tx_isolation  | READ-COMMITTED |
+---------------+----------------+
1 row in set (0.00 sec)
 
mysql> select * from t1 where a=1;
Empty set (0.00 sec)
 
mysql> select * from t1 where a=111;
+-----+----+----+
| a   | b  | c  |
+-----+----+----+
| 111 | c2 | c2 |
+-----+----+----+
1 row in set (0.01 sec)
 
mysql>
ログイン後にコピー


但是如果在REPEATABLE-READ事务隔离级别下,总是读取事务开始时的数据,所以得到的结果截然不同,如下所示:

mysql> show variables like &#39;tx_isolation&#39;;
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tx_isolation  | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)
 
mysql> select * from t1 where a=1;
+---+----+----+
| a | b  | c  |
+---+----+----+
| 1 | c0 | c2 |
+---+----+----+
1 row in set (0.00 sec)
 
mysql> select * from t1 where a=111;
Empty set (0.00 sec)
 
mysql>
ログイン後にコピー


对于READ-COMMITTED的事务隔离级别而言,从数据库理论的角度来看,其实违反了事务ACIDI的特性,既是隔离性,整理成时序表,如下图所示。

| |

Time

Session A

Session B

| time 1

Begin;

Select * from t1 where a=1;有记录

| time 2

Begin;

Update t1 set a=111 where a=1;

|

t1から*を選択してくださいここで、a=1;

記録

コミット;

V 時間 6

コミット;

ACID原則のI原則分離に従う場合、セッション全体でセッションASelect * from t1 where a=1;がクエリされる必要があります。データは一定のままですが、現時点では セッション A は時間 5 で終了していません。クエリ結果は変更されており、時間 1 および時間 3 と矛盾しており、ACID の分離を満たしていません。 FOR UPDATE && SELECT LOCK IN SHARE MODE


デフォルト この場合、

innodb

ストレージエンジンの

select

操作は一貫した非ロック読み取りを使用しますが、場合によっては読み取り操作が使用されます。ロックする必要があります。

Innodbストレージ エンジンは、読み取り行レコードの select ステートメント ;

2

タイプの追加ロック操作をサポートします。 1つ追加します

? SELECT ... LOCK IN SHARE MODE 对于读取的行记录添加一个S共享锁。其它事务可以向被锁定的行加S锁,但是不允许添加X锁,否则会被阻塞。

对于一致性 非锁定读,即使读取的行数已经被SELECT ... FOR UPDATE了,但是也是可以进行读取的。

PS… FOR UPDATE以及LOCK IN SHARE MODE必须在一个事务中,如果事务commit了,锁也就释放了,所以在使用的时候务必加上begin;start transaction或者set autocommit=0;

例子如下:

会话A:开启事务,执行LOCK IN SHARE MODE;锁定

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
 
mysql> SELECT * FROM t1 WHERE a=1 LOCK IN SHARE MODE;
+---+----+----+
| a | b  | c  |
+---+----+----+
| 1 | c0 | c2 |
+---+----+----+
1 row in set (0.00 sec)
 
mysql>
ログイン後にコピー


同时在另外一个窗口开启会话B,执行dml操作

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
 
mysql> update t1 set a=111 where a=1;
ログイン後にコピー


这里会卡住,没有信息。

再开启一个会话C,查询INNODB_LOCKSINNODB_TRXINNODB_LOCK_WAITS表,就会看到锁的详细信息:

mysql> select * from INNODB_LOCKS;
+-----------------+-------------+-----------+-----------+-------------+------------+------------+-----------+----------+-----------+
| lock_id         | lock_trx_id | lock_mode | lock_type | lock_table  | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-----------------+-------------+-----------+-----------+-------------+------------+------------+-----------+----------+-----------+
| 3015708:797:3:2 | 3015708     | X         | RECORD    | `test`.`t1` | PRIMARY    |        797 |         3 |        2 | 1         |
| 3015706:797:3:2 | 3015706     | S         | RECORD    | `test`.`t1` | PRIMARY    |        797 |         3 |        2 | 1         |
+-----------------+-------------+-----------+-----------+-------------+------------+------------+-----------+----------+-----------+
2 rows in set (0.00 sec)
 
mysql>
mysql> select * from INNODB_LOCK_WAITS;
+-------------------+-------------------+-----------------+------------------+
| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id |
+-------------------+-------------------+-----------------+------------------+
| 3015708           | 3015708:797:3:2   | 3015706         | 3015706:797:3:2  |
+-------------------+-------------------+-----------------+------------------+
1 row in set (0.00 sec)
 
mysql>
mysql> SELECT it2.`trx_id` AS waiting_trx_id, it2.`trx_state` AS waiting_trx_status,it2.`trx_mysql_thread_id` AS waiting_thread,it2.`trx_query` AS waiting_query,
    -> it1.`trx_id` AS blocking_trx_id, it1.`trx_mysql_thread_id` blocking_thread, it1.`trx_query` blocking_query
    -> FROM `information_schema`.`INNODB_LOCK_WAITS` ilw, `information_schema`.`INNODB_TRX` it1,`information_schema`.`INNODB_TRX` it2
    -> WHERE it1.`trx_id`=ilw.`blocking_trx_id` AND it2.`trx_id`=ilw.`requesting_trx_id`;
+----------------+--------------------+----------------+-------------------------------+-----------------+-----------------+----------------+
| waiting_trx_id | waiting_trx_status | waiting_thread | waiting_query                 | blocking_trx_id | blocking_thread | blocking_query |
+----------------+--------------------+----------------+-------------------------------+-----------------+-----------------+----------------+
| 3015708        | LOCK WAIT          |             18 | update t1 set a=111 where a=1 | 3015706         |              21 | NULL           |
+----------------+--------------------+----------------+-------------------------------+-----------------+-----------------+----------------+
1 row in set (0.00 sec)
 
mysql>
ログイン後にコピー


会话A开启的事务1(事务id3015706)执行了SELECT * FROM t1 WHERE a=1 LOCK IN SHARE MODE;

ステートメントは a=1 の行に S ロックを追加したため、トランザクション 2 がセッション B (トランザクション id: 2 3015708 ) が実行されました update t1 set a=111 where a=1;sql ステートメントは トランザクション 1 がブロックされているため、トランザクション 2 のステータス値は次のようになります待っていたLOCK WAIT。トランザクションがタイムアウトを待機するまで、エラーは次のように報告されます: mysql> update t1 set a=111 where a=1;ERROR 1205 (HY000): ロック待機タイムアウトを超過しました

mysql>

この時点で、セッション

B

のトランザクション

2

が終了します

update t1 set a=111 where a=1;'s dml リクエスト操作。 6

、自己成長およびロック

自增长在数据库中是非常常见的一种属性,在Innodb的存储引擎的内存结构中,对每个含有自增长值的表都有一个自增长计数器(auto-increment counter)。当对有自增长字段的表进行insert时候,这个计数器会被初始化,执行如下的sql语句来得到计数器的值。

SELECT MAX(auto_inc_col) FROM tablename FOR UPDATE;

插入操作会依据这个自增长的计数器值+1赋予自增长列,这个实现方式称为AUTO-INC Locking,这种锁其实是一种特殊的表锁机制,为了提高插入的性能,锁不是在一个事务完成后才释放,而是在完成对自增长值插入的sql语句后立即释放。

mysql 5.1.22版本开始,提供了一些轻量级互斥的自增长实现机制,这种机制大大提高自增长值插入的性能。还提供了一个参数innodb_autoinc_lock_mode,默认值为1.

自增长的分类:

mysqlinnodb表中,自增长列必须是索引,而且必须为索引的第一列,如果是第二个列会报错如下所示:

mysql> CREATE TABLE t(a INT AUTO_INCREMENT ,b VARCHAR(10),KEY (b,a));
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key
mysql>
mysql> CREATE TABLE t(a INT AUTO_INCREMENT ,b VARCHAR(10),PRIMARY KEY (a),KEY (b,a));
Query OK, 0 rows affected (0.01 sec)
 
mysql>
ログイン後にコピー


而在myisam表中,则没有这样的限制,如下所示:

mysql>  CREATE TABLE t_myisam(a INT AUTO_INCREMENT ,b VARCHAR(10),KEY (b,a))engine=myisam;
Query OK, 0 rows affected (0.01 sec)
ログイン後にコピー


 

mysql>

 

7MySQL外键和锁

innodb存储引擎中,对于一个外键列,如果没有显式的针对这个列添加索引Innodb存储引擎会自动的对其添加一个索引,这样可以避免表锁,这点比oracle做的较好一些,oracle需要自己手动添加外键锁。

 以上就是MySQL 温故而知新--Innodb存储引擎中的锁的内容,更多相关内容请关注PHP中文网(www.php.cn)!

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!