Classes
- Dexie
- DexieError
- Collection
- and():Add JS based criteria to collection(向集合添加基於JS的條件)
- delete():Delete all objects in the collection(刪除集合中的全部對象)
- distinct():Remove duplicates of items with same primary key(刪除具備相同主鍵的項的重複項)
- modify():Modify all objects in the collection with given properties or function.(使用給定的屬性或函數修改集合中的全部對象。)
- ————————————————————————————————————————————————————————————————————
- each():Execute query and call a function for each item(執行查詢併爲每一個項調用函數)
- eachKey():Execute query on the index or primary key being used and call a function for each key(對正在使用的索引或主鍵執行查詢,併爲每一個鍵調用函數)
- eachPrimaryKey():Execute query on the index and call a function for each primary key that corresponds to the index.(對索引執行查詢,併爲對應於索引的每一個主鍵調用函數。)
- eachUniqueKey():Execute query on the index or primary key being used and call a function for each unique key(對正在使用的索引或主鍵執行查詢,併爲每一個惟一鍵調用函數)
- ————————————————————————————————————————————————————————————————————
- toArray():Execute query and get an array with the results sorted by the index used in the where() clause(執行查詢並獲取一個數組,其結果按where()子句中使用的索引排序)
- desc():Sort in descending order(按降序排序)
- reverse():Reverse the order of items.(顛倒項目順序。)
- sortBy():Execute query and get an array with the results sorted by given property(執行查詢並獲取按給定屬性排序結果的數組)
- ————————————————————————————————————————————————————————————————————
- first():Get the first item in the collection
- last():Get the last item in the collection(獲取集合中的最後一項)
- limit():Limit the result to given number of items(將結果限制爲給定的項目數)
- offset():Ignore N items before given offset and return the rest(忽略給定偏移量以前的n個項目並返回其他項目)
- until():Ignores items occurring after given filter returns true.(忽略給定篩選器返回true以後發生的項。)
- filter():Filter objects
- ————————————————————————————————————————————————————————————————————
- keys():Retrieve an array containing all keys of the collection (index or primary key depending on where() clause)(檢索包含集合全部鍵的數組(索引鍵或主鍵取決於where()子句))
- primaryKeys():Retrieve an array containing all primary keys of the collection(檢索包含集合的全部主鍵的數組)
- uniqueKeys():Retrieve an array containing all unique keys of the collection (index or primary key depending on where() clause)(檢索包含集合全部惟一鍵的數組(索引鍵或主鍵取決於where()子句))
- ————————————————————————————————————————————————————————————————————
- count():Get the number of items in the collection(獲取集合中的項數)
- or():Logical OR operation
- raw():Don’t filter results through reading hooks(不要經過閱讀掛鉤過濾結果)
- clone():Clone the query before manipulating it further (Does not clone database items).(在進一步操做以前克隆查詢(不克隆數據庫項)。)
- IndexSpec
- Promise
- Table
- name:The name of the object store represented by this Table instance.
- schema:The table schema of this object store.(此對象存儲區的表架構。)
- ————————————————————————————————————————————————————————————————————
- hook(‘creating’):Atomic CRUD hook called when object is about to be created in db.(當對象將要在數據庫中建立時調用)
- hook(‘reading’):Atomic CRUD hook called when object has been read from db and is about to be delivered to caller.
- hook(‘updating’):Atomic CRUD hook called when object is about to be modified in db.
- hook(‘deleting’):Atomic CRUD hook called when object is about to be deleted from db.
- ————————————————————————————————————————————————————————————————————
- toArray():Get an array containing all objects in store.(獲取包含存儲區中全部對象的數組。)
- limit():Return a Collection ordered by primary key, limited to N items.(返回按主鍵排序的集合,限制爲n個項目。)
- orderBy():Returns a Collection instance ordered by given index.(返回按給定索引排序的集合實例。)
- offset():Return a Collection ordered by primary key, where the first N items in the table are ignored.(返回按主鍵排序的集合,其中表中的前n個項將被忽略。)
- reverse():Returns a Collection instance with reversed order of the primary key.(返回主鍵順序相反的集合實例。)
- ————————————————————————————————————————————————————————————————————
- get():Retrieve object by primary key.
- where():Retrieve objects using a query.(使用查詢檢索對象。)
- add():Insert an object into store.
- bulkAdd():Same as add() but takes array arguments and is optimized for adding a large number of objects.(與add()相同,但接受數組參數,並針對添加大量對象進行了優化。)
- delete():Delete an object from store.
- bulkDelete():Same as delete() but takes and array of keys and is optimized for deleting a large number of objects.
- put():Replace or insert object.(替換或插入對象。)
- bulkPut():Same as put() but takes array arguments and is optimized for putting a large number of objects.
- update():Apply given changes to an existing object.(將給定的更改應用於現有對象。)
- clear():Clear all objects in store.
- ————————————————————————————————————————————————————————————————————
- defineClass():Define a javascript constructor function and map to this table.(映射表)
- mapToClass():Map this table to javascript constructor function.(映射表)
- count():Count all objects.
- each():Iterate all objects in store.(迭代存儲區中的全部對象。)
- filter():Apply javascript filter on all items in the object store
- toCollection():Get a Collection containing all objects in store.(獲取包含存儲區中全部對象的集合。)
- TableSchema
- Transaction
- Version
- WhereClause
- above():Returns a collection of objects where index is above given key(返回索引位於給定鍵上方的對象集合)
- aboveOrEqual():Returns a collection of objects where index is above or equal given key(返回索引高於或等於給定鍵的對象集合)
- ————————————————————————————————————————————————————————————————————
- below():Returns a collection of objects where index is below given key(返回索引低於給定鍵的對象集合)
- belowOrEqual():Returns a collection of objects where index is below or equal given key(返回索引低於或等於給定鍵的對象集合)
- ————————————————————————————————————————————————————————————————————
- between():Returns a collection of objects where index is between given boundaries(返回索引位於給定邊界之間的對象集合)
- inAnyRange():Returns a collection where index is within any of the given ranges.(返回索引在任何給定範圍內的集合)
- ————————————————————————————————————————————————————————————————————
- noneOf():Returns a collection where index equals anything but any of the keys in given array(返回一個集合,其中index等於給定數組中的任何鍵之外的任何值)
- notEqual():Returns a collection where index equals anything but given value(返回一個集合,其中索引等於給定值之外的任何值)
- ————————————————————————————————————————————————————————————————————
- equalsIgnoreCase():Returns a collection of objects where index equals given string-key ignoring case differences(返回一個對象集合,其中索引等於給定的字符串鍵,忽略大小寫差別)
- equals():Returns a collection of objects where index equals given key(返回索引等於給定鍵的對象集合)
- ————————————————————————————————————————————————————————————————————
- anyOfIgnoreCase():Returns a collection of objects where index matches any of given strings, ignoring case differences.(返回一個對象集合,其中索引與任何給定字符串匹配,忽略大小寫差別。)
- anyOf():Returns a collection of objects where index is equal to any of the keys in given array(返回一個對象集合,其中索引等於給定數組中的任何鍵)
- ————————————————————————————————————————————————————————————————————
- startsWith():Returns a collection of objects where index starts with given string-key(返回以給定字符串鍵開頭的對象集合)
- startsWithIgnoreCase():Returns a collection of objects where index starts with given string-key ignoring case differences(返回一個對象集合,其中索引以給定的字符串鍵開頭,忽略大小寫差別)
- ————————————————————————————————————————————————————————————————————
- startsWithAnyOf():Returns a collection of objects where index starts with any of the given strings(返回以任何給定字符串開頭的對象集合)
- startsWithAnyOfIgnoreCase():Returns a collection of objects where index starts with any of given strings, ignoring case differences(返回一個對象集合,其中索引以任何給定字符串開頭,忽略大小寫差別)
Quick Reference(快速參考)
——————————————————————————————————————————————
總體說明
- meaning that any operation that requires a result won’t be returned directly. Instead all such operations will return a Promise.(任何須要結果的操做都不會同步返回,全部這樣的行爲都將返回 Promise)
- But Dexie gives you a little shortcut in all methods returning a promise with a value, so the above code will be equal to:(Dexie 爲全部返回值的異步方法提供了簡便方法,能夠不寫Promise成功時的then而改成回調函數傳入方法中)
db.friends.where('name').startsWithIgnoreCase('arnold').toArray().then(function(a) {...})
// 等價於
db.friends.where('name').startsWithIgnoreCase('arnold').toArray(function(a) { // 回調函數傳入toArray這個異步方法
console.log(a.length);
}).catch(function(err) {
console.error(err);
});
——————————————————————————————————————————————
安裝
npm install dexie --save
——————————————————————————————————————————————
Declare Database(聲明數據庫)
- An instance of Dexie will represent a database connection(一個Dexie 實例就是一個database 對象)
- On your Dexie instance you will have direct access to instances of Table for each object store you have defined in your schema.(在Dexie 實例下能夠直接經過屬性訪問定義好的各個表實例)
- You only need to specify properties that you wish to index. The object store will allow any properties on your stored objects but you can only query them by indexed properties(只須要指定索引字段,value能夠保存任意屬性)
- Never index properties containing images, movies or large (huge) strings. Store them in IndexedDB, yes! but just don’t index them!(不要把任何大數據做爲索引對象,包括圖片、視頻、長字符串)
import Dexie from 'dexie';
var db = new Dexie("MyDatabase");
db.version(1).stores({
friends: "++id, name, age, *tags",
gameSessions: "id, score"
});
Understanding the flow(流程)
- First time ◦Database is being created(建立數據庫)
- If on(‘populate’) is triggered to populate ground data.(若是有populate,觸發填充初始數據)
- db.open() promise resolves.(db.open()調用then成功)
- Modify Schema(修改表的架構)
——————————————————————————————————————————————
The populate Event(初始化事件)
- If database is not present, or an earlier version was present, indexedDB’s onupgradeneeded event is fired and taken care of by Dexie.(若是數據庫不存在或傳入更高版本號,indexedDB的 onupgradeneeded事件將被觸發)
- IndexedDB is designed for handling database creation and upgrades through the onupgradeneeded event, and define the schema there.(indexeddb設計用於經過onupgradeneeded 事件處理數據庫建立和升級,並在其中定義模式。)
- Dexie adds a declarative schema syntax on top of that so that you don’t need to subscribe to the onupgradeneeded event either.(Dexie添加了一個聲明性模式語法,這樣您也不須要訂閱onupgradened事件。)
- The database schema is declarative, not imperative.(數據庫表架構是聲明性的,不是必需的。能夠在打開數據庫後再建立?)
- In case your database need initial data in order to work - data that must only be populated on database creation and never more, you can subscribe to the populate event. (若是要在數據庫創建時初始化數據可使用 populate 事件)
- This will only be called in case the database is initially created - not when it is upgraded.(populate 事件只在創建數據庫時調用,更新時不調用)
var db = new Dexie("MyTicketDB");
db.version(1).stores({
tickets: "++id,headline,description,statusId",
statuses: "++id,name,openess"
});
db.on("populate", function() {
// Init your DB with some default statuses:
db.statuses.add({id: 1, name: "opened", openess: true});
db.statuses.add({id: 2, name: "closed", openess: false});
db.statuses.add({id: 3, name: "resolved", openess: false});
db.statuses.add({id: 4, name: "wontfix", openess: false});
});
——————————————————————————————————————————————
Schema Syntax(表模式的語法)
++keyPath
Autoincrement primary key(自動增長的主鍵)
++
Hidden autoincremented primary key(隱藏的自動增長的主鍵)
keyPath
Means that primary key can be any type and we have to provide it ourself(主鍵能夠是任意值,新增時須要手動傳入)keyPath represents a property name or a dotted path to a nested property.(keypath能夠是屬性名或嵌套屬性的點路徑。)
(blank)
Hidden primary key(隱藏主鍵?)
&keyPath
Means that keyPath is indexed and keys must be unique(索引的值是惟一的)
*keyPath
Means that if key is an array, each array value will be regarded as a key to the object.(若是索引的值是一個數組,那麼數組中的每一項都能索引到該行數據)This feature lacks support in IE.(此功能在IE中缺少支持)
[keyPath1+keyPath2]
Defining a compound index for keyPath1 and keyPath2(以keyPath1 and keyPath2定義複合索引,和and查詢相同效果)his feature lacks support in IE.(此功能在IE中缺少支持)
Indexable Types(可索引類型)
- Only properties of certain types can be indexed. This includes string, number, Date and Array but NOT boolean, null or undefined. (能索引的類型:字符串、數值、日期、數組。不能索引的類型:布爾、null、undefined)
- IndexedDB 2.0 contains support for indexing binary data. (IndexedDB 2.0支持二進制數據作爲索引)
- Indexing a property path that turns out to hold a non-indexable type will have no effect. (爲一個屬性路徑創建索引,結果發現該屬性路徑包含一個不可索引的類型,將不會產生任何效果。)
- 屬性路徑,例如:定義索引或主鍵爲
a.b
,那麼這張表就會認爲value下的a是一個對象,而且這個對象有個屬性b能夠做爲主鍵或索引。能夠經過a.b
這個路徑直接操做表
——————————————————————————————————————————————
Class Binding(綁定類)
- Whichever method you use, your database will return real instances of your mapped class, so that the expression(數據庫獲取數據操做返回的數據將是這個類的一個實例)
- mapToClass() - map an existing class to an objectStore(將類映射到表)
class Friend {
// Prototype method
save() {
return db.friends.put(this); // Will only save own props.
}
// Prototype property(原型屬性)
get age() { // 這裏個get 是class中的一個關鍵字,new Friend().age時會調用該函數
return moment(Date.now()).diff (this.birthDate, 'years'); // moment是一個日期處理庫
}
}
db.friends.mapToClass(Friend);
- defineClass() - let Dexie declare a class for you(Dexie聲明一個類)
var db = new Dexie("MyAppDB");
db.version(1).stores({
folders: "++id,&path",
files: "++id,filename,extension,folderId"
});
var Folder = db.folders.defineClass({
id: Number,
path: String,
description: String
});
Folder.prototype.save = function () {
return db.folders.put(this);
}
var File = db.files.defineClass({
id: Number,
filename: String,
extension: String,
folderId: Number,
tags: [String]
});
File.prototype.save = function () {
return db.files.put(this);
}
——————————————————————————————————————————————
Change Tracking(變更鉤子)
- With Dexie it’s possible to control and monitor each database change.(使用dexie,能夠控制和監視每一個數據庫更改。經過鉤子函數)
- Whenever database is about to be read from or modified, they allow hook implementation to modify what will happen, or just react on the event.(當數據庫即將被讀取或修改時觸發)
- Hooks Documentation(鉤子列表)
- hook(‘creating’)
- hook(‘reading’)
- hook(‘updating’)
- hook(‘deleting’)
——————————————————————————————————————————————
打開數據庫(非必須)
- Dexie also supports queuing operations, meaning you can start using the database directly after having defined it. In case open() hasn’t been called, it will open it automatically and enqueue the operation to execute as soon as the database is finished opening. (Dexie 支持在實例化後鏈式調用請求,這些請求支持依序排隊執行。這時若是open未被調用,將自動打開數據庫執行這些排隊任務)
- If open fails, queued operations will immediately fail with the error event from the open request.(若是打開數據庫失敗,排隊任務也將失敗,錯誤信息顯示在oepn方法的Promise.cacth中)
var db = new Dexie("FriendsAndPetsDB");
db.version(1).stores({
friends: "++id,name,isCloseFriend", // 自增主鍵和索引名
pets: "++id,name,kind"
});
db.open();
db.friends.add({name: "Ingemar Bergman", isCloseFriend: 0});
db.pets.add({name: "Josephina", kind: "dog", fur: "too long right now"});
——————————————————————————————————————————————
Upgrade(升級)
- 下一個版本會基於上一個版本改變,因此升級時應當保持原有版本的數據庫聲明不變
- If no database present, Dexie initializes the last version directly by parsing the stores schema syntax and adding stores and indexes accordingly. No upgrade() functions run in this case.(若是新建數據庫,upgrade方法不會被觸發)
- If any error occur in any upgrade function in the sequence, the upgrade transaction will roll back and db.open() will fail. (若是序列中的任何升級函數發生錯誤,升級事務將回滾,db.open()將失敗。)
db.version(1).stores({
friends: "++id,name,age,*tags",
gameSessions: "id,score"
});
db.version(2).stores({
friends: "++id, [firstName+lastName], yearOfBirth, *tags", // Change indexes(改變索引)
gameSessions: null // Delete table(刪除表)
}).upgrade(tx => {
// Will only be executed if a version below 2 was installed.(當前瀏覽器數據庫版本低於2時觸發)
return tx.friends.modify(friend => { // tx.friends返回的是Collection類的實例?
friend.firstName = friend.name.split(' ')[0];
friend.lastName = friend.name.split(' ')[1];
friend.birthDate = new Date(new Date().getFullYear() - friend.age, 0);
delete friend.name; // delete是js中刪除對象的關鍵字
delete friend.age;
});
});
——————————————————————————————————————————————
Add Items(添加)
- 容許存儲二級制數據,例如:new Uint8Array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
await db.friends.add({name: "Josephine", age: 21});
await db.friends.bulkAdd([
{name: "Foo", age: 31},
{name: "Bar", age: 32}
]);
——————————————————————————————————————————————
Update Items(更新)
// 替換或新增
await db.friends.put({id: 4, name: "Foo", age: 33});
await db.friends.bulkPut([
{id: 4, name: "Foo2", age: 34},
{id: 5, name: "Bar2", age: 44}
]);
// 根據主鍵更新(更新?)
await db.friends.update(4, {name: "Bar"});
// 根據搜索結果更新
await db.customers
.where("age")
.inAnyRange([ [0, 18], [65, Infinity] ]) // 返回索引在任何給定範圍內的集合。
.modify({discount: 0.5}); // 更新
——————————————————————————————————————————————
Delete items(刪除)
// 根據主鍵刪除
await db.friends.delete(4);
await db.friends.bulkDelete([1,2,4]);
// 根據搜索結果刪除
const oneWeekAgo = new Date(Date.now() - 60*60*1000*24*7);
await db.logEntries
.where('timestamp').below(oneWeekAgo)
.delete();
db.users.where('email').startsWith('david@').distinct() // 刪除具備相同主鍵的項的重複項?
——————————————————————————————————————————————
Query Items(查詢)
- 儘可能不使用傳入函數的方法,應該效率會比較低
- 查詢方式有兩種
- Table.get() - retrieve an object by its primary key.(經過主鍵獲取)
- Table.where() - do an advanced query.(執行高級搜索)
- Native indexedDB has no support for logical AND or OR operations.(原生indexedDB 不支持and 和 or 查詢)
- Logical OR cannot be done by filtering - we must query the database with two queries to get it.(or 是經過兩次查詢取並集得到的)
- We would gain no performance by letting the database handle Logical AND (launching two separate queries and the filter away entries that don’t exist in both collections).(and 經過js過濾性能更好)
var db = new Dexie('music');
db.version(1).stores({
genres: '++id,name',
albums: '++id,name,year,*tracks',
bands: '++id,name,*albumIds,genreId'
});
async function getBandsStartingWithA () {
const bands = await db.bands
.where('name')
.startsWith('A') // 返回以給定字符串鍵開頭的對象集合
.toArray();
await Promise.all (bands.map (async band => { // bands.map返回[promise, ... ]
[band.genre, band.albums] = await Promise.all([
db.genres.get (band.genreId), // 經過主鍵獲取
db.albums.where('id').anyOf(band.albumIds).toArray()
]);
}));
return bands;
}
db.users.where('name').startsWithIgnoreCase('da') // 返回一個對象集合,其中索引以給定的字符串鍵開頭,忽略大小寫差別
const abcFriends = await db.friends
.where("name")
.startsWithAnyOfIgnoreCase(["a", "b", "c"]) // 返回一個對象集合,其中索引以任何給定字符串開頭,忽略大小寫差別
.toArray();
await db.customers
.where("age")
.inAnyRange([ [0, 18], [65, Infinity] ]) // 返回索引在任何給定範圍內的集合。
.modify({discount: 0.5});
db.friends
.where('tags')
.equals('close-friend')
.primaryKeys(); // Retrieve an array containing all primary keys of the collection(返回查詢結果的全部主鍵組成的數組)
const someFriends = await db.friends
.where("age").between(20, 25) // 返回索引位於給定邊界之間的對象集合
.offset(150) // 忽略給定偏移量以前的n個項目並返回其他項目
.limit(25) // 將結果限制爲給定的項目數
.toArray(); // 執行查詢並獲取一個數組,其結果按where()子句中使用的索引排序
db.friends.toCollection() // 返回表中全部項的集合。
.modify(friend => {
// Modify each friend:
friend.firstName = friend.name.split(' ')[0];
friend.lastName = friend.name.split(' ')[1];
delete friend.name;
});
await db.friends
.where("name").equalsIgnoreCase("josephine") // 返回一個對象集合,其中索引等於給定的字符串鍵,忽略大小寫差別
.each(friend => { // 執行查詢併爲每一個項調用函數
console.log("Found Josephine", friend);
});
const friendsContainingLetterA = await db.friends
.filter(friend => /a/i.test(friend.name)) // 篩選對象
.toArray();
await db.friends
.where('age').above(25) // 返回age大於25
.or('shoeSize').below(8) // 返回shoeSize小於8
.or('interests').anyOf('sports', 'pets', 'cars') // 返回一個對象集合,其中索引等於給定數組中的任何鍵(數組?這個例子有問題嗎?)
.modify(friend => friend.tags.push("marketing-target")); // 使用給定的屬性或函數修改集合中的全部對象。
db.friends.where('shoeSize')
.between(37, 40)
.or('name')
.anyOf(['Arnold','Ingemar'])
.and(function(friend) { return friend.isCloseFriend; }) // 傳入過濾函數返回布爾值
.limit(10)
.each(function(friend){
console.log(JSON.stringify(friend));
});
const best5GameSession = await db.gameSessions
.orderBy("score") // 根據score字段排序
.reverse() // 顛倒項目順序
.limit(5) // 將結果限制爲給定的項目數
.toArray();
const forbundsKansler = await db.friends
.where('[firstName+lastName]')
.equals(["Angela", "Merkel"]) // 返回索引等於給定鍵的對象集合(複合索引時傳入數組,其餘傳入對應數據類型)
.first(); // 獲取集合中的第一項
// In Dexie 2.0, you could do the above query a little simpler:(在新版本中可寫爲)
const forbundsKansler = await db.friends.where({
firstName: "Angela",
lastName: "Merkel"
}).first();
// 或
const forbundsKansler = await db.friends.get({ // 獲取給定primarykey(主鍵)的對象或知足給定條件(keypath1:value1,keypath2:value2)的對象,並返回第一個匹配結果。
firstName: "Angela",
lastName: "Merkel"
});
// 等價於 select * from friends where firstName='Angela' order by lastName
// order by 排序
const angelasSortedByLastName = await db.friends
.where('[firstName+lastName]')
.between([["Angela", ""], ["Angela", "\uffff"])
.toArray()
——————————————————————————————————————————————
Transaction(事務)
- 事務能夠集合多個數據庫操做,這樣包裹在函數中的數據庫操做就能夠實現複用
- This will not only encapsulate your changes into an atomic operation, but also optimize your code! Internally, non-transactional operations also use a transaction but it is only used in the single operation, so if you surround your code within a transaction, you will perform less costly operations in total.(對數據庫的操做都是經過事務完成的,只是分爲顯示和隱示。把多個操做封裝爲事務能夠時多個操做統一回滾,而且提升性能)
- If modifying database and any error occur, every modification will be rolled back.(經過事務操做數據庫,當出現錯誤時可以自動回滾)
- You may do all write operations synchronically without the need to wait for it to finish before starting the next one. (see the 2nd example code below).(能夠同步執行全部寫操做)
- Even read-operations can be done the line after a write operations without waiting for write to finish - still your result will include all modifications. This is possible because all operations are queued when there is a pending write operation going on in current transaction.(事務中有寫操做時,全部的操做都會排隊執行,因此排在後面的讀操做可以讀取上一條寫操做寫入的數據)
- "rw" should be replaced with "r" if you are just going to do read operations.(能夠用‘r’替換'rw'若是讀數據是隻讀操做)
await db.transaction('rw', [db.friends], async () => { // 注意:這裏事務操做表的聲明使用了數組
// 注意這裏的事務處理函數使用了異步函數
const friend = await db.friends.get(1);
++friend.age;
await db.friends.put(friend);
});
db.transaction('rw', db.friends, db.pets, function () { // 注意:這裏事務操做表的聲明使用了多參數
// 注意這裏的事務處理函數使用了同步函數
// MAIN transaction block(主事務)
db.transaction('rw', db.pets, function () { // 事務嵌套,若是父事務回滾了,子事務會回滾嗎?
// SUB transaction block(子事務,事務能夠嵌套)
});
});
db.transaction('rw', db.friends, function() { // 注意:這裏事務操做表的聲明使用了單參數
db.friends.add({id:1, name:"Fredrik"});
db.friends.add({id:1, name:"Fredrik"}).catch(function (err) {
// Adding same primary key twice will of course fail. (兩次添加相同的主鍵會失敗。)
// But since we catch this error explicitely, the transaction wont abort. (可是,因爲咱們捕獲了這個錯誤,事務不會停止。)
// This makes it possible to continue the transaction in a managed way.
// If you still want to abort the transaction, just do Dexie.currentTransaction.abort(),(若是你想終止事務請執行Dexie.currentTransaction.abort())
// throw an exception, or just:(從新拋出錯誤)
// return Promise.reject(err);(返回Promise.reject(err))
});
}).then (function () {
alert ("Transaction successfully completed");
});
- IndexedDB will commit a transaction as soon as it isn’t used within the same task.(indexeddb將在同一任務中不使用事務時當即提交該事務。)
- News in Dexie 2.0.0-beta.6: You can now wait for other async APIs and still hold the transaction active, using Dexie.waitFor()(在Dexie 2.0.0-beta.6可使用Dexie.waitFor()保持事務打開狀態,執行非數據庫操做的異步方法)
- Make sure to use the global promise (window.Promise) within transactions. (在事務中只能使用綁定在winodw下的全局Promise)
// 該例子是錯誤示範,應該先把import庫綁定在window上,window.Promise = Promise
// promise-polyfill-of-your-choice是低版本瀏覽器promise的兼容庫
import Promise form 'promise-polyfill-of-your-choice';
db.transaction(..., ()=>{
Promise.all()
Promise.race() // Promise.race([promise1,promise2]) // 其中一個promise返回就會觸發Promise.race改變狀態
new Promise((resolve, reject) => { ... })
})
- In the case you write a library (not an app) and you want your library to work on old browsers without requiring a Promise polyfill, it is still safe to use Dexie.Promise:(Dexie內部提供了Dexie.Promise來兼容低版本瀏覽器)
db.transaction(..., ()=>{
Dexie.Promise.all()
Dexie.Promise.race()
new Dexie.Promise((resolve, reject) => { ... })
})
Exception Handling(異常處理)
- When you work with transactions, you will also get the benefit of being able to catch all errors in one single place - at the end of the transaction, instead of having to catch() every promise of each database operation. (使用事務時不須要對事務中的全部數據庫操做進行錯誤處理,事務的異常包含內部的全部錯誤)
- Any uncatuch error (no matter error events, exception or miss-spelled variable in your code) will abort the ongoing Transaction and trigger its returned Promise to reject, waking up any catch() clause attached to the transaction scope.(任何錯誤都會終止事務)
- If you catch a Promise from a database operation within a transaction, it will be considered to be handled and the transaction will not be aborted.(若是在事務中捕獲了異常後,事務會認爲異常已經被處理,並不會終止事務)
- If not rethrowing the error, Nils would be successfully added and transaction would commit since the error is regarded as handled when you catch the database operation.(若是沒有拋出錯誤,事務中其餘數據庫操做會被執行)
- This could be a common pitfall when people catch promises within transactions just to log it but expecting the transaction to abort. Solution: re-throw the errors that you don’t handle!(若是隻是爲了記錄錯誤,能夠經過從新拋出錯誤來終止事務)
——————————————————————————————————————————————
疑問
- db.diary.log 表對象(Table)彷佛沒有這個方法?
db.transaction('rw', db.friends, db.diary, async () => {
await spreadYourLove(); // spreadYourLove是另外一個事務
await db.diary.log({date: Date.now(), text: "Today I successfully spread my love"}); // 這裏的log很奇怪?
}).catch (err => {
console.error ("I failed to spread my love :( " + err.stack);
});
db.friends.where('name').startsWithIgnoreCase('arnold').toArray(function(a) {
console.log(a.length);
}).catch(DOMError, function(e) {
console.error("DOMError occurred: " + err);
}).catch(TypeError, function(e) {
console.error("TypeError occurred: " + err);
}).catch(function(err) {
console.error("Unknown error occurred: " + err);
}).finally(function(){
console.log("Finally the query succeeded or failed.");
});
- Dexie Promises supports a pattern similar to Thread-local storage where it is possible to have static properties that is bound to the executing promise and all it’s child-promises. This is similar Angular’s zone.js but in an unobtrusive way (no requirement of including any monkey-patching script). Dexie.js and it’s transaction API heavily depends on it’s transaction zones since it enables code to be aware of the currently executing transaction without having to pass transaction objects around.?