1

ワークスペースAとワークスペースBにデータベースがあります。オンラインには、両方のワークスペースから常に更新されるこのデータベースのコピーがあります。また、他のワークスペースが変更を加えるたびに、両方のワークスペースでデータベースを更新する必要があります。

すべてがうまく機能していますが、私の問題はこれです。たとえば、2つのテーブルがStockありOrders、中Ordersには。である列がありstock_idます。

ワークスペースAが自動的にインクリメントされる「stock_id」=23で新しい「ストックX」を作成し、ワークスペースBが自動的にインクリメントされる「stock_id」= 23で新しい「ストックY」を作成する場合、ワークスペースBはワークスペースAの「ストックX」を追加します。ワークスペースBはワークスペースBの「ストックY」を追加しますが、それぞれがデータベースごとに異なるIDを持ちます。

この問題は、ワークスペースAが「StockX」であるstock_id = 23で注文を行うときに発生します。このクエリが中央データベースに送信され、次にワークスペースBに送信されると、注文が挿入されますが、stock_id=23は「ストックY」。

私は本当にこの感謝でいくつかの助けをいただければ幸いです:)

4

3 に答える 3

2

ワークスペースAとBがそれぞれID23の異なるエントリを持っている場合、唯一のオプションは、レコードが中央DBに更新されるときに、エントリごとに2次キーを作成することです。このキーは、更新時にワークスペースデータベースに再コピーされ、真に一意の識別子を使用してアイテムにアクセスできるようになります。

ただし、この方法は使用しないことを強くお勧めします。

適切な方法は、ワークスペース1と2で使用されるWebまたはデスクトップアプリケーションを作成することです。これらのアプリケーションは、中央データベースに接続し、すべてのデータアクセスに使用します。優れたデータベース設計とは、一般に、データの重複コピーをできるだけ少なくすることを意味します。注文や在庫などの複数のコピーを3つの異なるデータベースで実行することにより、将来のデータの破損や損失に備えることができます。この問題は、データベースが大きくなるにつれて修復がますます困難になります。サイズ。データベースが大きくなる前に、構造上の問題を修正してください。

于 2012-04-14T16:03:25.337 に答える
2

編集:

元のデザインAUTO INCREMENTでは、主キーに列を使用していました。これに伴う問題は、最終的にマージされる別々のデータベースに同時にデータが入る場合に見られるように、重複するキーを作成してしまうことです。

別の方法の1つは、個別のデータベースごとにシーケンスを使用することです。残念ながら、シーケンスはmysqlでネイティブに使用できません(Oracle、db2などの他の多くのdbにはシーケンスがあります。これらは、衝突なしでこのタイプの分散データベース挿入を許可します)。 AUTO INCREMENT列は、必要な種類のレプリケーションを許可しません。

したがって、2つの選択肢があります。

1)location_idを設定する主キーの余分な部分を追加します(最初の回答に従って)。

2)または、列を使用するのではなく、独自のシーケンスを使用して手動で挿入のIDを生成しAUTO INCREMENTます。

シーケンスの次の値を取得したときにそれ自体をコミットするストアドプロシージャ/関数としてシーケンスを実装するのがおそらく最善です。これにより、値が使用されなくなる可能性があります。それは問題ありません。挿入全体がコミットされるまでシーケンス番号をコミットするのを待つ場合は、競合よりも優れています。

主なことは、最初の挿入を行うときに、ストアドプロシージャのシーケンス#を使用することです。データを2番目のデータベースに効果的に複製する場合、元のデータベースからの行で生成されたシーケンス#を使用します。また、衝突を防ぐために、シーケンスは異なる開始点を持つ各個別のデータベースで維持されます。

たとえば、各データベースで、次の2つの部分が必要になります。

1)名前付きシーケンスごとに次に使用可能なシーケンス番号を保持するテーブル。(シーケンスから引き出された主キーを取得する各テーブルはエントリを取得します)。2)次のシーケンス番号でそのテーブルにアクセスして更新する関数。

実装例は次のとおりです。

シーケンステーブル:

CREATE TABLE sequences (
  name varchar(30) NOT NULL,
  value int(10) unsigned,
  PRIMARY KEY (name)
) ENGINE=InnoDB

シーケンス関数:

delimiter //
create function get_next_value(p_name varchar(30)) returns int
  deterministic
  sql security invoker
