SQLite одновременное чтение и запись - PullRequest
24 голосов
/ 12 ноября 2011

Я прочитал много тем, но не могу найти ответ на вопрос: можно ли читать и писать одновременно?

У меня есть фоновый поток, который обновляет некоторые данные, и пользовательскому интерфейсу требуется небольшой фрагмент данных, хранящийся в БД. Так в потоке пользовательского интерфейса операция SELECT выполняется. Но он блокируется, когда идет обновление. В результате пользовательский интерфейс зависает на несколько секунд.

У кого-нибудь есть успех при чтении из БД при записи?


Его можно читать и записывать в БД на iPhone. Причиной такой разницы является синхронная реализация оболочки на нативных функциях sqlite?

Ответы [ 4 ]

56 голосов
/ 25 апреля 2013

В Android 3.0 и выше базы данных SQLiteDatabase поддерживают режим WAL (ведение журнала с предварительной записью):

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

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

http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#enableWriteAheadLogging()

Чтобы запустить транзакцию в режиме WAL, используйте beginTransactionNonExclusive () вместоBeginTransaction ().Пока beginTransaction () запускает транзакцию в режиме EXCLUSIVE, beginTransactionNonExclusive () запускает транзакцию в режиме IMMEDIATE

  • В режиме EXCLUSIVE используются эксклюзивные блокировки (http://www.sqlite.org/lockingv3.html#excl_lock), что означает, что никакое другое соединение с базой данных, кроме соединений read_uncommitted, не будетбыть в состоянии прочитать базу данных, и никакое другое соединение без исключения не сможет записать базу данных, пока транзакция не будет завершена
  • Режим IMMEDIATE использует зарезервированные блокировки (http://www.sqlite.org/lockingv3.html#reserved_lock) означает, что никакое другое соединение с базой данных не сможетчтобы записать в базу данных или выполнить BEGIN IMMEDIATE или BEGIN EXCLUSIVE, другие процессы могут продолжить чтение из базы данных, однако.

Проще говоря: вызовите beginTransactionNonExclusive () для режима IMMEDIATE, и мы можем прочитатьв то время как другой поток пишет (состояние до начала транзакции записи, потому что мы не будем использовать соединения read_uncommitted -> http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Dirty_reads).

3 голосов
/ 03 октября 2016

Начиная с API 11 Android поддерживает режим WAL. Он сохраняет исходные данные без изменений во время транзакции, поэтому другие потоки могут читать, когда транзакция выполняется. Вы можете проверить мою статью для более подробной информации о режиме WAL:

http://www.skoumal.net/en/parallel-read-and-write-in-sqlite/

Вам также следует избегать выполнения запросов к базе данных в потоке пользовательского интерфейса. Это всегда может стать вялым и заблокировать ваш пользовательский интерфейс.

3 голосов
/ 12 ноября 2011

Вы не можете читать и писать одновременно. SQLite - это серверная база данных на основе файлов.

Из FAQ по SQLite:

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

1 голос
/ 12 ноября 2011

Невозможно одновременно читать и писать. Однако, если у вас правильно настроены классы баз данных SQLite (один экземпляр ваших классов DB и helper), разные потоки должны иметь возможность синхронно захватывать соединение с БД, чтобы не было заметных задержек.

Звучит так, будто вы пытаетесь выполнить бэкэнд-работу (запись в БД) с помощью потока пользовательского интерфейса. Вы не должны делать это. Создайте AsyncTask для обработки этого, вместо того чтобы ваш поток пользовательского интерфейса обрабатывал его.

См. Документацию SQLiteOpenHelper . Вот предыдущий пост, в котором также говорится об этом: Каковы лучшие практики для SQLite на Android?

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