IndexedDB: When to close a connection - html

I would like to know what the correct place to close a connection to the database is.
Let's say that I have the following piece of code:
function addItem(dbName, versionNumber, storeName, element, callback){
var requestOpenDB = indexedDB.open(dbName, versionNumber); //IDBRequest
requestOpenDB.onsuccess = function(event){
//console.log ("requestOpenDB.onsuccess ");
var db = event.target.result;
var trans = db.transaction(storeName, "readwrite");
var store = trans.objectStore(storeName);
var requestAdd = store.add(element);
requestAdd.onsuccess = function(event) {
callback("Success");
};
requestAdd.onerror = function(event) {
callback("Error");
};
};
requestOpenDB.onerror = function(event) {
console.log ("Error:" + event.srcElement.error.message);/* handle error */
callback("Error");
};
}
addItem basically adds a new element into the database. As per my understanding, when the requestAdd event is triggered that doesn't mean necessarily that the transaction has finished. Therefore I am wondering what the best place to call db.close() is. I was closing the connection inside of requestAdd.onsucess, but if an error happens and requestAdd.onerror is triggered instead, the connection might still be opened. I am thinking about adding trans.oncomplete just under request.onerror and close the db connection here which might be a better option. Any inputs will be more than welcome. Thank you.

You may wish to explicitly close a connection if you anticipate upgrading your database schema. Here's the scenario:
A user opens your site in one tab (tab #1), and leaves it open.
You push an update to your site, which includes code to upgrade the database schema, increasing the version number.
The same user opens a second tab to your site (tab #2) and it attempts to connect to the database.
If the connection is held open by tab #1, the connection/upgrade attempt by tab #2 will be blocked. Tab #1 will see a "versionchange" event (so it could close on demand); if it doesn't close its connection then tab #2 will see a "blocked" event.
If the connection is not held open by tab #1, then tab #2 will be able to connect and upgrade. If tab #1 then tries (based on user action, etc) to open the database (with an explicit version number) it will fail since it will be using an old version number (since it still has the old code).

You generally never need to close a connection. You are not creating memory leaks or anything like that. Leaving the connection open does not result in a material performance hit.
I would suggest not worrying about it.
Also, whether you add trans.oncomplete before or after request.onerror is not important. I understand how it can be confusing, but the order in which you bind the listeners is irrelevant (qualified: from within the same function scope).

You can call db.close() immediately after creating the transaction
var trans = db.transaction(storeName, "readwrite");
db.close();
and it will close the connection only after the transaction has completed.
https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/close says
The connection is not actually closed until all transactions created using this connection are complete. No new transactions can be created for this connection once this method is called.

If you want to run multiple versions of your app and both access the same database, you might think it's possible to keep connections open to both. This is not possible. You must close the database on one before opening it on another. But one problem is that there is currently no way to know when the database actually closes.

Related

OrmLite (ServiceStack): Only use temporary db-connections (use 'using'?)

For the last 10+ years or so, I have always opened a connection the database (mysql) and kept it open, until the application closed. All queries was executed on the connection.
Now, when I see examples on Servicestack webpage, i always see the using-block being used, like:
using (var db = dbFactory.Open())
{
if (db.CreateTableIfNotExists<Poco>())
{
db.Insert(new Poco { Id = 1, Name = "Seed Data"});
}
var result = db.SingleById<Poco>(1);
result.PrintDump(); //= {Id: 1, Name:Seed Data}
}
In my current test-project, I got OrmLite to work in my normal way (one db-connection, no using-statements), so I basically had a class-wide _db, like this:
_dbFactory = new OrmLiteConnectionFactory($"Uid={dbAccount.Username};Password={dbAccount.Password};Server={dbAccount.Address};Port={dbAccount.Port};Database={dbAccount.Database}", MySqlDialect.Provider);
_db = _dbFactory.Open(); // var kept in memory, and used for all queries
It worked in the beginning, but now I suddenly got the Exception:
There is already an open DataReader associated with this Connection which must be closed first
Some code might run a SELECT here and there, and if I understand it correctly, if a SELECT and an INSERT would occur at the same time, this error appears?
If so, is it best-practice to always open a new connection for every single query (say, inside a using-statement)? Isnt that a big overhead, to do what for every query?
Having 1 DB Connection is not ThreadSafe so holding on to the connection is only an option if there’s at most 1 thread accessing the DB connection.
Most ADO.NET providers enable connection pooling by default so it’s more efficient to close the connection when you’re done with it as the connection gets returned back to the pool which reduces the number of active connections in use.

Updating just created collaborative map entries

I have a graph editor, where user has option to create a node. It gets connected with all currently selected nodes. In google document, it looks like a node (its string label) is mapped to the comma-separated set of connected labels. So, to add a node, I first create an empty map item
map.set(name, "");
and, then, separately add the connected items
if (map.get(a) == null) throw new Error("node " + a + " does not exist") // fails here
if (map.get(b) == null) throw new Error("node " + b + " does not exist")
map.set(a, a_connections)
map.set(b, b_connections)
The problem is that map.get detects that node is not added into the map yet. It takes some time. It seems that the operations are non-blocking even within single JS client (read-my-writes inconsistent). How am I supposed to work with that?
I have noticed this inconsistency when tried to establish two connections (just to detect when connections are failed because it can happen that connection is lost and all my edits do not propagate to server and I wanted to the user to know about that).
This page has some details on conflict resolution and things you can do in order to have your changes be applied together.
I'm a little confused from your example what the problem/expected behavior is.
If you do map.set("foo", "") followed by map.get("foo") on the same client from within the same synchronous block the get will always return what you set.
If you do it from different synchronous blocks, but on the same client, get will return something different only if another client made a change to the value of "foo".
If you are doing the set and get on different clients, then the value of "foo" can take an arbitrary amount of time to propagate to the other client. You should be able to register a listener to discover when it is set.
If you'd like to track when all changes have been persisted, you can listen to DocumentSaveStateChangedEvents

How to manage many openAsync() calls in a big Flex application?

I used openAsync() function many times in my application to open SQLite connection with a success. But lately I added more code that also uses openAsync() and now I obtain this error:
Error: Error #3110: Operation cannot be performed while SQLStatement.executing is true.
at Error$/throwError()
at flash.data::SQLStatement/checkReady()
at flash.data::SQLStatement/execute()
at Function/com.lang.SQL:SQLErrorStack/deleteAllRecordsFromErrorStackTable/com.lang.SQL:connOpenHandler()[C:\work\Lang\trunk\actionscript\src\com\lang\SQL\SQLErrorStack.as:466]
It looks like the previous code didn't finish executing while another has started.
My question is: Why the execution of code in the second connection was rejected? I expected that some kind of a queue mechanism is used but it isn't. I looked everywhere for a solution how to cope with this problem but I failed. Can you help?
Can one opened DB connection solve the problem? What changes to my code should I apply then?
This is the code similar to this, that appears a few times in my application.
var SQLquery:String;
SQLquery = "DELETE FROM ErrorStackTable";
var sqlConn:SQLConnection = new SQLConnection();
sqlConn.addEventListener(SQLEvent.OPEN, connOpenHandler);
var dbFile:File = new File();
dbFile.nativePath = FlexGlobals.topLevelApplication.databaseFullPath_conf+"\\"+FlexGlobals.topLevelApplication.databaseName_conf;
sqlConn.openAsync(dbFile); // openDB
sqlSelect = new SQLStatement();
sqlSelect.sqlConnection = sqlConn;
sqlSelect.text = SQLquery;
function connOpenHandler(event:SQLEvent):void
{
sqlSelect.addEventListener(SQLEvent.RESULT, resultSQLHandler);
sqlSelect.addEventListener(SQLErrorEvent.ERROR, errorHandler);
sqlSelect.execute();
}
In Big Flex Applications Try To Avoid openAsync(db) calls because of the reusablity of the SQL code , if u have many sql statments to be executed then you should define more and more sql statments . and if you have dynamic result [Array] getting from web service (RPC ) then you will surely get an error although it is successful Execution and array insertion in the database will be fail .. Just Look at
the link Click Here You Will Get your answer
I just changed conn.openAsync(db); to conn.open(db); and it worked
Thanks

How to replace chrome.tabs.onSelectionChanged deprecated method?

I need to get data from the tab the user is leaving (switching on other tab or going on other program).
But chrome.tabs seems not providing an event allowing that..
Before there was apparently chrome.tabs.onSelectionChanged (not tested) but it's deprecated.
And other event are giving the data of the new tab not the one the user just left...
I try also jQuery $(window).blur event, but i have to make a call to the chrome.storage of the tab left by the user (i create a storage for each tab named by the tab id) and i did not get the response of storage in time with this event (the result of the storage is used in a if() to know if i have or not to display an confirm box.
Someone could help me ?
Thx !
To detect a tab change, just use chrome.tabs.onActivated. Since you're interested in the previous tab, store the result of the event at the end of each event. For instance, like this:
var storedWindowInfo = {};
chrome.tabs.onActivated.addListener(function(activeInfo) {
var windowLastTabId = storedWindowInfo[activeInfo.windowId];
if (windowLastTabId) {
// Do something with previous tab, e.g. send a message:
chrome.tabs.sendMessage(windowLastTabId);
}
// Update ID of currently active tab in the current window
storedWindowInfo[activeInfo.windowId] = activeInfo.tabId;
});
Note: Only the tabID and windowID are provided to this event. You need to issue chrome.tabs.query to get more information, such as whether the tab still exists, its URL, etc.

Titanium: How to reload a tab upon focus?

I have built a favorite-tab in my application that displays entries in a database that are flagged as such. On the backside this works as it should, but I can't figure out how to reload the favorites tab after changes have been made. When I quit and relaunch the app though, the updates appear as they should.
In essence I have the same problem as is presented here: http://developer.appcelerator.com/question/31211/tab---tableview--database-reload
"I have a 'search' and 'search history' tab in my application. Every search executed under this tab gets inserted into my local db.
However the new search is not reflected in the tableview retrieving data from the DB in the 'search history' tab when i browse to it, after searching.
The latest search, however, gets loaded when I exit the app and relaunch it.
I need some help in figuring out how to trigger the tableview reload without exiting the app.
SOLUTION UPDATE:
I feel 'noobish' for asking this question but it was really so simple
I added a 'focus' eventlistener for the window housing the tab to load the data.
win.addEventListener('focus', function() { loadDBdata(); });
This seems reasonable, but what should the loadDBdata function should contain?
I would greatly appreciate any pointers to this.
i would suggest firing an event when the favorites are updated and having an event listenter on the table that holds the favorites list. When it receives the event, it should update the tables contents.
see this question I just answered it should provide a guide for solving your problem also
Problems with refresh function for page, in Appcelerator
the loaddb function should contain something like:
// init database
var db = Ti.Database.install('path/to/database.db','myDB');
// your request
var sql = 'SELECT * FROM myDatabaseTable';
// the result from that request
var myContent = db.execute(sql);
// need to put the result in a valid structure before inserting into your tableview
var data = [];
while (myContent.isValidRow()){
// your tableviewrow
var row = {
title = myContent.field(0);
};
data.push(row);
myContent.next();
};
// need to close stuff (!)
myContent.close();
db.close();
// finally return data
return data;