在 Java 中,我们使用 JDBC(Java Database Connectivity)来连接和操作数据库。当我们执行查询语句后,如果事先不知道 ResultSet
里包含哪些数据列,以及每个数据列的数据类型,就可以使用 ResultSetMetaData
对返回的结果集进行解析。那么本文就为大家介绍 ResultSetMetaData
分析结果集。
ResultSetMetaData
是 JDBC API 的一部分,在 java.sql
包下,是一个接口。它提供了关于结果集的元数据信息,例如列数、列名、列类型等。通过使用 ResultSetMetaData
,我们可以方便地获取结果集的元数据信息,从而更好地解析和处理结果集。
我们来看官方代码说明:
package java.sql;
/**
* An object that can be used to get information about the types
* and properties of the columns in a ResultSet
object.
* The following code fragment creates the ResultSet
object rs,
* creates the ResultSetMetaData
object rsmd, and uses rsmd
* to find out how many columns rs has and whether the first column in rs
* can be used in a WHERE
clause.
*
*
* ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");
* ResultSetMetaData rsmd = rs.getMetaData();
* int numberOfColumns = rsmd.getColumnCount();
* boolean b = rsmd.isSearchable(1);
*
*
*
* @since 1.1
*/
public interface ResultSetMetaData extends Wrapper {}
我们从源码可知 ResultSetMetaData
是一个接口,在 java.sql
包下,继承 Wrapper
接口。类注释中说(直译):一个对象,可用于获取关于 ResultSet
对象中列的类型和属性的信息。下面的代码片段创建 ResultSet
对象 rs
,创建 ResultSetMetaData
对象 rsmd
,并使用 rsmd
来查找 rs
有多少列,以及 rs
中的第一列是否可以用于 WHERE
子句。
我们可以看出 ResultSetMetaData
的用法非常简单,通过 rs.getMetaData()
获取 ResultSetMetaData
对象后,就可以查看分析后的结果。
世界很大,信息很多,有时候,我们知道某个东西(不精通)更重要。
接下来列出 ResultSetMetaData
常用的一些 API 方法:
// 返回此ResultSet对象中的列数。
int getColumnCount() throws SQLException;
// 指出指定列的正常最大宽度(以字符为单位)。
int getColumnDisplaySize(int column) throws SQLException;
// 获取指定列的建议标题,以用于打印输出和显示。建议的标题通常由SQL AS子句指定。
String getColumnLabel(int column) throws SQLException;
// 获取指定列的名称。
String getColumnName(int column) throws SQLException;
// 获取指定列的表模式。
String getSchemaName(int column) throws SQLException;
// 获取指定列的数据精度。
int getPrecision(int column) throws SQLException;
// 获取指定列在小数点右侧的位数。
int getScale(int column) throws SQLException;
// 获取指定列的表名称。
String getTableName(int column) throws SQLException;
// 获取指定列的表的编目名称。(数据库名)
String getCatalogName(int column) throws SQLException;
// 获取指定列的数据类型。返回的是java.sql.Types中的SQL类型。
int getColumnType(int column) throws SQLException;
// 获取指定列的数据库特定类型名称。
String getColumnTypeName(int column) throws SQLException;
// 返回生成其实例的Java类的全限定名称
String getColumnClassName(int column) throws SQLException;
// 指出指定的列是否为自增编号
boolean isAutoIncrement(int column) throws SQLException;
// 指出指定列是否区分大小写。
boolean isCaseSensitive(int column) throws SQLException;
// 指出指定的列是否可用于where子句。
boolean isSearchable(int column) throws SQLException;
// 指出指定的列是否为货币类型
boolean isCurrency(int column) throws SQLException;
// 指出指定列中值的可空性(该列是否可以为null)
int isNullable(int column) throws SQLException;
// 指出指定列中的值是否为带符号的数字。(该列是否为无符号)
boolean isSigned(int column) throws SQLException;
// 指出指定列是否只读。
boolean isReadOnly(int column) throws SQLException;
// 指出指定列是否可写。
boolean isWritable(int column) throws SQLException;
大家看到上述一些列方法,就很容易明白 ResultSetMetaData
接口是干嘛的了。注意这里的 ResultSetMetaData
接口是 JDBC 提供的标准,具体实现是由各数据库驱动操作的。
那么接下来我们在实际操作一下,看一下从 ResultSetMetaData
中具体可以获取哪些信息。
import java.sql.*;
public class TestResultSetMetaData {
public static void main(String[] args) {
String url = "jdbc:mysql://127.0.0.1:3306/test_jdbc?serverTimezone=Asia/Shanghai";
String user = "root";
String password = "root";
String sql = "select * from teacher where id = ?";
try {
// 加载数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 声明数据库连接、预编译语句资源对象
try (Connection connection = DriverManager.getConnection(url, user, password);
PreparedStatement preparedStatement = connection.prepareStatement(sql);){
// 设置参数
preparedStatement.setInt(1, 1);
// 执行SQL查询语句,声明ResultSet资源对象
try(ResultSet resultSet = preparedStatement.executeQuery();) {
// 通过resultSet.getMetaData()获取该结果集的ResultSetMetaData对象
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
// 获取列数
int columnCount = resultSetMetaData.getColumnCount();
System.out.println("查询结果一共有:" + columnCount + "列。");
// 获取每列的信息,注意列的序列从1开始
for (int i = 1; i <= columnCount; i++) {
System.out.println("===============================第" + i + "列==============================");
String columnName = resultSetMetaData.getColumnName(i);
int columnType = resultSetMetaData.getColumnType(i);
String columnTypeName = resultSetMetaData.getColumnTypeName(i);
String columnClassName = resultSetMetaData.getColumnClassName(i);
boolean isAutoIncrement = resultSetMetaData.isAutoIncrement(i);
System.out.print("=》列名称:" + columnName);
System.out.print(",列类型: " + columnType);
System.out.print(",列类型名称: " + columnTypeName);
System.out.print(",列对应Java类型全限定名: " + columnClassName);
System.out.print(",列是否为自增:" + isAutoIncrement);
System.out.print(",列是否可为空:" + resultSetMetaData.isNullable(i));
System.out.print(",列的最大宽度:" + resultSetMetaData.getColumnDisplaySize(i));
System.out.println();
}
} catch (SQLException e) {
e.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
上述代码中,通过 preparedStatement.executeQuery();
执行预编译好的 SQL,并将查询结果封装在 ResultSet
对象中,接下来调用 ResultSet
对象中的 getMetaData()
方法获取分析后的结果集元数据。然后通过其方法将列名、列类型等获取并打印出来。
在实际应用中,我们可能需要获取结果集的元数据信息,例如在结果集进行数据转换、数据格式化、数据映射等操作时。通过使用 ResultSetMetaData
,我们可以更好地了解结果集的结构和数据类型,从而进行更准确和高效的处理。此外,我们还可以利用 ResultSetMetaData
实现自定义的结果集处理逻辑,例如自定义列名、列宽、格式等。
以下实现一个小功能:连接到 test_jdbc
数据库,展示数据库中各表的表名,用户选择一个表(将表名输入到控制台),然后程序打印出该表的列以及每列的数据。注意以下代码仅仅是一个实现思路,或者说一个小应用场景的展示,并没有考虑过多的代码细节。
import java.sql.*;
import java.util.Scanner;
import java.util.Vector;
public class TestResultSetMetaDataDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 数据库连接信息
String url = "jdbc:mysql://127.0.0.1:3306/test_jdbc?serverTimezone=Asia/Shanghai";
String user = "root";
String password = "root";
// 查询数据库表名信息SQL语句
String sql = "select table_name from information_schema.tables where table_schema = 'test_jdbc'";
// 加载数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 声明数据库连接、预编译语句资源对象
try (Connection connection = DriverManager.getConnection(url, user, password);
PreparedStatement psTable = connection.prepareStatement(sql);){
// 提示信息
System.out.println("数据库:test_jdbc");
System.out.print("该数据库中存在以下表:");
// 执行查询数据库中表名SQL语句
try(ResultSet rsTableName = psTable.executeQuery();) {
// 遍历打印表名
while (rsTableName.next()){
System.out.print(rsTableName.getString("table_name") + " ");
}
System.out.println();// 换行
}
// 提示控制台输入表名
System.out.println("请输入要查询的数据库表:");
Scanner scanner = new Scanner(System.in);
String tableName = scanner.nextLine();
// 预编译并执行查询用户输入表的数据
try (PreparedStatement psTableData = connection.prepareStatement("select * from " + tableName);
ResultSet resultSet = psTableData.executeQuery();){
// 通过resultSet.getMetaData()获取该结果集的ResultSetMetaData对象
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
// 获取列数
int columnCount = resultSetMetaData.getColumnCount();
// 获取每列的信息,注意列的序列从1开始
for (int i = 1; i <= columnCount; i++) {
// 获取列名并打印
String columnName = resultSetMetaData.getColumnName(i);
System.out.print(" " + columnName + " ");
}
System.out.println();// 换行
// 将每行数据存储在Vector集合中
Vector<Vector<String>> rowData = new Vector<>();
while (resultSet.next()){
Vector<String> columnData = new Vector<>();
for (int i = 1; i <= columnCount; i++) {
columnData.add(resultSet.getString(i));
}
rowData.add(columnData);
}
// 第一层循环遍历每行数据
for (int i = 0; i < rowData.size(); i++) {
Vector<String> columnData = rowData.get(i);
// 第二层循环遍历每行中每列数据
for (int j = 0; j < columnData.size(); j++) {
System.out.print(" " + columnData.get(j) + " ");
}
System.out.println();// 换行
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
运行效果如下:
数据库:test_jdbc
该数据库中存在以下表:teacher
请输入要查询的数据库表:
teacher
id name sex age
1 张三 男 25
2 李四 男 27
3 王五 男 28
4 赵六 女 20
5 张某0 男 20
6 张某1 男 20
7 张某2 男 20
8 张某3 男 20
9 张某4 男 20
10 张某5 男 20
11 张某6 男 20
12 张某7 男 20
13 张某8 男 20
14 张某9 男 20
15 张某10 男 20
以上实现是不是和我们的数据库客户端有点像,只不过我们的程序太简陋。
ResultSetMetaData
是 JDBC 中非常重要的一个接口,它提供了关于结果集的元数据信息。通过使用 ResultSetMetaData
,我们可以方便地获取结果集的列数、列名、列类型等,从而更好地解析和处理结果集。在实际应用中,我们可能会遇到不同的数据源和数据类型,通过使用 ResultSetMetaData
,我们可以更好地了解和处理这些数据源和数据类型,实现更准确和高效的数据转换、数据格式化、数据映射等操作。