Восстановление SQLite через Deserialize в Go: пошаговое руководство
При работе с SQLite в Go разработчики часто сталкиваются с ситуацией, когда метод Deserialize не восстанавливает базу данных из среза байт, хотя сохранение в файл и последующее восстановление через NewRestore работают корректно. Это происходит из-за особенностей внутреннего состояния соединения и неправильного использования API. В этой статье разберём, как правильно выполнить десериализацию SQLite без обращения к файловой системе.
Почему Deserialize не работает?
Ключевая проблема в исходном коде - вызов Deserialize на уже открытом соединении dw.DB. По документации modernc.org/sqlite, метод Deserialize предназначен для замены содержимого базы данных в памяти, но он требует, чтобы соединение было создано с нуля, либо чтобы база была пустой. При вызове на активном соединении с существующими данными операция может игнорироваться или завершаться ошибкой.
Дополнительно, использование conn.Raw с передачей driverConn не гарантирует, что внутреннее состояние SQLite будет корректно сброшено. В результате Deserialize не применяется, и база остаётся в прежнем виде.
Правильный способ: создание нового соединения
Чтобы восстановить базу через Deserialize, необходимо открыть новое соединение к базе в памяти и сразу применить десериализацию. Вот рабочий пример:
func (dw *databaseWrapper) restoreBackup(ctx context.Context, data []byte) error {
// Создаём новое in-memory соединение
db, err := sql.Open("sqlite", ":memory:")
if err != nil {
return err
}
defer db.Close()
conn, err := db.Conn(ctx)
if err != nil {
return err
}
defer conn.Close()
err = conn.Raw(func(driverConn any) error {
return driverConn.(sqliteBackuper).Deserialize(data)
})
if err != nil {
return err
}
// Заменяем текущее соединение на новое
dw.DB.Close()
dw.DB = db
return nil
}Здесь мы создаём отдельную in-memory базу, десериализуем в неё данные и затем заменяем исходное соединение. Это гарантирует, что Deserialize применится к пустой базе.
Альтернатива: сброс и повторное открытие
Если вы не хотите создавать новое соединение, можно закрыть текущее и открыть заново с использованием sql.Open с тем же источником данных. Однако для in-memory баз этот подход не подходит, так как данные теряются. Поэтому рекомендуется первый вариант.
Проверка результата
После десериализации убедитесь, что данные корректно загружены. Выполните простой запрос, например, SELECT count(*) FROM sqlite_master. Если таблицы присутствуют - восстановление прошло успешно.
Распространённые ошибки
- Использование Deserialize на уже заполненной базе - данные не перезаписываются, метод игнорируется.
- Игнорирование ошибки возврата - Deserialize может вернуть ошибку, которую нужно обработать.
- Работа с закрытым соединением - убедитесь, что соединение открыто до вызова Raw.
Заключение
Метод Deserialize в modernc.org/sqlite - мощный инструмент для быстрого восстановления базы из памяти. Главное правило: применяйте его только к новому, пустому соединению. Это избавит от лишних операций ввода-вывода и ускорит работу приложения.