2

私のオフィスには、リモートWebサーバーに注文プラットフォームがあり、ローカルの本番マシンがあります。両方のWebサーバーが同じリモートMySQL(InnoDB)データベースにアクセスします。

私の問題:2〜3のトランザクションが開いている場合、制作には数分かかります。今回は、新しい請求書番号を生成してインクリメントします。最新の請求書番号は、データベースの番号テーブルに保存されます。

public Long getNewInvoiceNumber() {
    Criteria crit = getSession().createCriteria(Numbers.class);
    Numbers n = ((Numbers)crit.uniqueResult());
    Long newNumber = n.getInvoiceNumber() + 1L;
    n.setInvoiceNumber(newNumber);
    return newNumber;
}

これで、誰かが生産中に新しい注文を保存しているときに、同じ番号テーブルにアクセスして別の番号(請求書ではない)を生成しています。プロダクションによって処理されたすべての注文は、正しい請求書番号で保存されます。ただし、Numbers-Tableは最新の値で更新されず、請求書番号は生産前と同じままです。

トランザクションの1つに「古いテーブル」メッセージが表示されることを理解しています。しかし、MySQL / Hibernate / Javaの動作はどうですか?ロールバックしてこの危険なデータベースの不整合を回避できるように、トランザクションの1つから例外を取得したいと思います。

編集: これはテーブルがどのようにNumbers見えるかです:

id | invoice_number | tag_number
0  | 16533          | 1055

id主キーです。この1行にのみアクセスし、必要な数を増やします。

編集2: わかりました、このテーブル構造はちょっと悪いようです。私はそれを次のように更新しました:

id             | number
invoice_number | 16533
tag_number     | 1055

これで、各行に個別にアクセスできます。それでも私の問題が解決するかどうかはわかりません。

4

2 に答える 2

0

データベースを同時に操作するには、さまざまな方法があります。たとえば、オプティミスティックロックまたはペシミスティックロックを使用します(後者は遅延やデッドロックを引き起こす可能性があるため、注意が必要です)。

しかし、あなたの場合、トランザクションの終了時ではなく、トランザクションの開始直後にNumbersテーブルを変更する必要があると思います。これにより、請求書のスロットが確実に予約されます。

また、HibernateのIdジェネレーターを確認することも理にかなっています。価値を生み出すメカニズムを実装する方法について、さまざまなアイデアがあります。

于 2012-09-20T13:19:08.853 に答える
0
public Long getNewInvoiceNumber() {
    Criteria crit = getSession().createCriteria(Numbers.class);
    crit.setLockMode(LockMode.PESSIMISTIC_WRITE);   // LINE ADDED
    Numbers n = ((Numbers)crit.uniqueResult());
    Long newNumber = n.getInvoiceNumber() + 1L;
    n.setInvoiceNumber(newNumber);
    getSession().update(n);              // LINE ADDED
    return newNumber;
}

MySQLを使用している場合は、InnoDBを使用する必要があります。Hibernateがパーツ用に生成されたSQLに「FORUPDATE」を追加していることを確認する必要がありますcrit.uniqueResult()。また、(実行を停止するために)直後にJavaブレークポイントを設定し、同じSQLクエリを手動でテストすると、別のクライアントがブロックされます。

これは、SQLサーバーが正常であり、Dialectが正しくセットアップされており、基本的にこの機能が機能することをテストするためのものです。

これにより、次のInvoiceNumberの生成時にSQLサーバーでシリアル化が強制されます。

このようにして、1000人のユーザーが同時に請求書を作成しようとしても、2つのInvoiceNumberが同じになることはありません。

注:LockOptionsは、同時実行のこの側面に関するモードを指定するためにLockModeを置き換えます。ヘルプについては、休止状態のリリースノートを参照してください。

注:あなたは数分間続く取引について話しました。トランザクションがコミットされていない間、他のユーザーは新しい請求書番号を生成できません。ネストされた個別のトランザクションとしてこれを実行する必要があるかもしれません。次に、他の処理エラーのために番号を使用できなかった場合、InvoiceNumberに問題のある穴が表示されます。会計士/会計システムは、請求書番号の穴や、それらが古くなっていることを好みません。

関連するMySQLドキュメントリンクhttps://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

于 2012-09-20T13:19:34.787 に答える