1

たとえば、http://starcounter.io/tutorials/1-introduction-to-part-1/ InvoiceDemo のサンプル アプリについて考えてみます

次のデータベース オブジェクトが宣言されています

using Starcounter;

[Database]
public class Invoice {
    public int InvoiceNo;
    public string Name;
    public decimal Total {
        get {
            return Db.SQL<decimal>(@"SELECT sum(r.Total)
                                     FROM InvoiceRow r
                                     WHERE r.Invoice = ?",
                                     this).First;
        }
    }
    public QueryResultRows<InvoiceRow> Items {
        get {
            return Db.SQL<InvoiceRow>(@"SELECT r
                                       FROM InvoiceRow r
                                       WHERE r.Invoice = ?",
                                       this);
        }
    }

    public Invoice() {
        new InvoiceRow() {
            Invoice = this
        };
    }
}

[Database]
public class InvoiceRow {
    public Invoice Invoice;
    public string Description;
    public int Quantity;
    public decimal Price;
    public decimal Total {
        get {
            return Quantity * Price;
        }
    }

    public InvoiceRow() {
        Quantity = 1;
    }
}

追加された請求書行の順序を確認したい場合は、標準の SQL DB で自動インクリメント ID を使用します。Starcounter でのベスト プラクティスは何ですか?

4

2 に答える 2

3

Starcounter は自動インクリメントされたユーザー ID を提供しません。さまざまな理由により、提供されるとは思えません。例えば:

  1. このような機能には、一元化されたカウンターとそれに対する要求のシリアル化が必要です。これはパフォーマンスの問題です。
  2. シリアル化の順序は内部実装に依存するため、アプリケーション開発者の期待に必ずしも応える必要はありません。

順序が何を意味し、アプリケーションによって期待されるかが明らかでない場合の例:

行を作成順に並べ替えることができることを確認する必要があります

作成時間は次のことを意味します。

  1. レコードが挿入されコミットされたとき。
  2. レコードがメモリに割り当てられたとき。
  3. ユーザーが要求を送信したとき。これにより、レコードが作成されます。
  4. レコードを作成するハンドラーが呼び出されたとき。

レコードは異なるトランザクションで同時に追加できるため、それらの順序はオプション間で大きく異なる場合があります。アプリケーション開発者のみが、どの順序が意味され、それがユーザー エクスペリエンス (UX) にどのように影響するかを知っています。

Starcounter はカウンターベースのオブジェクト IDを割り当てるため、自動インクリメント ID に似ていますが、データベース内のすべてのオブジェクト/レコードが対象です。ただし、次のことを覚えておくことが重要です。

  1. ID のグループを事前に割り当てることができるシナリオがあるため、増分順序が壊れます。たとえば、レプリケーターのシナリオ。
  2. 上記で説明したように、開発者が期待する順序と同じである必要はありません。
  3. アロケーターの実装またはフルスタック フレームワークのわずかな改善により、場合によっては以前とは異なる順序が生成される可能性があります。これはUXを壊す可能性があります。
  4. オブジェクト ID の割り当て方式は、パフォーマンス上の理由から将来変更される可能性が非常に高いです。したがって、オブジェクト ID 番号の手続は、時間内の手続に対応しません。

最後の点のため、Starcounter のオブジェクト ID を使用してレコードを作成時間で並べ替えることはお勧めできません。

他のデータベースの自動インクリメント ID にも同様の問題があると思います。そのため、UX を維持する必要がある場合、または将来的に大幅な変更が行われる可能性がある場合 (通常は予見できない場合)、それらを使用することはあまり安全ではありません。

私の意見では、順序はアプリケーション固有であり、アプリケーション ロジックで実装する必要があります。いくつかの方法があります:

  1. 同じレコードのオブジェクト ID は常に同じであることが保証されているため、タイムスタンプ フィールドを使用して、同じタイムスタンプを持つレコードを順序付けするための時間順序とオブジェクト ID を決定論的に識別します。
  2. [編集]データベース外の共有カウンター オブジェクトを持っています。ロックなどを介してシリアル化を実装する必要があります。たとえば、__sync_bool_compare_and_swaporInterlocked.Incrementを使用できます。これはアトミック操作であり、ロックは必要ありませんが、キャッシュには適していません。再試行可能なトランザクション スコープ外、つまりスナップショット分離を使用してアクセスすることが重要であることに注意してください。ただし、そのようなトランザクションで使用しても機能しますが、カウンターは再試行ごとに増加します。
  3. データベース オブジェクトを使用してカウンターを格納します。主な問題は、楽観的な同時実行性により、高負荷時に競合が多すぎることです。
  4. [編集] @warpech で提案されているように: など、既存の最大の ID を取得しSELECT MAX(InvoiceRowNo) FROM InvoiceRow、それをインクリメントします。同時実行の場合に同じ ID を回避するために、一意のインデックスを作成して一意の制約を追加します。トランザクション間の同時インクリメント競合の場合、トランザクションの 1 つが再試行​​され、もう 1 つが成功します。負荷が高いと競合が頻繁に発生する可能性があり、不運なリクエストが大幅に遅延するか、まったく通過しないことに注意してください。
于 2016-04-19T07:28:28.330 に答える