0

Is there any advantage in keeping a local sqlite connection open the entire time that the activity is running?

I usually create a new connection and then close it within every method that does a database operation. It would look something like this :

myMethod(Context context){
    LocalDBHelper localDBHelper = new LocalDBHelper(context); //extended SQLiteOpenHelper 
    SQLiteDatabase db = localDBHelper.getWritableDatabase();
    ...
    localDBHelper.close();
}

So in a typical user session, this would happen around 10 times. Would it make sense to create a connection in onResume(), use that in all the database access methods and finally close it in onPause()?

faizal
  • 3,497
  • 7
  • 37
  • 62

4 Answers4

2

Is there any advantage in keeping a local sqlite connection open the entire time that the activity is running?

You usually want one "connection" for the entire life of your process. In particular, you do not want to have multiple "connections" in use simultaneously across multiple threads. All of the thread-safety logic for SQLite in Android is based around using a single SQLiteDatabase (and, hence, single SQLiteOpenHelper) for all of those threads, so proper locking can be done.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • That makes sense. But how would i initialize SQLiteDatabase at the process level? I usually do it in my fragment/activity or DAO methods. Do i extend the `Application` class and do it in it's constructor? – faizal Oct 09 '14 at 11:22
  • I am not so sure it is a good idea because Logcat always throws errors/warnings when i start an activity from another activity that has an open `SQLiteDatabase` instance. So creating a process level `SQLiteDatabase` that is open throughout the process life would result in the same errors. – faizal Oct 09 '14 at 11:29
  • 2
    @faizal: "But how would i initialize SQLiteDatabase at the process level?" -- lazy-initialize a singleton. "So creating a process level SQLiteDatabase that is open throughout the process life would result in the same errors" -- I have not seen that. – CommonsWare Oct 09 '14 at 11:31
  • Here is warning message from my app : `A SQLiteConnection object for database xyz was leaked! Please fix your application to end transactions in progress properly and to close the database when it is no longer needed.` That' what i usually get if i don't close the DB before starting another activity. – faizal Oct 09 '14 at 11:34
  • 1
    @faizal: You are welcome to ignore that message. Or, you are welcome to try what I suggest and see whether you continue to get that message. Or, you are welcome to roll your own thread synchronization mechanism, plus incur the overhead of opening and closing the database constantly. – CommonsWare Oct 09 '14 at 11:39
  • A Singleton `SQliteOpenHelper` would imply the possibility of a corrupted state. If a service tries to reads data, while a transaction is updating it, it would be reading uncommitted data. Even if the transaction does not get rolled back, the service would still have read partially updated data. Data isolation is a problem with this pattern. – faizal Nov 04 '14 at 09:54
  • 2
    @faizal: "If a service tries to reads data, while a transaction is updating it, it would be reading uncommitted data" -- no, it would not, as that is not how a transaction works in databases. – CommonsWare Nov 04 '14 at 10:27
  • SQLite provides isolation between operations in separate database connections. However, there is no isolation between operations that occur within the same database connection. In other words, if X begins a write transaction using BEGIN IMMEDIATE then issues one or more UPDATE, DELETE, and/or INSERT statements, then those changes are visible to subsequent SELECT statements that are evaluated in database connection X. ref - sqlite.org/isolation.html. – faizal Nov 04 '14 at 10:40
  • 2
    @faizal: "However, there is no isolation between operations that occur within the same database connection" -- that is provided by `SQLiteDatabase`. "if X begins a write transaction using BEGIN IMMEDIATE" -- then do not use `BEGIN IMMEDIATE` (which translates to the non-exclusive versions of `beginTransaction()` on `SQLiteDatabase`) unless you know that you have the only running thread. – CommonsWare Nov 04 '14 at 10:46
  • you are right. i have written an answer with a little more detail http://stackoverflow.com/a/26735566/2105986 – faizal Nov 04 '14 at 12:55
  • @CommonsWare are you familiar with how keeping a connection open in the main app and keeping one in another process e.g. ":sync" would interact? I'm sure you know objects in separate processes do not share state so they will not share the same connection/helper even though they will share the same DB. – whizzle Jan 03 '15 at 02:10
  • 1
    @whizzle: I avoid multi-process Android apps at all costs. That being said, AFAIK, it will work as SQLite does in other environments (e.g., Rails), using OS file-level locking for isolation. – CommonsWare Jan 03 '15 at 12:11