begin
  declare current_val integer;
    UPDATE sequences
    SET value = (@current_val:=value) + 1
    WHERE name = p_name;

  return @current_val;
end //
delimiter ;

主な問題は、ストアド関数が単一のステートメントである必要があることです。これにより、関数は完了し、すぐにコミットされます(そうしないと、注文が入ったときにトランザクションが互いにスタックするようにロックされます。スループットがそれほど高くない場合、これはそれほど問題にはなりません。

私はこの関数を作成しませんでした。詳細については、http://www.bigdbahead.com/?p=185 参照してください。(そして、そのユーザーがここで私を見つけた場合、私は彼に答えを書かせて、ここでも適切なクレジットを与えることができます)。

ここで、データベースごとに、衝突を回避するために異なる番号で値を初期化します。したがって、ordersテーブルの場合、場所Aで、これを次のように初期化します。

insert into sequences ('orders', 1);

場所Bでは、これを次のように初期化します。

insert into sequences ('orders', 1000000);

そして、両方のデータベースで、に挿入するordersと、次のようになります。

insert into orders (order_id, . . .)
select mysql.get_next_value('user_id'), . . . <hardcoded-values>

-

私はこのソリューションをロードテストしていません-シーケンスに関する私の答えで私が提案していたことの概要としてそれをとってください。上記のブログエントリリンクをフォローアップする必要があります。これは、特にトランザクション制御下でこれがどのように機能するかについての詳細を提供します。コメントを参照してください(元の関数ではなく、コメントから関数の形式を取得しました) 、そしてもちろん、負荷がかかった状態でテストします。

于 2012-04-14T16:35:46.743 に答える
0

私はこの答えを考えましたが、Imは、上記の他の解決策よりもそれを使用する方が良いかどうかまだ混乱しています。ワークスペースBのすべてのクエリは、ローカルデータベースですぐに実行され、中央データベースにも送信されてから、ワークスペースAに送信されます。ただし、ワークスペースAのクエリは、ローカルデータベースですぐに実行されるのではなく、中央データベースに送信されてから、中央データベースに送信されます。それらをワークスペースBに送信し、ワークスペースBがこれらのクエリを実行すると、セントラルに通知し、次にワークスペースAに通知し、保存されたクエリを実行できます。そのため、ワークスペースBは通常どおりクエリを実行できますが、ワークスペースAはワークスペースBがクエリを実行したことを知っている場合にのみクエリを実行できます。これは、ワークスペースBがAのクエリを実行する前に、独自の新しいクエリを送信するためです。クエリ、次に、Aのクエリを実行します。したがって、AはBがクエリを実行したことを通知された後、Bが独自の新しいクエリを送信したかどうかを確認して実行し、次に独自のクエリを実行します。そうすれば、自動インクリメンテッドIDはすべて両方のワークスペースで同じになります。例:

ワークスペースA:

         q1= insert into stock (name) values ('A')    not executed

         q2= insert into stock (name) values ('B')    not executed

Aのデータベース:(EMPTY)

ワークスペースAはq1とq2をセントラルに送信し、セントラルがそれらのクエリを実行したことを確認して、それ自体で実行できるようにするのを待機しています。

ワークスペースB:

         q3= insert into stock (name) values ('C')    executed id=1

         q4= insert into stock (name) values ('D')    executed id=2

Bのデータベース:(1、'C')、(2、'D')

ワークスペースBは、q3とq4をセントラルに送信した後、q1とq2が通知されます。

ワークスペースBはq1とq2を実行します

          q1= insert into stock (name) values ('A')   executed id=3

          q2= insert into stock (name) values ('B')   executed id=4

データベースB:(1、'C')、(2、'D')、(3、'A')、(4、'B')

ワークスペースAは、Bがq1とq2を実行したことを通知されますが、q1とq2を実行する前にq3とq4を実行する必要があると通知されます。

ワークスペースA:

          q3= insert into stock (name) values ('C')    executed id=1

          q4= insert into stock (name) values ('D')    executed id=2

          q1= insert into stock (name) values ('A')    executed id=3

          q2= insert into stock (name) values ('B')    executed id=4

Bのデータベース:(1、'C')、(2、'D')、(3、'A')、(4、'B')

于 2012-04-15T09:44:18.463 に答える