Подтвердить что ты не робот

Вставка большого количества значений (с помощью FK) в базу данных с использованием LiquiBase и Spring

Я пытаюсь добавить много записей (в настоящее время находится в файле Excel) в свою БД с использованием Liquibase (чтобы я знал, как это сделать для будущих изменений в БД)

Моя идея состояла в том, чтобы прочитать файл excel с помощью Java, а затем заполнить ChangeLogParameters из моего класса инициализации Spring следующим образом:

SpringLiquibase liqui = new SpringLiquibase();
liqui.setBeanName("liquibaseBean");
liqui.setDataSource(dataSource());
liqui.setChangeLog("classpath:changelog.xml");

HashMap<String, String> values = new HashMap<String, String>();
values.put("line1col1", ExcelValue1);
values.put("line1col2", ExcelValue2);
values.put("line1col3", ExcelValue3);
values.put("line2col1", ExcelValue4);
values.put("line2col2", ExcelValue5);
values.put("line2col3", ExcelValue6);
...
liqui.setChangeLogParameters(values);

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

<changeSet author="gcardoso" id="2012082707">
    <insert tableName="t_user">
        <column name="login" value="${ExcelValue1}"/>
        <column name="name" value="${ExcelValue2}}"/>
        <column name="password" value="${ExcelValue3}"/>
    </insert>
    <insert tableName="t_user">
        <column name="login" value="${ExcelValue4}"/>
        <column name="name" value="${ExcelValue5}}"/>
        <column name="password" value="${ExcelValue6}"/>
    </insert>
    ...
</changeSet>

Есть ли способ, которым я мог бы сделать что-то вроде этого:

HashMap<String, ArrayList<String>> values = new HashMap<String, ArrayList<String>>();
values.put("col1", Column1);
values.put("col2", Column2);
values.put("col3", Column3);
liqui.setChangeLogParameters(values);

<changeSet author="gcardoso" id="2012082707">
    <insert tableName="t_user">
        <column name="login" value="${Column1}"/>
        <column name="name" value="${Column2}}"/>
        <column name="password" value="${Column3}"/>
    </insert>
</changeSet>

Или есть другой способ?

РЕДАКТИРОВАТЬ: Мой текущий вариант - преобразовать Excel в CSV файл и импортировать данные с помощью

<changeSet author="gcardoso" id="InitialImport2" runOnChange="true">

    <loadData tableName="T_ENTITY" file="com/exictos/dbUpdate/entity.csv">
        <column header="SHORTNAME" name="SHORTNAME" />
        <column header="DESCRIPTION" name="DESCRIPTION" />
    </loadData>


    <loadData tableName="T_CLIENT" file="com/exictos/dbUpdate/client.csv">
        <column header="fdbhdf" name="ENTITYID" defaultValueComputed="(SELECT ID FROM T_ENTITY WHERE SHORTNAME = ENTITY_REFERENCE"/>
        <column header="DESCRIPTION" name="DESCRIPTION" />
    </loadData>


</changeSet>

с этими файлами CSV:

entity.csv

SHORTNAME,DESCRIPTION
nome1,descricao1
nome2,descricao2

client.csv

DESCRIPTION,ENTITY_REFERENCE
descricaoCliente1,nome1
descricaoCliente2,nome2

Но я получаю эту ошибку:

liquibase.exception.DatabaseException: Error executing SQL INSERT INTO `T_CLIENT` (`DESCRIPTION`, `ENTITY_REFERENCE`) VALUES ('descricaoCliente1', 'nome1'): Unknown column 'ENTITY_REFERENCE' in 'field list'

Если я изменил заголовок моего client.csv на DESCRIPTION, ENTITYID, я получаю эту ошибку:

liquibase.exception.DatabaseException: Error executing SQL INSERT INTO `T_CLIENT` (`DESCRIPTION`, `ENTITYID`) VALUES ('descricaoCliente1', 'nome1'): Incorrect integer value: 'nome1' for column 'entityid' at row 1

