tutorial locations generate java sql database spring liquibase

java - locations - spring datasource initialization



InserciĆ³n de muchos valores(con FK) en la base de datos utilizando LiquiBase y Spring (2)

Estoy tratando de agregar una gran cantidad de registros (actualmente ubicados en un archivo de Excel) en mi base de datos utilizando Liquibase (para saber cómo hacerlo para futuros cambios en la base de datos)

Mi idea fue leer el archivo de Excel usando Java y luego llenar los ChangeLogParameters de mi clase de inicialización de Spring de esta manera:

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);

El problema con este enfoque es que mi changelog.xml sería muy extraño (y no productivo)

<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>

¿Hay alguna manera de que yo pueda hacer algo como esto:

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>

o hay otra manera?

EDITAR: Mi opción actual es convertir Excel en un archivo CSV e importar los datos usando

<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>

con estos archivos CSV:

entidad.csv

SHORTNAME,DESCRIPTION nome1,descricao1 nome2,descricao2

cliente.csv

DESCRIPTION,ENTITY_REFERENCE descricaoCliente1,nome1 descricaoCliente2,nome2

Pero me sale este error:

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

Si cambio el encabezado de mi client.csv a DESCRIPTION, ENTITYID recibo este error:

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

En cualquiera de estos casos, parece que defaultValueComputed no funciona de la misma manera que valueComputed en el siguiente ejemplo

<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>

¿Es este el comportamiento esperado? Bug de LiquiBase? ¿O simplemente estoy haciendo algo mal (lo más probable)?

¿O hay alguna otra manera de importar una gran cantidad de datos? Pero siempre utilizando LiquiBase y / o Spring.

EDIT2: Mi problema es que no puedo insertar los datos en la segunda tabla con la clave externa correcta


Depende de su base de datos de destino. Si está utilizando el servidor Sybase o MSSQL , puede usar la herramienta BCP que viene con su controlador cliente + instalado. Es la forma más rápida de mover grandes cantidades de datos dentro / fuera de estas bases de datos.

Buscando en Google también encontré estos enlaces ...

Oracle tiene la herramienta SQL * LOADER

MySQL tiene el comando LOAD DATA INFILE

Espero que cada proveedor de bases de datos proporcione una herramienta con alguna descripción para la carga masiva de datos.


Yo diría que Liquibase no es la herramienta ideal para lo que quiere lograr. Liquibase está bien adaptado para administrar la estructura de la base de datos, no los datos de la base de datos.

Si aún desea usar Liquibase para administrar los datos, tiene un par de opciones (vea here ) -

  1. Registre sus declaraciones de inserción como SQL, y consúltelas desde changelog.xml como esto:

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

  2. Utilice una clase de refactorización personalizada a la que hace referencia en el archivo changelog.xml como este:

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

    YourJavaClass leería los registros del archivo CSV y los aplicaría a la base de datos, implementando este método:

    void execute(Database database) throws CustomChangeException;

Tenga en cuenta que una vez que haya cargado estos datos a través de Liquibase, no debe modificar los datos en el archivo, ya que esos cambios no se volverán a aplicar. Si desea realizar cambios en él, tendría que hacerlo en los conjuntos de cambios posteriores. Entonces, después de un tiempo, puede terminar con una gran cantidad de diferentes conjuntos de cambios de archivos CSV / liquibase, todos operando en los mismos datos / similares (esto depende de cómo vaya a usar estos datos, ¿alguna vez cambiará una vez que se inserte?).

Recomendaría considerar el uso de DBUnit para administrar sus datos de referencia. Es una herramienta utilizada principalmente en pruebas unitarias, pero es muy madura, adecuada para uso en producción, diría yo. Puede almacenar información en CSV o XML. Yo sugeriría usar un ''InitializingBean'' de Spring para cargar el conjunto de datos de la ruta de clase y realizar una operación de ''actualización'' de DBUnit, que, desde los docs :

Esta operación, literalmente, actualiza el contenido del conjunto de datos en la base de datos. Esto significa que los datos de las filas existentes se actualizan y la fila no existente se inserta. Cualquier fila que exista en la base de datos pero no en el conjunto de datos no se verá afectada.

De esta manera, puede mantener sus datos de referencia en un lugar y agregarlos a lo largo del tiempo para que haya solo una fuente de información, y no se divide entre varios conjuntos de cambios Liquibase. Mantener sus conjuntos de datos DBUnit en el control de versiones brindaría capacidad de rastreo, y como beneficio adicional, los conjuntos de datos DBUnit son portátiles en todas las bases de datos, y pueden administrar cosas como el orden de inserción para evitar violaciones de clave externa para usted.