I'm working with SQLite in my android project. There is a feature that is clear to me -- if there are multiple threads working with DB then they should use only ONE instance of DBHelper and SQLite guarantee a safe access (even if it is concurrent) to the DB.
But I still have one thing needed to be clarified. How should I manage with DB connection (SQLiteDatabase object)? How often should I call geWritableDatabase() and close()? Is it ok if I call these methods once? Or it's better to obtain SQLDatabase object and close one every time I perform read/write operation on DB?
It is handled by default... I mean if a writtable database open, whenever you try to access read-only database it closes writtable one and create new read-only database instance. As far as i know :)
Related
I am working on a chat application and in chat we are getting lots of update from server. And we are also saving the updates into the local SQLite database file.
Can someone suggest me, after every single insertion/update, should we close the database or we should close the database when it is actually needed ?
Closing the connection throws away the page cache, and requires that the schema version is checked and the entire schema is re-parsed the next time it is opened.
In most apps, there are not enough database accesses so that the overhead of continually re-opening the database would actually become noticeable. But this is no reason to add useless code to your app.
Please note that the SQLiteDatabase object is reference counted. So if you are using a global open helper instance, you can keep the DB open with an extra getWritableDatabase() call, even when all your other code calls close().
You should close the connection after each query.
In .net (and in most other frameworks), SQLConnections are stored in the background anyway. It won´t hit your runtime.
Also: connection pooling is your friend.
Ive done a lot of Googlig on this topic and I'm confused as to best practice.
Initially I had:
A) Created a DataBase object in my main class header area and then just passed it to functions as needed. I then later read that a DataBase should be opened and closed each time before use.
so then I:
B) went to each function (passing Context) which uses a SQL command and created a new DataBase object, created a filled cursor via SQL, and then closed the Database before returning. However, I then later read that it's expensive to do this.
now i'm thinking that:
C) I should create a new Database object in each subclass that uses one, and open and close it as needed.
Im sorry for the noob and seemingly design question (delete it if it's out of scope of StackOverflow), however, I truly am confused of how this should be handled to avoid errors, and how Google wants us to do it.
Regards
The Android docs recommend using an SQLiteOpenHelper, which caches the database object. From the SQLiteOpenHelper reference:
Once opened successfully, the database is cached, so you can call this
method every time you need to write to the database. (Make sure to
call close() when you no longer need the database.)
So, I'd go for a singleton carrying an instance of SQLiteOpenHelper, so you can access it from anywhere. Then get the database where you need it, and close it on exit points of your application (if any). That way you only open a database if required, but can re-use the same connection for other tasks as well.
If you do only need the database for single tasks and/or there are other Applications accessing the same database, you may consider closing it directly after your database-tasks are done; there is a discussion about closing in another question.
I've been reading, browsing, searching a lot on this, I've criss-crossed stackoverflow back and forth many times and I managed to narrow my problem as much as I could.
The only thing I do not understand, is how to fully use an in-memory SQLite database.
Here is my situation - I have an encrypted SQLite database which I decrypt during the loading of my application (this part works for sure). My class that interacts with the database works for sure with a plain database.
So to make it short, everything is flawless with a plain DB which gets loaded from the internal phone memory, but I am not sure how or where to store the decrypted DB in memory so it would get interpreted as normal DB.
I guess I should put null instead of a name in super(context, null, null, 3); and use :memory: instead of a path in SQLiteDatabase.openDatabase(), but I still don't understand fully. It says it cannot find an android_metadata table, but I am certain the database is as it should be.
Hope I was clear on this :)
SQLiteOpenHelper() will create an in-memory database if the name is null. Note that it will be created when you invoke getWritableDatabase().
Then you should insert your data.
You (or the framework) create a database using ONE of the following:
SQLiteDatabase.create()
SQLiteDatabase.openDatabase()
SQLiteDatabase.openOrCreateDatabase()
The first option is the only way to create a memory-only database, the other two open or create a database file.
Consequently, if you are using SQLiteOpenHelper() and you pass name as null, the framework calls SQLiteDatabase.create(null), so you will get a database that only lives in memory (it dies when close() is called). There is no need to also call one of the other direct methods. Instead call getReadableDatabase() or getWritableDatabase() from your helper.
You have to be carefull wile using inmemory as your data will be lost once the db connection is lost. Make sure your db instance is not been closed
https://www.sqlite.org/inmemorydb.html
I have a SQLite Database in android that is accessed from a thread when the activity is running, and in the onPause() of the activity a new thread is created to save everything into the database with a different thread to avoid timeout issues. However, when I try to do so, I either get database is locked errors. How can I fix this? Since I need to access the database from a separate thread in onPause(), could I delete somehow my previous access to it since I wouldn't use it again?
You cannot access an SQLite database when it already has a lock on it.
To avoid this, Android gives you ContentProviders to handle this sort of thing.
You should implement your own ContentProvider to do this kind of thing.
That said, databases can NEVER be assumed to be threadsafe unless you manage the threads yourself. Avoid using the db like this. Instead, cache the data (on a stack, perhaps) and request access to the database with a callback when your current transaction is complete.
As far as I know SQLite does not support concurrent access, so you either have to have a dedicated thread to provide access, or you have to obtain a lock to the SQLite object instance.
We all learn that resources, such as database connections, should be acquired late and released early.
Yet applying this principle to SQLite database connections on Android have caused me some headache.
I have an app that download updates from a backend server in a service working in the background, writing updates to the database at a regular basis. The problem I experience arise when the following sequence occurs:
Service opens a writable database connection
Some activity opens a readable database connection
Service closes its database connection concurrently with the activity reading data
Activity fails due to its database connection was closed
Both the service and the activity uses the same SQLiteOpenHelper class, though different instances, to open their connections. My initial assumption was that this should work just fine, but somehow it seems that the underlying connection is shared between the two database instances.
To work around the problem I ended up not closing the database objects, only closing any opened cursors. This seems to work, though I'm not sure that I'm not leaking memory here.
Is there something obvious I am missing here?
Is there something obvious I am missing here?
I'd say no. Looking at the source code to SQLiteOpenHelper, I can't see how two instances could be sharing a SQLiteDatabase object.
Some diagnostic suggestions:
Dump the toString() value of each SQLiteDatabase, which should give you a Java instance ID. If they are the same, that is where your problem lies, and you will need to work your way upstream to figure out how the heck this is happening (e.g., you really are using the same instance of the SQLiteOpenHelper).
With your database in a stable state (i.e., no need to create or upgrade), flip one of your two database spots to use SQLiteDatabase directly, rather than via SQLiteOpenHelper, and see if that changes matters.