使用 JDBC 和 Java 进行数据库访问 - 不对表和列进行建模

database access with JDBC and Java - without modelling tables and columns

我想通过 JDBC 读写数据库 table,而无需告诉我的 Java 代码任何关于 table 的信息,除了它们的名字。

我需要对数据进行的唯一处理是比较和 read/write。详情见下文。

我基本上是在寻找类似的东西:

A = connect_db();
B = connect_db();
while (row = read_next_row(A)) {
    if (A.something == whatever) {
        insert_row(B, row);
    }
}

在类似 PHP 的事情中,这很容易,我将一行读入关联数组,完成。在 Java 中,这似乎过于复杂,但我在 Java 中并不擅长,所以我可能会错过一个明显、简单的解决方案。

这是一个低级的、数据库优先的工具,它在多个数据库之间比较和复制数据。我可以假设 table 在 DB 之间是相同的,除了数据类型(一个 DB 可能称它为 String 和另一个 Varchar)和我可以安全地忽略的某些源中的附加(内部计算)列.我正在寻找编码解决方案的原因是数据库系统不同(但都有 JDBC 连接器)。

但是,我的用户能够更改数据库结构,因此我的工具需要独立于列名和类型,但主 ID 等少数列始终保证存在。但是,例如,关于人的 table 包含名字和姓氏(以及其他内容),我不能保证它将来不会包含中间名列。我不想为每次数据库结构更改都更改非常简单的复制工具。

我错过了什么?这在 Java/JDBC 中可能吗?

查询时,您可以检查 ResulSetMetaData 以发现查询的列名(或标签)。

PHP 关联数组的等价物是 Map

一个您已经知道 table 名称的简单示例:

public List<Map<String, Object>> getValues(String tableName, Connection connection) {
  try (var stmt = connection.createStatement();
       var rs = stmt.executeQuery("select * from " + stmt.enquoteIdentifier​(tableName, true))) {
    var result = new ArrayList<Map<String, Object>>();
    var rsmd = rs.getMetaData();
    int columnCount = rsmd.getColumnCount();
    while (rs.next()) {
      var row = new HashMap<String, Object>>(columnCount);
      for (int idx = 1; idx <= columnCount; idx++) {
        // or use getColumnLabel if you use a query that can have aliases
        row.put(rsmd.getColumnName(idx), rs.getObject(idx));
      }
      result.add(row);
    }
    return result;
  }
}

请注意,此 returns 是 table 的所有行,因此对于非常大的 table,这在内存方面效率不高。因此,为了处理大型 table,您需要考虑不同的解决方案,例如返回 Stream,或传递行的使用者(例如 Consumer<Map<String, Object>>)。

对于更高级的表单,您可以使用 DatabaseMetaData.getTables to discover the available tables, and optionally DatabaseMetaData.getColumns 来发现 table 的列。