老实说,JdbcTemplate
这不是此类任务的最佳选择。您需要对创建插入 SQL 进行一些一次性处理,ResultSet
并且实际上没有任何一点可以使用JdbcTemplate
(据我所知)。
无论如何,这就是我在纯 JDBC 中做你想要的副本的方式(JdbcTemplate
如果你愿意,你可以采用相同的原则并将其压缩):
Connection sourceConnection = null;
Connection destinationConnection = null;
PreparedStatement selectStatement = null;
PreparedStatement insertStatement = null;
ResultSet resultSet = null;
try
{
sourceConnection = ...
destinationConnection = ...
selectStatement = sourceConnection.prepareStatement("SELECT * FROM table");
resultSet = selectStatement.executeQuery();
insertStatement = destinationConnection.prepareStatement(createInsertSql(resultSet.getMetaData()));
int batchSize = 0;
while (resultSet.next())
{
setParameters(insertStatement, resultSet);
insertStatement.addBatch();
batchSize++;
if (batchSize >= BATCH_EXECUTE_SIZE)
{
insertStatement.executeBatch();
batchSize = 0;
}
}
insertStatement.executeBatch();
}
finally
{
JdbcUtils.closeResultSet(resultSet);
JdbcUtils.closeStatement(insertStatement);
JdbcUtils.closeStatement(selectStatement);
JdbcUtils.closeConnection(destinationConnection);
JdbcUtils.closeConnection(sourceConnection);
}
重要的是在createInsertSql
和setParameters
方法中发生了什么,它们都使用ResultSetMetaData
来执行它们的操作。根据您使用的数据库,您需要稍微使用它们,但它们看起来像:
private String createInsertSql(ResultSetMetaData resultSetMetaData) throws SQLException
{
StringBuffer insertSql = new StringBuffer("INSERT INTO ");
StringBuffer values = new StringBuffer(" VALUES (");
insertSql.append(resultSetMetaData.getTableName());
for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++)
{
insertSql.append(resultSetMetaData.getColumnName(i));
values.append("?");
if (i <= resultSetMetaData.getColumnCount())
{
insertSql.append(", ");
values.append(", ");
}
else
{
insertSql.append(")");
values.append(")");
}
}
return insertSql.toString() + values.toString();
}
和:
private void setParameters(PreparedStatement preparedStatement, ResultSet resultSet) throws SQLException
{
for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++)
{
preparedStatement.setObject(i, resultSet.getObject(i));
}
}
请注意,这仅适用于源数据库和目标数据库具有相同结构的表的情况。如果它们不同,您将不得不开始定义两者之间的映射,此时您最好购买 ETL 工具。
关注评论
插入/更新的事情要困难得多。
从DatabaseMetaData
您需要获取主键并查询源表和目标表,确保查询按主键列排序。
Then as you iterate over the source result set you'd need to check the destination result set to see if the primary key columns match or are greater in ordering, creating insert or update sql accordingingly.
For example if you had simple integer keys in the source table 1, 2, 3, 4, 7 and in the destination table you had 1, 2, 4, 5, 6 then:
- 1 = update
- 2 = update
- 3 because it's before 4 can safely be an insert
- 4 = update
- 7 you need to iterate the destination result set until you've gone past 6 before you can know for certain that 7 is an insert.
Sorry if that's not that clear, it's hard to explain in static text.