2

Based on @CommonsWare answer, i have implemented a Singleton pattern to have a single application wide instance of LocalDBHelper using lazy instantiation. It works fine till now and avoids the need to instantiate and close the helper/database for every operation.

public class MyApplication extends Application{
    private static MyApplication instance;
    public MyApplication(){
        instance = this;
    }
    public static Context getContext(){
        return instance;
    }
}

public class LocalDBHelper extends SQLiteOpenHelper{
    private static final int DATABASE_VERSION = 1;
    private static final String DATABASE_NAME = "MyDB";
    private static final String LOG_TAG = "LocalDBHelper";

    private static LocalDBHelper instance = null;
    /*private constructor to avoid direct instantiation by other classes*/
    private LocalDBHelper(){
        super(MyApplication.getContext(), DATABASE_NAME, null, DATABASE_VERSION);
    }
    /*synchronized method to ensure only 1 instance of LocalDBHelper exists*/
    public static synchronized LocalDBHelper getInstance(){
        if(instance == null){
            instance = new LocalDBHelper();
        }
        return instance;
    }
    ...
    ...
}

Usage :

SQLiteDatabase db = LocalDBHelper.getInstance().getWritableDatabase();
db.insert(...)

Usage with transactions :

SQLiteDatabase db = LocalDBHelper.getInstance().getWritableDatabase();
db.beginTransaction();
try{
....
...
db.setTransactionSuccessful();
}catch(Exception e){
    e.printStackTrace();
}
finally{
    db.endTransaction();

}

Important : No need to call localDBHelper.getInstance().close() anywhere

faizal
  • 3,497
  • 7
  • 37
  • 62
1

As your app works on the same machine every time it is luanched and the same memory is accessed every time, so there will be no problem to let it be open. because in the same memory space , sqlite just loads like a DLL for a main application.

Just one problem may occur! when you wanna run many threads for accessing database at the same time(for example with AsyncTask) the interference between them forces some threads to stop! so its better to make connection for new threads eachtime!

Peyman.H
  • 1,819
  • 1
  • 16
  • 26
  • that's interesting. do you think opening a SQLite connection is a resource/time heavy operation in Android? – faizal Oct 09 '14 at 10:41
  • @faizal As i know so far , the OS has some buffers for each client connection. so it takes time for allocating and deallocating these buffers. – Peyman.H Oct 09 '14 at 10:46
0

Personally I find it easier to call the SQL Connections required on the initial app load, to store into the SQLite DB's, and either set a refresh button for the user to decide when they want to refresh the data, OR set a periodic update interval timer for the application.

By doing it this way, you are increasing performance during general usage of the app by placing the data load on a pre/user defined time.

Although I do suppose this depends on how often a DB Interaction is going to be performed....

This Question may ahve some useful answers for you:

Should I open() and close() my SQL database constantly or leave it open?

Community
  • 1
  • 1
  • Sorry i realized my question was misleading and so i have changed it to make it more clear. If there is no remote SQL access involved in the app, does it make sense to create a long standing local SQLite connection? – faizal Oct 09 '14 at 10:24
  • Well, if there is no remote SQL access I wouldn't think it would be an issue, but if the application tries to run any functions on the database while it is open in a previous activity it may kick off an error or two. – Jay Paleschi Oct 09 '14 at 10:27
  • Some answers here may be of use to you :) http://stackoverflow.com/questions/6339545/should-i-open-and-close-my-sql-database-constantly-or-leave-it-open – Jay Paleschi Oct 09 '14 at 10:28
  • I don't think it would be a problem across activities because i would be closing the connection in `onPause()`. – faizal Oct 09 '14 at 10:37
  • Ah I see... to be honest I can't see any issues then, but maybe another user might have some insight i'm not aware of :) – Jay Paleschi Oct 09 '14 at 10:40