私が2年前にデータベースについて知っていたことを望む3つのこと



取引
データベーストランザクションは、1つの機能単位に一連のデータベース相互作用を論理的にグループ化する方法です.このユニットはデータベースに適用されるか、または削除されます.
トランザクションが我々のアプリケーションをより弾力性にする方法の例を見てみましょう.この例では、我々は食料品店報酬アプリを実行します.100ポイントを持つすべてのメンバーが自動的にギフトカードを送信し、そのポイントを0にリセットを取得します.
それで、我々は自動的に彼らに感謝贈り物カードを送ることができるように、100以上の報酬ポイントですべての食料品店報酬メンバーを見つけるために、質問をします.我々はギフトカードを送った後、我々は報酬ポイントをゼロにする必要があります.
SELECT accounts.id, accounts.email FROM accounts JOIN rewards ON accounts.id=rewards.id WHERE rewards.points > 100;

次に我々のアプリは、ギフトカードのメールを送信するいくつかの非同期ジョブを作成します.
最後に、すべてのユーザーのポイントをリセットするデータベースを更新します.
UPDATE rewards SET rewards.points=0 WHERE rewards.points > 100;
それで、何がここで間違っていたかもしれませんか?私のデモアプリでは、おそらく、右働いた?
我々がここで見ることができた問題ケースは、『汚い読書』と呼ばれています.基本的に、100以上のポイントを持つすべての行を見つけるために、報酬表の問い合わせを行いました.その後、私たちは再び同じクエリを行いました.
誰かが店でチェックアウトして、我々が贈り物カード仕事をつくったあと、101 -> 101ポイントから行ったならば、点をゼロにリセットする前に、彼らの点はゼロにされました、しかし、GiftCardを受けることなく.
トランザクション内のこれらの相互作用のすべてをラップすると、この種の動作を防ぐことができます.データベースは、WHERE句が両方の読み込みで同じ結果を返すと保証しました.

外部キー制約
リレーショナルデータベースはすべて「関係」についてです.そして、それは単純な用語で異なったデータベース表で行を関連づけます.我々は、キーの何らかの種類でJOINをすることによってこれをします.最後の例を見て、我々はこのJOIN rewards ON accounts.id=rewards.idを行いました.
外部キー制約は、rewardsテーブルの行を作成するときに、id列がアカウント表の有効な行のIDである必要があることを確認するデータベース規則です.これは私たちに誤って悪いデータを使用してデータベースを埋めるために少し保護を与えるので、これは素晴らしいです.

行ロック
データベースへの同時書き込みについて考えるとき、私は髪がちょうどあなたの首の後ろに立っていることを望みます.微妙なものから壊滅的に至るまで、ここで間違って行くことができるものがたくさんあります.
現代のデータベースは、これらの様々なケースを扱うの非常に良い仕事をします、しかし、アプリケーション展望から正にそれを得ることはかなりの注意が支払われていることを必要とします.sqliteのようなデータベースには、デフォルトで別の接続からの同時書き込みもできません.
私がここで呼ぶ特定のケースは、あなたのデータベースへの更新が以前の読書に依存するところです.つのスレッドは、このようなことをしようとしている場合は、お互いの更新を一掃する可能性があります.
私たちの報酬プログラムのアプリから例を見てみましょう.
# User 1 has 15 rewards points
Connection 1: Reads current rewards of 15
Connection 2: Reads current rewards of 15
Connection 1: Calculates new values should be 17, and updates the database
Connection 2:  Calculates new values should be 16, and updates the database

# Final value: User 1 has 16 rewards points
この問題を解決するには、まず最初に、この依存している読み込みと書き込みが1つのトランザクション内にあることを保証することができます.第2に、必要なトランザクション分離レベルを使用するようにデータベースを構成していることを確認します.
これは以下のようになります.
SELECT id, points, rewards_id FROM rewards WHERE rewards_id=:rewards_id FOR UPDATE;
上記のものは、我々が我々のアップデート呼び出しをすでにしたように、我々が読んだ行の排他的なロックを維持しています.これは、トランザクションをコミットしたりロールバックしたりするまで、他の接続を一時的に読み込むのを防ぎます.今、我々は2つの同時の作家を持っている場合でも、彼らはお互いを吐き出すことはありません保証することができます書き込みます.

結論
ここの物語のモラルは、現代のデータベースがきちんとしたものをすることができるということです.これらの機能のいくつかを学ぶためにいくつかの時間を入れて価値がある、特にそれらの足で自分を撮影することを防ぐために.