Room vs SQLite: как одна библиотека избавила меня от головной боли с базами данных
Введение
Когда я только начинал писать под Android, сохранение данных на телефоне казалось простой задачей. Берёшь SQLite, пишешь пару запросов и готово. Но чем больше становилось приложение, тем сильнее я ненавидел ручную работу с базами данных. Каждый раз писать execSQL, потом закрывать Cursor, не забыть db.close()… А если опечататься в названии колонки — приложение падает уже у пользователя, а не у тебя в студии.
Я пробовал терпеть, но в какой-то момент понял, что так нельзя. И тогда я нашёл Room. Это библиотека от Google, которая работает поверх SQLite.
В этой статье я покажу на реальных примерах кода, как выглядит работа с SQLite «вручную» и как тот же самый функционал пишется на Room. (Небольшой спойлер: разница как между велосипедом и автомобилем).
Основная часть
2. Что такое ORM и как Room решает проблемы
ORM (объектно-реляционное отображение) — это подход, при котором таблицы базы данных превращаются в обычные классы, а строки — в объекты. Вместо того чтобы писать INSERT INTO users ..., вы просто создаёте объект и вызываете insert(user). Библиотека сама генерирует нужный SQL.
Room — это официальная ORM-библиотека от Google. Она берёт на себя управление соединениями, генерацию запросов и проверки.
Room состоит из трёх основных частей:
- Entity — класс, который описывает таблицу. Каждое поле класса становится колонкой (Вы просто ставите аннотацию @Entity)
- DAO (Data Access Object) — интерфейс, в котором вы объявляете методы для работы с данными: insert, update, delete, getAll. (Room автоматически пишет их реализацию)
- Database — абстрактный класс, наследник RoomDatabase. Он связывает Entity и DAO и даёт доступ к БД
Главные плюсы Room:
- Проверка SQL на этапе компиляции. Если вы ошиблись в имени таблицы или колонки, приложение даже не соберётся
- Никакого ручного закрытия Cursor или SQLiteDatabase — Room управляет ресурсами сам
- Минимум кода. Не нужно писать шаблонные CREATE TABLE и разбирать Cursor по индексам
- Методы DAO можно сделать suspend, и Room выполнит запрос в фоновом потоке, не блокируя интерфейс
3. Тот же пример на Room
Теперь покажу, как добавить пользователя, найти всех взрослых (возраст > 18), а также попробуем обновить возраст и удалить запись. Всё то же самое, что мы делали на чистом SQLite, но с Room.
Шаг 1. Сущность User
Создаём обычный data-класс и добавляем аннотацию @Entity (Room сам создаст таблицу с нужными колонками)
Никакого CREATE TABLE. Room сам создаст таблицу с колонками id, name, age.
Шаг 2. DAO (интерфейс для работы с данными)
Объявим интерфейс с аннотированными методами (Реализацию Room сгенерирует сам).
Методы с аннотациями @Insert, @Update, @Delete позволяют не писать SQL вручную — Room делает это сам. Для сложной выборки (запросов) — @Query.
В ответ получаем List<User> (Cursor больше не нужен).
Шаг 3. База данных (синглтон)
Создаём класс, который будет представлять всю базу данных. Он должен быть абстрактным и наследоваться от RoomDatabase. Указываем, какие таблицы в нём будут (в нашем случае — User), и версию базы (пока первая). Внутри объявляем абстрактный метод, который будет возвращать наш DAO — через него мы и будем обращаться к данным.
Это стандартный шаблон, который можно скопировать один раз и забыть.
Шаг 4. Использование в коде (Activity или Fragment)
А вот как выглядит та же логика, когда используешь Room:
Обратите внимание:
Нет close() — Room сам закрывает соединения.
- Нет возни с индексами колонок — результат сразу в виде списка объектов.
- suspend-функции позволяют выполнять запросы в фоновом потоке, не блокируя интерфейс.
- В методе findByName параметр :name автоматически экранируется — SQL-инъекции исключены.
Для наглядности — схематичное сравнение двух подходов:
Заключение
Мы сравнили два подхода к работе с SQLite на Android: ручной через SQLiteOpenHelper и современный Room. Room заметно сокращает количество кода, убирает рутину с закрытием курсоров и находит ошибки в запросах ещё на этапе компиляции. Для новых проектов я однозначно рекомендую Room — он делает работу с БД простой и понятной. SQLite я использую только в особых случаях, например, когда нужно подключить готовую базу со сложной структурой. В остальном берите Room и не мучайтесь)