В любом из этих случаев он выглядит как defaultValueComputed не работает так же, как valueComputed в следующем примере

<changeSet author="gcardoso" id="InitialImport1">

    <insert tableName="T_ENTITY">
        <column name="SHORTNAME">nome1</column>
        <column name="DESCRIPTION">descricao1</column>
    </insert>

    <insert tableName="T_CLIENT">
        <column name="ENTITYID" valueComputed="(SELECT ID FROM T_ENTITY WHERE SHORTNAME = 'nome1')"/>
        <column name="DESCRIPTION">descricaoCliente</column>
    </insert>

</changeSet>

Является ли это ожидаемым поведением? Ошибка в LiquiBase? Или просто я делаю что-то неправильно (скорее всего)?

Или есть ли другой способ импорта огромного количества данных? Но всегда используйте LiquiBase и/или Spring.

EDIT2: Моя проблема в том, что я не могу вставить данные во вторую таблицу с правильным внешним ключом

4b9b3361

Ответ 1

Я бы сказал, что Liquibase - не идеальный инструмент для того, чего вы хотите достичь. Liquibase хорошо подходит для управления структурой базы данных, а не данными базы данных.

Если вы все еще хотите использовать Liquibase для управления данными, у вас есть пара опций (см. здесь) -

  • Запишите свои операторы вставки как SQL и обратитесь к ним из файла changelog.xml следующим образом:

    <sqlFile path="/path/to/file.sql"/>

  • Используйте Пользовательский класс рефакторинга, который вы ссылаетесь на файл changelog.xml следующим образом:

    <customChange class="com.example.YourJavaClass" csvFile="/path/to/file.csv"/>

    YourJavaClass будет считывать записи из файла CSV и применять их к базе данных, реализуя этот метод:

    void execute(Database database) throws CustomChangeException;

Имейте в виду, что после загрузки этих данных через Liquibase вы не должны изменять данные в файле, потому что эти изменения не будут повторно применены. Если вы хотите внести в него изменения, вам нужно будет сделать это в последующих наборах изменений. Таким образом, через некоторое время у вас может быть множество разных файлов CSV/Liquibase, все из которых работают с одними и теми же/подобными данными (это зависит от того, как вы собираетесь использовать эти данные - будет ли он когда-либо изменяться после вставки?).

Я бы рекомендовал использовать DBUnit для управления вашими справочными данными. Его инструмент в основном используется в модульном тестировании, но он очень зрелый, подходит для использования в производстве, я бы сказал. Вы можете хранить информацию в CSV или XML. Я бы предложил использовать Spring 'InitializingBean' для загрузки набора данных из пути к классам и выполнить операцию обновления базы данных DBUnit, которая из docs:

Эта операция буквально обновляет содержимое набора данных в базе данных. Эта   означает, что данные существующих строк обновляются и несуществующая строка get   вставлено. Любые строки, которые существуют в базе данных, но не в наборе данных, остаются   незатронутыми.

Таким образом, вы можете хранить свои справочные данные в одном месте и добавлять к нему со временем, чтобы был только один источник информации, и он не разбивается на несколько наборов изменений Liquibase. Сохранение наборов данных DBUnit в управлении версиями обеспечило бы возможность отслеживания, а в качестве бонуса набор данных DBUnit переносится через базы данных и может управлять такими вещами, как порядок вставки, чтобы предотвратить нарушения внешнего ключа для вас.

Ответ 2

Это зависит от вашей целевой базы данных. Если вы используете сервер Sybase или MSSQL, вы можете использовать инструмент BCP, который приходит вместе с вашим установленным клиентом + драйвером. Это самый быстрый способ перемещения больших объемов данных в/из этих баз данных.

Google google, я также нашел эти ссылки...

В Oracle есть инструмент SQL * LOADER

У MySQL есть команда команда LOAD DATA INFILE

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