Android SQLite DB, когда закрывать - PullRequest
93 голосов
/ 29 декабря 2010

Я работаю с базой данных SQLite на Android.Мой менеджер баз данных является одноэлементным и прямо сейчас открывает соединение с базой данных, когда она инициализируется.Безопасно ли оставлять базу данных открытой все время, чтобы, когда кто-то вызывал мой класс для работы с базой данных, она уже была открыта?Или я должен открыть и закрыть базу данных до и после каждого доступа необходим.Есть ли вред, если вы просто оставляете его открытым все время?

Спасибо!

Ответы [ 7 ]

60 голосов
/ 29 декабря 2010

я бы оставил его открытым все время и закрыл бы его каким-нибудь методом жизненного цикла, таким как onStop или onDestroy. таким образом, вы можете легко проверить, используется ли база данных, вызывая isDbLockedByCurrentThread или isDbLockedByOtherThreads для одного SQLiteDatabase объекта каждый раз перед его использованием. это предотвратит множественные манипуляции с базой данных и спасет ваше приложение от потенциального сбоя

так что в вашем синглтоне у вас может быть такой метод для получения вашего единственного SQLiteOpenHelper объекта:

private SQLiteDatabase db;
private MyDBOpenHelper mySingletonHelperField;
public MyDBOpenHelper getDbHelper() {
    db = mySingletonHelperField.getDatabase();//returns the already created database object in my MyDBOpenHelper class(which extends `SQLiteOpenHelper`)
    while(db.isDbLockedByCurrentThread() || db.isDbLockedByOtherThreads()) {
        //db is locked, keep looping
    }
    return mySingletonHelperField;
}

поэтому всякий раз, когда вы хотите использовать свой открытый вспомогательный объект, вызывайте этот метод getter (убедитесь, что он потоковый)

другим методом в вашем синглтоне может быть (КАЖДЫЙ РАЗ, прежде чем пытаться вызвать вызывающий метод выше):

public void setDbHelper(MyDBOpenHelper mySingletonHelperField) {
    if(null == this.mySingletonHelperField) {
        this.mySingletonHelperField = mySingletonHelperField;
        this.mySingletonHelperField.setDb(this.mySingletonHelperField.getWritableDatabase());//creates and sets the database object in the MyDBOpenHelper class
    }
}

Вы также можете закрыть базу данных в синглтоне:

public void finalize() throws Throwable {
    if(null != mySingletonHelperField)
        mySingletonHelperField.close();
    if(null != db)
        db.close();
    super.finalize();
}

если пользователи вашего приложения имеют возможность очень быстро создавать множество взаимодействий с базой данных, вам следует использовать что-то, как я продемонстрировал выше. но если взаимодействие с базой данных минимально, я бы об этом не беспокоился, а просто каждый раз создавал и закрывал базу данных.

20 голосов
/ 26 марта 2015

На данный момент нет необходимости проверять, заблокирована ли база данных другим потоком. Пока вы используете одиночный SQLiteOpenHelper в каждом потоке, вы в безопасности. Из isDbLockedByCurrentThread документации:

Название этого метода происходит от времени, когда активный подключение к базе данных означало, что поток содержал фактический заблокировать базу данных. В настоящее время больше нет настоящей базы данных заблокировать ", хотя потоки могут блокировать, если они не могут получить базу данных подключение для выполнения определенной операции.

isDbLockedByOtherThreads устарело с уровня API 16.

12 голосов
/ 26 февраля 2016

По вопросам:

Мой менеджер баз данных является одноэлементным и сейчас открывает соединение с базой данных, когда она инициализируется.

Мы должны разделить «открытие БД», «открытие соединения». SQLiteOpenHelper.getWritableDatabase () дает открытую БД. Но нам не нужно контролировать соединения, как это делается внутри.

Безопасно ли оставлять базу данных открытой все время, чтобы, когда кто-то вызывал мой класс для работы с базой данных, он уже был открыт?

Да, это так. Соединения не зависают, если транзакции правильно закрыты. Обратите внимание, что ваша БД также будет автоматически закрыта, если GC завершит ее.

Или я должен открыть и закрыть базу данных до и после каждого необходимого доступа.

Закрытие экземпляра SQLiteDatabase ничего не дает, кроме закрытия соединений, но это плохо для разработчика, если в данный момент есть некоторые соединения. Кроме того, после SQLiteDatabase.close () SQLiteOpenHelper.getWritableDatabase () вернет новый экземпляр.

Есть ли вред, если вы просто оставляете его открытым все время?

Нет, нет. Отметим также, что закрытие БД в несвязанный момент и поток, например, в Activity.onStop () может закрывать активные соединения и оставлять данные в несогласованном состоянии.

1 голос
/ 22 февраля 2018

С точки зрения производительности оптимальный способ - сохранить один экземпляр SQLiteOpenHelper на уровне приложения.Открытие базы данных может быть дорогим и является блокирующей операцией, поэтому его не следует делать в основном потоке и / или в методах жизненного цикла действия.

setIdleConnectionTimeout () метод (введен вAndroid 8.1) можно использовать для освобождения оперативной памяти, когда база данных не используется.Если время простоя установлено, соединения с базой данных будут закрыты после периода бездействия, то есть, когда к базе данных не было доступа.Соединения будут снова открыто открыты для приложения, когда будет выполнен новый запрос.

Кроме того, приложение может вызывать releaseMemory () , когда оно переходит в фоновый режим или обнаруживает памятьдавление, например, в onTrimMemory ()

1 голос
/ 15 января 2018

Android 8.1 имеет метод SQLiteOpenHelper.setIdleConnectionTimeout(long), который:

Устанавливает максимальное количество миллисекунд, в течение которых соединение SQLite может бездействовать, прежде чем оно будет закрыто и удалено из пула.

https://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#setIdleConnectionTimeout(long)

0 голосов
/ 20 декабря 2014

Вы также можете использовать ContentProvider.Он сделает это за вас.

0 голосов
/ 11 декабря 2012

Создайте свой собственный контекст приложения, затем откройте и закройте базу данных оттуда. Этот объект также имеет метод OnTerminate (), который вы можете использовать для закрытия соединения. Я еще не пробовал, но, похоже, лучше.

@ binnyb: мне не нравится использовать finalize () для закрытия соединения. Может сработать, но, насколько я понимаю, написание кода в методе finalize () на Java - плохая идея.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...