问题
Hi I am trying to update records indexdb. I want to implement a generic method that allows me to upgrade to any field.
To do this I have a function that returns me the record I need.
function getObjectStoreClienteDB(clave,valor){
//Ahora recogeremos los datos de nuestro almacén "Productos"
var transaction = db.transaction(["customers"], "readwrite");
var objectStore = transaction.objectStore("customers");
var index = objectStore.index(clave);
var singleKeyRange = IDBKeyRange.only(valor);
// To use one of the key ranges, pass it in as the first argument of openCursor()/openKeyCursor()
return index.openCursor(singleKeyRange);
}
And another that updates the returned record
function updateClienteDB(clave,valor,newvalor){
console.log("updateClienteDB ... clave: "+clave+" valor: "+valor+" newvalor: "+newvalor);
var objectStore = db.transaction(["customers"], "readwrite").objectStore("customers");
request = getObjectStoreClienteDB("name",valor);
request.onsuccess = function(event) {
// Get the old value that we want to update
var data = request.result;
// update the value(s) in the object that you want to change
if(clave=="name")
data.name = newvalor;
else if(clave=="email")
data.email = newvalor;
else if(clave=="matricula")
data.matricula = newvalor;
else if(clave=="telefono")
data.telefono = newvalor;
// Put this updated object back into the database.
var requestUpdate = objectStore.put(data);
requestUpdate.onerror = function(event) {
console.log("addCliente ..."+name+" "+email +" "+ event.target.errorCode);
};
requestUpdate.onsuccess = function(event) {
console.log("All done!");
};
};
}
In the line: var requestUpdate = objectStore.put(data);
error: Uncaught TransactionInactiveError: Failed to execute 'put' on 'IDBObjectStore': The transaction has finished.
回答1:
Try using the same readwrite transaction. It looks like you are calling db.transaction(...) in two places. You are then trying to update an object store linked to a different transaction in the context of a different transaction. The result is that one of the transactions completes (its lifetime ends), probably because it times out, because it does not detect any registered requests. The objectStore variable lives within the lifetime of the transaction that completes early, so you get a transaction finished error.
This is trivial to fix. You simply need to register a new request (the put request) on the same transaction before its lifetime ends. To do this, you can either (a) inline the statement request = getObjectStoreClienteDB("name",valor);
so that it is attached to the same transaction instance, or (b) store the transaction instance in a separate variable and reference that in both calls.
For example, the following code is a modification of yours that uses a single transaction:
// this function was changed, it now takes an active transaction as its first argument.
function getObjectStoreClienteDB(transaction, clave,valor){
//Ahora recogeremos los datos de nuestro almacén "Productos"
// this was changed. instead of creating a new transaction we just reference the
// transaction instance passed to this function
var objectStore = transaction.objectStore("customers");
var index = objectStore.index(clave);
var singleKeyRange = IDBKeyRange.only(valor);
// To use one of the key ranges, pass it in as the first argument of openCursor()/openKeyCursor()
return index.openCursor(singleKeyRange);
}
function updateClienteDB(clave,valor,newvalor){
console.log("updateClienteDB ... clave: "+clave+" valor: "+valor+" newvalor: "+newvalor);
// this line was added. we create the transaction here, once
var transaction = db.transaction(["customers"], "readwrite");
// this line was changed, we simply reference the transaction instance here instead of
// creating a second transaction
var objectStore = transaction.objectStore("customers");
// this line was changed, we pass in the one active transaction instance to the function
// now instead of having the function create its own transaction
request = getObjectStoreClienteDB(transaction, "name",valor);
request.onsuccess = function(event) {
// Get the old value that we want to update
var data = request.result;
// update the value(s) in the object that you want to change
if(clave=="name")
data.name = newvalor;
else if(clave=="email")
data.email = newvalor;
else if(clave=="matricula")
data.matricula = newvalor;
else if(clave=="telefono")
data.telefono = newvalor;
// Put this updated object back into the database.
// this line now works. objectStore is attached to our 1 transaction that is still 'alive'
// because it gets registered 'in time' (before transaction finishes due to timeout due
// to no additional requests registered in allowed time window).
var requestUpdate = objectStore.put(data);
requestUpdate.onerror = function(event) {
console.log("addCliente ..."+name+" "+email +" "+ event.target.errorCode);
};
requestUpdate.onsuccess = function(event) {
console.log("All done!");
};
};
}
And, just to be clear, here is a second example. It re-creates a reference to the object store using the transaction of the caller, instead of cross referencing an object store attached to a different transaction:
function updateClienteDB(clave,valor,newvalor){
console.log("updateClienteDB ... clave: "+clave+" valor: "+valor+" newvalor: "+newvalor);
var objectStore = db.transaction(["customers"], "readwrite").objectStore("customers");
request = getObjectStoreClienteDB("name",valor);
request.onsuccess = function(event) {
// Get the old value that we want to update
var data = request.result;
// update the value(s) in the object that you want to change
if(clave=="name")
data.name = newvalor;
else if(clave=="email")
data.email = newvalor;
else if(clave=="matricula")
data.matricula = newvalor;
else if(clave=="telefono")
data.telefono = newvalor;
// Put this updated object back into the database.
// the following line is changed so that it works.
//var requestUpdate = objectStore.put(data);
var theOtherTransactionThatIsStillAlive = event.transaction;
var objectStoreFromValidTransaction = theOtherTransactionThatIsStillAlive.objectStore('customers');
var requestUpdate = objectStoreFromValidTransaction.put(data);
requestUpdate.onerror = function(event) {
console.log("addCliente ..."+name+" "+email +" "+ event.target.errorCode);
};
requestUpdate.onsuccess = function(event) {
console.log("All done!");
};
};
}
来源:https://stackoverflow.com/questions/27709648/update-indexeddb