Image
Top
Navigation

トランザクション分離レベルについての確認 Dirty Lead

OrientDBは1.7.8の段階ではレベルをREPEATABLE READとしています。

ここでは実際にコードを書いて確認していきたいと思います。
手順としてはリモート接続にてJavaのAPIを使用して実施します。

Dirty Lead

まずはDirty Leadの確認。別のトランザクションでコミットされてないデータが読み取れる現象です。

手順としては、

1.トランザクションAでレコードを「未処理」から「トランザクションA」にUPDATE(未コミット)
2.トランザクションBでレコードをSELECTする
3.トランザクションAをロールバックする
4.トランザクションBで取得したデータは「トランザクションA」となっている。

プログラム2つの非常にシンプルなJavaプログラムを使用します。
一つは、トランザクションA用のプログラム.

package transaction.dirty;

import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.id.ORecordId;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.tx.OTransaction.TXTYPE;

public class DocumentDirtyLead1withSleep {

    /**
     * @param args
     */
    public static void main(String[] args) {
        ODatabaseDocumentTx database = null;
        try {

            System.out.println(">>>> トランザクションA");
            // remoteでデータベースへ接続します。

            database = new ODatabaseDocumentTx("remote:172.16.251.205/DocumentTest");
            database.open("root", "root");

            database.begin(TXTYPE.OPTIMISTIC);

            // RIDを指定して直接取得
            ODocument doc_ = database.load(new ORecordId("#26:0")).getRecord();

            // save前に値を確認
            System.out.println("> 更新処理前に値を確認");
            for (String fieldName : doc_.fieldNames()) {
                System.out.println(fieldName + " : " + doc_.field(fieldName));
            }

            // 更新します
            doc_.field("status", "トランザクションA");
            doc_.save();

            // save 後の値を確認
            System.out.println("> 更新したが未コミットの状態で値を確認");
            ODocument doc_2 = database.load(new ORecordId("#26:0")).getRecord();

            for (String fieldName : doc_2.fieldNames()) {
                System.out.println(fieldName + " : " + doc_2.field(fieldName));
            }

            System.out.println("---------- 10秒Sleepする ---------- ");
            Thread.sleep(10000); // 10秒Sleepする

            database.rollback();

            // ロールバック 後の値を確認
            System.out.println("> ロールバック 後の値を確認");
            ODocument doc_3 = database.load(new ORecordId("#26:0")).getRecord();

            for (String fieldName : doc_3.fieldNames()) {
                System.out.println(fieldName + " : " + doc_3.field(fieldName));
            }

            database.close();

        } catch (Exception e) {
            e.printStackTrace();
            database.rollback();

        } finally {

            database.close();
        }

    }
}

内容としては、RIDが#26:0の値を取得し「status」の値を「トランザクションA」へ更新します(コミットはしません)。処理の後に10秒ほどスリープします。
その間にトランザクション2を実行するためです。
トランザクション2が

確認のために、レコード取得後、更新後、スリープ明け後に値を表示指定ます。

こちらは、トランザクションB用のプログラム.

package transaction.dirty;

import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.id.ORecordId;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.tx.OTransaction.TXTYPE;

public class DocumentDirtyLead11 {

    public static void main(String[] args) {
        ODatabaseDocumentTx database = null;
        try {
            System.out.println(">>>> トランザクションB");
            // remoteでデータベースへ接続します。

            database = new ODatabaseDocumentTx("remote:172.16.251.205/DocumentTest");
            database.open("root", "root");

            database.begin(TXTYPE.OPTIMISTIC);

            // RIDを指定して直接取得
            ODocument doc_ = database.load(new ORecordId("#26:0")).getRecord();

            // トランザクショでAが更新(未コミット前)後の状態で値を取得
            System.out.println("> トランザクションAが更新(未コミット)後の状態で値を取得");
            for (String fieldName : doc_.fieldNames()) {
                System.out.println(fieldName + " : " + doc_.field(fieldName));
            }
            // トランザクションAがロールバックするのを待つために10秒Sleepする
            System.out.println("---------- 10秒Sleepする ---------- ");
            Thread.sleep(10000); 

            // 同一トランザクショでAがロールバック後に値を再取得
            System.out.println("> 同一トランザクショでAがロールバック後に値を再取得");
            ODocument doc_3 = database.load(new ORecordId("#26:0")).getRecord();

            for (String fieldName : doc_3.fieldNames()) {
                System.out.println(fieldName + " : " + doc_3.field(fieldName));
            }

            database.close();

        } catch (Exception e) {
            e.printStackTrace();
            database.rollback();
        } finally {
            database.close();
        }

    }
}

こちらの内容としては、RIDが#26:0の値を取得し「status」の値を「トランザクションB」へ更新しコミットはします。
その間にトランザクション2を実行するためです。
確認のために、レコード取得後、更新後、コミット後に値を表示しています。

こちらはAの結果です。

>>>> トランザクションA
> 更新処理前に値を確認
name : IsolationTest
status : 処理前
> save 更新したが未コミットの状態で値を確認
name : IsolationTest
status : トランザクションA
---------- 10秒Sleepする ----------
> ロールバック 後の値を確認
name : IsolationTest
status : 処理前

こちらはBの結果です。

>>>>トランザクションB
> トランザクションAが更新(未コミット)後の状態で値を取得
name : IsolationTest
status : 処理前
---------- 10秒Sleepする ----------
> 同一トランザクショでAがロールバック後に値を再取得
name : IsolationTest
status : 処理前

トランザクションBでは、未コミット前やロールバック後にも影響されずに処理前の値を表示できています。
これで、DocumentデータベースはDirtyLeadが発生していないことが確認できます。

次にグラフデータベースで確認をしてみましょう。

次はファジーリードに関して試していきたいと思います。