Является ли SQLite потокобезопасным?

«Является ли SQLite потокобезопасным?» — вопрос из категории Базы данных, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

SQLite является потокобезопасным, но с критически важными условиями.

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

Основное правило: *Одно соединение с базой (`sqlite3`) должно использоваться только в одном потоке за раз.** Нельзя передавать соединение между потоками.

Правильный паттерн использования:

  1. Каждый поток, которому нужен доступ к базе, должен открывать свое собственное соединение.
  2. Каждое соединение работает независимо.

Пример (с использованием библиотеки GRDB.swift):

// Создаем очередь для базы данных, которая управляет соединением.
let dbQueue = try DatabaseQueue(path: "/path/to/database.sqlite")

// Запись из одного потока
DispatchQueue.global().async {
    try! dbQueue.write { db in
        try db.execute(sql: "INSERT INTO users (name) VALUES (?)", arguments: ["Alice"])
    }
}

// Чтение из другого потока
DispatchQueue.global().async {
    try! dbQueue.read { db in
        let names = try String.fetchAll(db, sql: "SELECT name FROM users")
        print(names)
    }
}

Что может пойти не так?

  • Разделение одного соединения между потоками: Приведет к неопределенному поведению и крашам.
  • Блокировки: Длинные транзакции в одном соединении могут блокировать запись для других соединений.

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