我正在尝试使用Liquibase将大量记录(当前位于Excel文件中)添加到我的数据库中(以便我知道如何为将来的数据库更改执行此操作)
我的想法是使用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>
或者还有其他方法吗?
编辑: 我目前的选择是将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:我的问题是我无法使用正确的外键将数据插入第二个表
答案 0 :(得分:9)
我想说Liquibase不是你想达到的目标的理想工具。 Liquibase非常适合管理数据库结构,而不是数据库的数据。
如果您仍想使用Liquibase来管理数据,您有几个选项(请参阅here) -
将您的insert语句记录为SQL,并从changelog.xml中引用它们,如下所示:
<sqlFile path="/path/to/file.sql"/>
使用您在changelog.xml中引用的Custom Refactoring Class,如下所示:
<customChange class="com.example.YourJavaClass"
csvFile="/path/to/file.csv"/>
YourJavaClass将从CSV文件中读取记录,并将它们应用于数据库,实现此方法:
void execute(Database database) throws CustomChangeException;
请记住,一旦通过Liquibase加载了这些数据,就不应该修改文件中的数据,因为这些更改不会被重新应用。如果要对其进行更改,则必须在后续更改集中执行此操作。所以过了一段时间你可能会得到很多不同的CSV文件/ liquibase变更集,所有这些都在相同/相似的数据上运行(这取决于你将如何使用这些数据 - 它一旦插入就会改变吗?)。 / p>
我建议您使用DBUnit来管理参考数据。它是一种主要用于单元测试的工具,但它非常成熟,适合在生产中使用。您可以使用CSV或XML存储信息。我建议使用Spring'InitializingBean'从类路径加载数据集并执行DBUnit'refresh'操作,该操作将来自docs:
此操作从字面上将数据集内容刷新到数据库中。这个 表示现有行的数据已更新且不存在的行已获取 插入。数据库中存在但不存在于数据集中的任何行 不受影响。
这样,您可以将参考数据保存在一个位置,并随着时间的推移添加它,以便只有一个信息源,并且它不会分割为多个Liquibase变更集。将DBUnit数据集保留在版本控制中将提供跟踪功能,作为奖励,DBUnit数据集可以跨数据库移植,并且可以管理诸如插入顺序之类的内容以防止外键违规。
答案 1 :(得分:2)
这取决于您的目标数据库。如果您使用的是 Sybase 或 MSSQL 服务器,则可以使用已安装的客户端+驱动程序附带的BCP tool。这是将大量数据移入/移出这些数据库的最快方法。
在谷歌上搜索我也找到了这些链接......
Oracle拥有SQL*LOADER工具
MySQL有LOAD DATA INFILE命令
我希望每个数据库供应商都能提供一些用于批量加载数据的工具。