5

我需要从我的数据库中的一些随机表中提取数据,并插入到不同数据库中的类似表中。

我不清楚如何编写一个可以处理所有表的通用方法。

this.jdbcTemplate.query("select * from TableName", new RowMapper() {
         @Override
         public Object mapRow(ResultSet resultSet, int i) throws SQLException {
             while(resultSet.next()){
//                Fetch data in a generic object for later updating in a different schema
             }
             return null;  //To change body of implemented methods use File | Settings | File Templates.
         }
     });
4

2 回答 2

3

老实说,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);
}

重要的是在createInsertSqlsetParameters方法中发生了什么,它们都使用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.

于 2012-05-04T10:33:43.813 回答
0

调用

this.jdbcTemplate.setDateSource(sourceDB)

读取数据前

this.jdbcTemplate.setDateSource(targetDB)

在写作之前。

在你的春天注册多个数据源并使用类似这样的东西

@Autowired
@Qualifier("writeDataSource")
public void setDataSource(DataSource writeDataSource) {
    this.jdbcTemplate = new JdbcTemplate(writeDataSource);
}
于 2012-05-04T09:51:01.917 回答