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を作成するには、の1回限りの処理を行う必要があります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)); 
  }  
}

これは、ソースデータベースと宛先データベースに同じ構造のテーブルがある場合にのみ機能することに注意してください。それらが異なる場合は、2つの間のマッピングの定義を開始する必要があります。その時点で、ETLツールを購入する方がよいでしょう。

次のコメント

挿入/更新のことはかなり難しいです。

からDatabaseMetaData主キーを取得し、ソーステーブルと宛先テーブルの両方にクエリを実行して、クエリが主キー列で順序付けられていることを確認する必要があります。

次に、ソース結果セットを反復処理するときに、宛先結果セットをチェックして、主キー列が順序に一致するか、それよりも大きいかどうかを確認し、それに応じて挿入または更新sqlを作成する必要があります。

たとえば、ソーステーブル1、2、3、4、7に単純な整数キーがあり、宛先テーブルに1、2、4、5、6がある場合、次のようになります。

  • 1=更新
  • 2=更新
  • 34より前なので安全にインサートになります
  • 4=更新
  • 7 7が挿入であることを確実に知る前に、6を超えるまで、宛先の結果セットを繰り返す必要があります。

それがそれほど明確でない場合は申し訳ありませんが、静的なテキストで説明するのは難しいです。

于 2012-05-04T10:33:43.813 に答える
0

電話する

this.jdbcTemplate.setDateSource(sourceDB)

データ読み込み前

this.jdbcTemplate.setDateSource(targetDB)

書く前に。

春に複数の DataSources を登録し、このようなものを使用します

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