Прямой перенос данных между базами: Подробный разбор метода на примере кода java
Салимжанов Р.
Введение
Что такое метод переноса данных?
Это способ копирования данных из одной базы (например, Firebird) в другую (например, Postgres) напрямую, без промежуточных шагов. Давайте разберем его на примере кода.
Основной алгоритм
- Подготовка целевой БД (создание таблиц если нужно)
- Чтение данных из исходной таблицы
- Пакетная запись в целевую БД
- Обработка конфликтов (обновление существующих записей)
Пример проблемы
Допустим есть небольшое задание: перенести кучу данных из одной БД в другую. У меня есть две базы:
Firebird с двумя заполненными таблицами например:
И PostgreSQL , куда нужно загрузить эти же таблицы:
Задача: написать программу на Java, которая перенесет гору записей из Firebird в Postgres, не дублируя их и обновляя при необходимости.
Разбор кода шаг за шагом
1. Подготовка БД
Что делает: Проверяет существование таблиц в Postgres и создает их при необходимости.
2. Умная вставка (UPSERT)
1) INSERT INTO
- Начинает с INSERT INTO tableName (col1, col2, …) и VALUES (?, ?, …), где число ? соответствует числу колонок.
2) ON CONFLICT (id)
- Добавляет ON CONFLICT (id) — ключевую колонку id берём за определяющую уникальность.
3) DO UPDATE SET …
- После DO UPDATE SET перечисляет все колонки, кроме id, в виде col = EXCLUDED.col, чтобы при конфликте (то есть если запись с таким id уже есть) обновить существующие поля новыми значениями.
3. Чтение и вставка данных из исходной таблицы
Объясню по шагам:
- getPgTableName(fbTableName) Преобразует имя таблицы из Firebird в имя таблицы в Postgres. В нашем случае просто заменяет fb1 → pg1.
- columns.split(",") Из строки вида "id,name,created_at" делает массив ["id", "name", "created_at"].
- Try-with-resources Открываются сразу два соединения (srcConn и dstConn), создаётся Statement для чтения и ResultSet с данными. Всё это автоматически закроется в конце блока, даже если упадёт исключение.
- Отключение автокоммита По умолчанию каждая операция INSERT сразу фиксируется. Мы отключаем это, чтобы группировать операции в одну транзакцию и контролировать момент коммита.
- buildUpsertSql(...) Возвращает строку SQL примерно такого вида:
Это гарантирует, что при повторной вставке записи с тем же id она будет обновлена, а не дублирована.
6 Заполнение и сборка батчей
- В цикле while (rs.next()) читаем каждую строку из Firebird.
- С помощью pstmt.setObject(...) последовательно подставляем значения в “?”, соответствующие колонкам.
- pstmt.addBatch() собирает все команды в один пакет.
- По достижении 1000 команд делаем executeBatch() (отправляем все эти 1000 запросов на сервер) и commit() (фликтим транзакцию).
7 Финальная запись и коммит После того как строки из ResultSet закончились, обязательно выполняем оставшийся пакет (executeBatch()) и фиксируем его (commit()).
Вывод и обоснование выбора метода прямого переноса данных
Метод прямого переноса данных между базами данных, рассмотренный выше, — это оптимальный способ миграции, когда необходимо:
- Скопировать большие объёмы данных без создания промежуточных файлов (например, CSV, XML и т.д.),
- Сохранить структуру и логику связи таблиц (включая внешний ключ),
- Обновлять уже существующие данные, а не дублировать их при повторном запуске,
- И работать с двумя различными СУБД (в примере — Firebird и PostgreSQL).
ПОЛНЫЙ КОД
PS
Конечно же, эта статья дает только суть. Основная структура будет намного сложнее. Например если рассмотреть с точки зрения информационной безопасности, можно выделить кучу рисков. Ну например:
1. Защита учетных данных Хранение их в открытом виде в конфигах — прямая угроза.
2. Защита данных в транзите Данные передаются в открытом виде между приложением и СУБД. Соответственно следует использовать SSL/TLS соединения.
3. Предотвращение SQL-инъекций Динамическое формирование SQL-запросов с именами таблиц через конкатенацию строк лучше не использовать. А например, сделать валидацию имен таблиц через белый список.
4. Принцип минимальных привилегий Приложение работает с правами суперпользователя БД. В безопасности это вообще “атата”.
И так далее и далее. Все перечислять не интересно.