使用 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 的列。
我想通过 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 的列。