22

Liquibase を使用して、多くのレコード (現在は Excel ファイルにあります) を DB に追加しようとしています (将来の DB 変更のためにそれを行う方法を知っているため)

私の考えは、Java を使用して Excel ファイルを読み取り、Spring 初期化クラスから ChangeLogParameters を次のように入力することでした。

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>

それとも他に方法はありますか?

EDIT: 私の現在のオプションは、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 ファイルで:

エンティティ.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:私の問題は、正しい外部キーを使用して2番目のテーブルにデータを挿入できないことです

4

2 に答える 2

11

Liquibaseはあなたが達成したいことのための理想的なツールではないと思います。Liquibaseは、データベースのデータではなく、データベース構造の管理に適しています。

それでもLiquibaseを使用してデータを管理したい場合は、いくつかのオプションがあります(ここを参照)-

  1. 挿入ステートメントをSQLとして記録し、次のようにchangelog.xmlから参照します。

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

  2. 次のように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の「refresh」操作を実行することをお勧めします。

この操作は、文字通りデータセットの内容をデータベースに更新します。これは、既存の行のデータが更新され、存在しない行が挿入されることを意味します。データベースには存在するがデータセットには存在しない行は影響を受けません。

このようにして、参照データを1つの場所に保持し、時間の経過とともに追加して、情報のソースが1つだけになり、複数のLiquibaseチェンジセットに分割されないようにすることができます。DBUnitデータセットをバージョン管理で維持すると、トレース機能が提供され、ボーナスとして、DBUnitデータセットはデータベース間で移植可能であり、挿入順序などを管理して外部キー違反を防ぐことができます。

于 2012-08-31T07:42:01.450 に答える
2

ターゲット データベースによって異なります。SybaseまたはMSSQLサーバーを使用している場合は、インストールされたクライアントとドライバーに付属する BCP ツールを使用できますこれは、これらのデータベースの内外に大量のデータを移動する最速の方法です。

グーグルで検索すると、これらのリンクも見つかりました...

Oracle にはSQL*LOADERツールがあります

MySQL にはLOAD DATA INFILEコマンドがあります

各データベース ベンダーが、データの一括読み込み用のツールを提供することを期待しています。

于 2012-08-30T16:47:58.423 に答える