同僚が、MySQLの非常に奇妙な動作に気付いたところです。
Auto_incrementフィールドと一意に設定された別のフィールド(ユーザー名フィールドなど)を含むテーブルがあるとします。テーブルにすでに存在するユーザー名の行を挿入しようとすると、期待どおりに挿入が失敗します。それでも、auto_incrementの値は増加していますが、何回か失敗した後で有効な新しいエントリを挿入するとわかります。
たとえば、最後のエントリが次のようになっている場合...
ID: 10
Username: myname
...次の挿入時に同じユーザー名の値を持つ5つの新しいエントリを試し、次のように新しい行を作成します。
ID: 16
Username: mynewname
これ自体は大きな問題ではありませんが、MySQLリファレンスマニュアルに記載されているように、失敗した挿入リクエストでテーブルをフラッディングすることでテーブルを強制終了することは、非常に愚かな攻撃のように見えます。
「値が指定された整数型に格納できる最大整数より大きくなる場合、自動インクリメントメカニズムの動作は定義されません。」
これは予想される動作ですか?
InnoDB
はトランザクションエンジンです。
これは、次のシナリオでは、
Session A
はレコードを挿入します1
Session B
はレコードを挿入します2
Session A
はロールバックします、ギャップの可能性があるか、session B
がsession A
をコミットまたはロールバックするまでロックされます。
InnoDB
デザイナー(他のほとんどのトランザクションエンジンデザイナーと同様)は、ギャップを許可することを選択しました。
ドキュメント から:
自動インクリメントカウンターにアクセスする場合、
InnoDB
は、トランザクションの最後ではなく、現在のSQL
ステートメントの最後まで保持する特別なテーブルレベルのAUTO-INC
ロックを使用します。 。AUTO_INCREMENT
列を含むテーブルへの挿入の同時実行性を向上させるために、特別なロック解放戦略が導入されました…
InnoDB
は、サーバーが実行されている限り、メモリ内の自動インクリメントカウンターを使用します。前述のように、サーバーが停止して再起動すると、InnoDB
は最初のINSERT
の各テーブルのカウンターをテーブルに再初期化します。
id
列の折り返しが怖い場合は、BIGINT
(8バイト長)にしてください。
正確な内部構造がわからなければ、そうだと思います。自動インクリメントは、挿入の失敗に対してスキップされた値を許可する必要があります(SHOULD)。銀行取引など、トランザクション全体と複数のレコードがオールオアナッシングとして処理されているとします。挿入を試み、IDを取得してから、そのトランザクションIDを使用して後続のすべての詳細にスタンプを付け、詳細レコードを挿入する場合は、修飾された一意性を確保する必要があります。複数の人がデータベースを悪用している場合、それらの人も、トランザクションがコミットされたときに自分と競合しないように、自分のトランザクションIDを取得する必要があります。最初のトランザクションで何かが失敗しても、害はなく、ダウンストリームのぶら下がり要素はありません。
古い投稿ですが、これは人々を助けるかもしれません、あなたは innodb_autoinc_lock_mode を0または2に設定する必要があるかもしれません。
数値を取るシステム変数は、コマンドラインでは--var_name=value
として、オプションファイルではvar_name=value
として指定できます。
コマンドラインパラメータの形式:
--innodb-autoinc-lock-mode=0
[〜#〜]または[〜#〜]mysql.iniを開き、次の行を追加します。
innodb_autoinc_lock_mode=0