6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Dexie.jsのトランザクションではまる

Last updated at Posted at 2018-09-28

Dexie.jsとは?

IndexedDBを簡単に扱うためのラッパーライブラリ(実は簡単ではなかったというお話:sob:)

IndexedDBとは?

簡潔に(雑に)表現すると、ブラウザ内のRDBMS。

上記リンク先にも書いてあるが、ローレベルなAPIなので、
ラッパーライブラリを使ったほうが実装が簡単。
今回Dexie.jsを使ったのはドキュメントが豊富だから。

Dexie.jsのインストール

$ yarn add dexie

終了!!!

Dexie.jsでのトランザクション

トランザクションではまってしまったのでその例を以下に示す。
まずは以下のrappersテーブルが既にあるものとする。

id name sort
1 Ad Rock 1
2 Biz Markie 2
3 Common 3

アドロックが俺はラッパーじゃないと言い出したのでテーブルから削除するトランザクションを考える。
ここで必要なのは削除と他のsortカラムの更新(デクリメント)である。
こういう処理はよくあると思う。
これをDexie.jsのトランザクションで書いてみる。

import Dexie from 'dexie';

const db = new Dexie('hiphop');

db.version(1).stores({
    rappers: '++id, name, sort'
});

db.rappers.bulkAdd([
    { name: 'Ad Rock', sort: 1 },
    { name: 'Biz Markie', sort: 2 },
    { name: 'Common', sort: 3 }
]);

db.transaction('rw', db.rappers, () => {
    db.rappers.get({ name: 'Ad Rock' }).then( adrock => {
        db.rappers.delete(adrock.id);
        db.rappers.where('sort').above(adrock.sort).each( rapper => {
            db.rappers.update(rapper.id, { sort: rapper.sort - 1 }).then( updated => {
                if (!updated) {
                    console.log('not updated.');
                }
            });
        });
    });
}).then( () => {
    console.log('committed');
}).catch( error => {
    console.log(error);
});
id name sort
2 Biz Markie 1
3 Common 2

実行すると正常に削除と更新がされる。

ここでトランザクション内で無理やりエラーを発生させてみよう。

db.transaction('rw', db.rappers, () => {
    db.rappers.get({ name: 'Ad Rock' }).then( adrock => {
        db.rappers.delete(adrock.id);
        db.rappers.where('sort').above(adrock.sort).each( rapper => {
            db.rappers.update(rapper.id, { sort: rapper.sort - 1 }).then( updated => {
                if (!updated) {
                    console.log('not updated.');
                }
            });
        }).then( () => {
            let z = a;  // エラー
        });
    });
}).then( () => {
    console.log('committed');
}).catch( error => {
    console.log(error);
});
id name sort
1 Ad Rock 1
2 Biz Markie 2
3 Common 3

ロールバックされ、データは更新されない。いい感じです。

次に、Dexie.jsにはTransaction.abort()というメソッドがある。

これを実行すると、

Dexie.currentTransaction.abort(); // Will discard all changes.

らしい。ロールバックされて強制終了するのではと想像する。

db.transaction('rw', db.rappers, () => {
    db.rappers.get({ name: 'Ad Rock' }).then( adrock => {
        db.rappers.delete(adrock.id);
        db.rappers.where('sort').above(adrock.sort).each( rapper => {
            db.rappers.update(rapper.id, { sort: rapper.sort - 1 }).then( updated => {
                if (!updated) {
                    console.log('not updated.');
                }
            });
        }).then( () => {
            Dexie.currentTransaction.abort();
        });
    });
}).then( () => {
    console.log('committed');
}).catch( error => {
    console.log(error);
});
id name sort
2 Biz Markie 1
3 Common 2

処理が中断されたことはコンソールでわかるけど、IndexedDBの中身を見ると、ロールバックされずにデータが削除更新されている。
abort()はロールバックしないということなのだろうか。
"Will discard all changes"じゃなくない??
それともトランザクションの記述の仕方が間違っているのだろうか。
とりあえず、abort()ではなく本当のエラーが起きたときはロールバックされているのでいいが、
プログラマブルにロールバックを実行できないのはもやっとする。
以上です:microphone:

6
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?