跳转至

数据库元数据

本文你会学到

  • 通过 DatabaseMetaData 获取数据库产品名称、版本等信息
  • 通过 DatabaseMetaData.getTables() 枚举数据库中的表
  • 通过 ResultSetMetaData 获取查询结果的列信息

JDBC 提供两类元数据接口:

接口 获取方式 描述
DatabaseMetaData conn.getMetaData() 数据库级别信息:产品名、版本、驱动信息、表结构等
ResultSetMetaData rs.getMetaData() 查询结果级别信息:列数、列名、列类型等

DatabaseMetaData:数据库基本信息

获取数据库产品名称、版本、驱动信息
    /**
     * 获取 DatabaseMetaData,打印数据库和驱动信息
     */
    @Test
    void testDatabaseMetadata() throws SQLException {
        try (Connection conn = DriverManager.getConnection(URL)) {
            // 从连接获取数据库元数据
            DatabaseMetaData dbmd = conn.getMetaData();

            // 数据库产品信息
            String productName = dbmd.getDatabaseProductName();
            String productVersion = dbmd.getDatabaseProductVersion();
            System.out.println("数据库产品名称: " + productName);
            System.out.println("数据库产品版本: " + productVersion);

            // 驱动信息
            String driverName = dbmd.getDriverName();
            String driverVersion = dbmd.getDriverVersion();
            System.out.println("驱动名称: " + driverName);
            System.out.println("驱动版本: " + driverVersion);

            // JDBC 版本
            int jdbcMajor = dbmd.getJDBCMajorVersion();
            int jdbcMinor = dbmd.getJDBCMinorVersion();
            System.out.println("JDBC 版本: " + jdbcMajor + "." + jdbcMinor);

            // 断言验证
            assertNotNull(productName, "数据库产品名称不应为 null");
            assertTrue(productName.contains("H2"), "应为 H2 数据库");
            assertNotNull(driverName, "驱动名称不应为 null");
            assertTrue(jdbcMajor >= 4, "JDBC 主版本应 >= 4");
        }
    }

DatabaseMetaData:枚举数据库中的表

通过 getTables() 列出数据库中所有表
    /**
     * 用 DatabaseMetaData.getTables() 获取表信息
     */
    @Test
    void testDatabaseMetadataTables() throws SQLException {
        try (Connection conn = DriverManager.getConnection(URL)) {
            // 先创建一个测试表
            try (Statement stmt = conn.createStatement()) {
                stmt.execute("CREATE TABLE IF NOT EXISTS metadata_test ("
                        + "id INT PRIMARY KEY, "
                        + "name VARCHAR(100))");
            }

            DatabaseMetaData dbmd = conn.getMetaData();
            // getTables 参数:catalog, schemaPattern, tableNamePattern, types
            // null 表示不过滤,"%" 匹配所有
            try (ResultSet tables = dbmd.getTables(null, null, "%", new String[]{"TABLE"})) {
                boolean foundTestTable = false;
                System.out.println("=== 数据库中的表 ===");
                while (tables.next()) {
                    String catalog = tables.getString("TABLE_CAT");
                    String schema = tables.getString("TABLE_SCHEM");
                    String tableName = tables.getString("TABLE_NAME");
                    String tableType = tables.getString("TABLE_TYPE");
                    System.out.printf("表: catalog=%s, schema=%s, name=%s, type=%s%n",
                            catalog, schema, tableName, tableType);
                    if ("METADATA_TEST".equalsIgnoreCase(tableName)) {
                        foundTestTable = true;
                    }
                }
                assertTrue(foundTestTable, "应能查到 METADATA_TEST 表");
            }

            // 清理
            try (Statement stmt = conn.createStatement()) {
                stmt.execute("DROP TABLE IF EXISTS metadata_test");
            }
        }
    }

ResultSetMetaData:查询结果的列信息

从 ResultSetMetaData 获取列数、列名、列类型
    /**
     * 从 ResultSetMetaData 获取列信息
     */
    @Test
    void testResultSetMetadata() throws SQLException {
        try (Connection conn = DriverManager.getConnection(URL)) {
            // 创建测试表
            try (Statement stmt = conn.createStatement()) {
                stmt.execute("CREATE TABLE IF NOT EXISTS rs_meta_test ("
                        + "id INT, "
                        + "name VARCHAR(100), "
                        + "score DOUBLE, "
                        + "active BOOLEAN)");
                stmt.executeUpdate(
                        "INSERT INTO rs_meta_test VALUES (1, '测试', 95.5, true)");
            }

            // 从查询结果获取 ResultSetMetaData
            try (Statement stmt = conn.createStatement();
                 ResultSet rs = stmt.executeQuery("SELECT * FROM rs_meta_test")) {

                ResultSetMetaData rsmd = rs.getMetaData();
                int columnCount = rsmd.getColumnCount();
                assertEquals(4, columnCount, "应有 4 列");
                System.out.println("列数: " + columnCount);

                System.out.println("=== 列信息 ===");
                for (int i = 1; i <= columnCount; i++) {
                    String colName = rsmd.getColumnName(i);
                    String colTypeName = rsmd.getColumnTypeName(i);
                    System.out.printf("列 %d: name=%s, typeName=%s%n",
                            i, colName, colTypeName);
                }

                // 断言验证列名
                assertEquals("ID", rsmd.getColumnName(1));
                assertEquals("NAME", rsmd.getColumnName(2));
                assertEquals("SCORE", rsmd.getColumnName(3));
                assertEquals("ACTIVE", rsmd.getColumnName(4));
            }

            // 清理
            try (Statement stmt = conn.createStatement()) {
                stmt.execute("DROP TABLE IF EXISTS rs_meta_test");
            }
        }
    }

元数据的典型应用场景

  • 通用数据库工具(如 JDBC 客户端)动态渲染表格列头
  • ORM 框架在运行时反射映射列名与字段名
  • 数据库迁移工具获取表结构信息