10
So I’m facing some problems with my Sqlite connection, where I’m not finding a skilled solution.
Setting
My scenario is this::
- I synchronize the data of my application with a legacy system, through a Webservice;
- This synchronization is done through a Thread that checks what’s new in the legacy database and starts several other Threads to get the data and save it in its local base (Sqlite);
- For each entity that is found new data in the legacy database a new Thread is opened, (each entity has an Endpoint, where it is accessed, downloaded, and saved the data, and then finalized the Thread). Ex: if there are new clients in the legacy database, a request is started that will fetch all new clients, and saves them in my client table in Sqlite, this would run in a Thread;
Problem
The problem is that even if I use AsyncTask.SERIAL_EXECUTOR that only runs one Thread at a time, between an opening and another connection ends up generating problem Lock, where I cannot get the Current reference of the connection and when trying to create a new one it accuses that db is Locked.
I believe my problem is not even with threads running simultaneously, but in my class connection management, which I am currently using is:
public abstract class GConexaoAdapter {
private final DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
protected final Context ctx;
public GConexaoAdapter(Context ctx, String dbName, int dbVersion) {
this.mDbHelper = new DatabaseHelper(ctx, dbName, dbVersion);
this.ctx = ctx;
}
private void open() {
try {
synchronized (ctx) {
synchronized (mDbHelper) {
if (mDb == null) {
mDb = mDbHelper.getWritableDatabase();
} else {
synchronized (mDb) {
mDb = mDbHelper.getWritableDatabase();
}
}
}
}
} catch (IllegalStateException e) {
e.printStackTrace();
if (mDb == null || !mDb.isOpen())
mDb = ctx.openOrCreateDatabase(mDbHelper.getDatabaseName(), 0,
null);
Log.i("TRATAR", "tratar");
}
}
protected SQLiteDatabase getConexao() {
synchronized (ctx) {
synchronized (mDbHelper) {
if (mDb == null) {
this.open();
} else if (!mDb.isOpen()) {
synchronized (mDb) {
if (!mDb.isOpen()) {
this.open();
}
}
}
return mDb;
}
}
}
protected void closeConexao() {
synchronized (ctx) {
synchronized (mDbHelper) {
if (mDb != null && mDb.isOpen()) {
synchronized (mDb) {
if (mDb.isOpen()) {
if (mDb.inTransaction()) {
mDb.endTransaction();
}
mDb.close();
}
}
}
}
}
}
private static class DatabaseHelper extends SQLiteOpenHelper {
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
if (!db.isReadOnly()) {
// db.execSQL("PRAGMA foreign_keys=ON;");
}
}
DatabaseHelper(Context context, String dbNome, int dbVersion) {
super(context, dbNome, null, dbVersion);
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
}
I don’t think I need all the synchronized that I have, is that I have tried several solutions I have found and none brought me the expected result.
Question?
I believe there’s even a "Cake recipe" for this type of connection management. I may not be the only one who needs a solution like this.
So how would I manage to effectively, effectively manage my connection to the Sqlite database?
Very important remark:
I would like to manage the Sqlite connection between multiple simultaneous threads, however without causing Locks that end up generating exceptions and violating data integrity!
I understood your suggestion, and it seems useful, but connection management should not be restricted to threads but to any connection call. I believe I could control the connection by keeping a single instance in the object Gconexaoadapter, I’m just looking for a way to do it well. I’m working in that idea
– Fernando Leal
In any access to the bank you will have to use the
synchronized()to avoid competing calls togetWritableDatabase(). You can’t do it any other way. The only alternative would be to create methodsinsert(),delete(), etc. in theGConexaoAdapter, all of themsynchronized, and within each you callgetWritableDatabase()before executing the operation itself, andclose()next.– Piovezan
"to avoid competing calls to getWritableDatabase()" - read "to ensure the atomic operation composed of
mDb = mDbHelper.getWritableDatabase()andmDb.close()"– Piovezan
your answer helped me find the path of stones, check out my solution.
– Fernando Leal