3

期待した結果が得られないスパイク コードを書いています。

基本的にカウンターの行であるテーブルがあります。他のテーブルはこれらの行を使用して、一意の ID を生成します。以下のコードを実行すると、select ステートメントに到達する最初のスレッドがその行またはテーブルのロックを取得し、一意の ID 値に対するすべての読み取りまたは書き込みが停止することを除いて例外がありました。ただし、2 番目のスレッドは常に最初のスレッドよりも前に完了します。これは、1 秒間スリープ状態になっているためです。したがって、両方とも同じ値を読み取り、同じ値を書き込むため、例外として 2 回ではなく 1 回だけインクリメントされます。

私のコードに何か問題がありますか、それとも分離レベルの理解が間違っていますか?

ボイラープレートコードを削除しました。MySQL データベースを使用した標準の sql.Connection。

private void incrementValue() {

        connection
                .setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);

        statement = connection.createStatement();

        System.out.println(Thread.currentThread().getName()
                + " doing select");
        resultSet = statement.executeQuery("select * from counter");
        System.out.println(Thread.currentThread().getName()
                + "after select");
        if (counter++ == 0) {
            Thread.sleep(1000);
        }
        String incrementedValue = getIncrementedValue(resultSet);

        statement.executeUpdate("update counter set counter='"
                + incrementedValue + "'");


}

private String getIncrementedValue(ResultSet resultSet) throws SQLException {
    String value = "";
    if (resultSet.next()) {
        System.out.println(Thread.currentThread().getName() + "Value was "
                + resultSet.getString(1));

        value = (new Integer(resultSet.getString(1)) + 1) + "";

    }

    return value;

}

これはメインから呼び出されます

public static void main(String[] args) {
    DatabaseExample databaseExample = new DatabaseExample();

    Runnable runnable = new Runnable() {

        @Override
        public void run() {
            DatabaseExample databaseExample = new DatabaseExample();
            databaseExample.incrementValue();
        }
    };
    new Thread(runnable).start();

    databaseExample.incrementValue();
}
4

1 に答える 1

3

SERIALIZABLE 分離レベルでも、複数の選択を並行して行うことができます。select 句の行をロックしたい場合は、 を使用しますselect ... for update

参考文献:

http://dev.mysql.com/doc/refman/5.1/en/select.html :

ページ ロックまたは行ロックを使用するストレージ エンジンで FOR UPDATE を使用する場合、クエリによって検査される行は、現在のトランザクションが終了するまで書き込みロックされます。LOCK IN SHARE MODE を使用すると、他のトランザクションが検査された行を読み取ることを許可する共有ロックが設定されますが、それらを更新または削除することはできません。

http://dev.mysql.com/doc/refman/5.1/en/set-transaction.html#isolevel_serializable :

シリアライズ可能

このレベルは REPEATABLE READ に似ていますが、自動コミットが無効になっている場合、InnoDB はすべての単純な SELECT ステートメントを暗黙的に SELECT ... LOCK IN SHARE MODE に変換します。

于 2013-02-09T15:00:56.797 に答える