使用spring jdbctemplate提取数据以加载到不同的数据库中

时间:2012-05-04 09:17:10

标签: java spring jdbctemplate

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

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

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

2 个答案:

答案 0 :(得分:1)

说实话,JdbcTemplate不是这类任务的最佳选择。您需要对ResultSet进行一次性处理以创建插入SQL,并且使用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您需要获取主键并查询源表和目标表,确保查询按主键列排序。

然后,当您遍历源结果集时,您需要检查目标结果集以查看主键列是否匹配或更高的顺序,依次创建插入或更新sql。

例如,如果您在源表1,2,3,4,7中有简单的整数键,并且在目标表中您有1,2,4,5,6,那么:

  • 1 =更新
  • 2 =更新
  • 3因为4之前可以安全地插入
  • 4 =更新
  • 7你需要迭代目标结果集,直到你已经超过6,然后才能确定7是插入。

对不起,如果不是那么清楚,很难用静态文字来解释。

答案 1 :(得分:0)

致电

this.jdbcTemplate.setDateSource(sourceDB)

在读取数据之前

this.jdbcTemplate.setDateSource(targetDB)

在写作之前。

在你的春天注册多个DataSource并使用类似的东西

@Autowired
@Qualifier("writeDataSource")
public void setDataSource(DataSource writeDataSource) {
    this.jdbcTemplate = new JdbcTemplate(writeDataSource);
}