【问题标题】:How to read database view metadata如何读取数据库视图元数据
【发布时间】:2022-01-03 17:13:16
【问题描述】:

我正在尝试使用 Java 和 Spring 来读取 MySQL 数据库的表结构。我得到的代码(基于本网站上的其他答案)是:

private void dumpDefinition(JdbcTemplate jdbc, String table) throws SQLException {
    DatabaseMetaData metaData = jdbc.getDataSource()
        .getConnection()
        .getMetaData();

    try (
        ResultSet definition = 
           metaData.getColumns(null, null, table, null)     // Exception here
    ) {
        System.out.println(table);

        while (definition.next()) {
            String name = definition.getString("COLUMN_NAME");
            int type = definition.getInt("DATA_TYPE");

            System.out.println("   " + name + "    " + type);
        }
    } catch (SQLException | RuntimeException e) {
        e.printStackTrace();
    }
}

如果我用我的任何数据库表的名称调用此代码,它就可以完美运行。但是,当我传递任何数据库视图的名称时,会出现以下异常:

java.sql.SQLException: Index 8 out of bounds for length 7
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129)
    at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
    at com.mysql.cj.jdbc.StatementImpl.executeQuery(StatementImpl.java:1206)
    at com.mysql.cj.jdbc.DatabaseMetaData$2.forEach(DatabaseMetaData.java:2162)
    at com.mysql.cj.jdbc.DatabaseMetaData$2.forEach(DatabaseMetaData.java:2091)
    at com.mysql.cj.jdbc.IterateBlock.doForAll(IterateBlock.java:56)
    at com.mysql.cj.jdbc.DatabaseMetaData.getColumns(DatabaseMetaData.java:2267)
    at my.package.MyClass.dumpDefinition(MyClass.java:69)
        --- omitted Spring Boot and Tomcat classes for clarity --- 

Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 8 out of bounds for length 7
    at com.mysql.cj.protocol.a.NativePacketPayload.readInteger(NativePacketPayload.java:386)
    at com.mysql.cj.protocol.a.NativeServerSessionStateController$NativeServerSessionStateChanges.init(NativeServerSessionStateController.java:108)
    at com.mysql.cj.protocol.a.result.OkPacket.parse(OkPacket.java:64)
    at com.mysql.cj.protocol.a.NativeProtocol.readServerStatusForResultSets(NativeProtocol.java:1691)
    at com.mysql.cj.protocol.a.ResultsetRowReader.read(ResultsetRowReader.java:83)
    at com.mysql.cj.protocol.a.ResultsetRowReader.read(ResultsetRowReader.java:42)
    at com.mysql.cj.protocol.a.NativeProtocol.read(NativeProtocol.java:1587)
    at com.mysql.cj.protocol.a.TextResultsetReader.read(TextResultsetReader.java:87)
    at com.mysql.cj.protocol.a.TextResultsetReader.read(TextResultsetReader.java:48)
    at com.mysql.cj.protocol.a.NativeProtocol.read(NativeProtocol.java:1600)
    at com.mysql.cj.protocol.a.NativeProtocol.readAllResults(NativeProtocol.java:1654)
    at com.mysql.cj.protocol.a.NativeProtocol.sendQueryPacket(NativeProtocol.java:1000)
    at com.mysql.cj.protocol.a.NativeProtocol.sendQueryString(NativeProtocol.java:933)
    at com.mysql.cj.NativeSession.execSQL(NativeSession.java:664)
    at com.mysql.cj.jdbc.StatementImpl.executeQuery(StatementImpl.java:1174)
    ... 72 more

我尝试将 SQL 驱动程序升级到最新版本 (8.0.27),但没有帮助。

作为一种解决方法,我尝试了:

try (
        PreparedStatement statement = jdbc.getDataSource()
            .getConnection()
            .prepareStatement("SELECT * from mySchema." + table + " WHERE 1 = 0");
        ResultSet resultSet = statement.executeQuery()  // Exception here
    ) {
        ResultSetMetaData meta = resultSet.getMetaData();
                    etc 

但同样,我得到了相同的 SQLException - 一个数组越界异常。

有什么想法吗?

附加

以下代码会转储所有数据库表列,但一旦将视图引入架构中就会失败并出现相同的异常

private void readDefinitions(JdbcTemplate jdbc) {
    try (
        ResultSet definition = jdbc.getDataSource()
            .getConnection()
            .getMetaData()
            .getColumns(null, "mySchema", null, null) // Exception here
    ) {
        while (definition.next()) {
            String name = definition.getString("COLUMN_NAME");
            int type = definition.getInt("DATA_TYPE");
            String table = definition.getString("TABLE_NAME");

            System.out.println(table + " - " + name + " => " + type);
        }
    } catch (SQLException | RuntimeException e) {
        e.printStackTrace();
    }
}

我在查看 JDBC 错误吗?

更新

  1. 我的 POM 中给出的 JDBC 驱动程序是:

     <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>8.0.27</version>
     </dependency>
    

metaData.getDriverVersion() 返回mysql-connector-java-8.0.27 (Revision: e920b979015ae7117d60d72bcc8f077a839cd791)

我也尝试过 8.0.21 和 5.1.49 版本,但它们的行为方式相同。

这一切都在装有 Java 17.0.1 的 Windows 11 PC 上运行

  1. 在上面的代码中,我突出显示了导致异常的行 - 它是创建我需要处理的结果的行(在我尝试读取任何列之前)

  2. WRT 堆栈跟踪 - 我捕获的异常是 java.sql.SQLException - 它没有包含在任何东西中。

  3. 我正在与之交谈的数据库位于 Raspberry Pi 上。详情如下:

  • 版本: 10.3.23-MariaDB-0+deb10u1 (Raspbian 10)
  • 编译用于: debian-linux-gnueabihf (armv7l)

【问题讨论】:

  • 什么版本的 Java/JDBC?什么 JDBC 驱动程序?您可以从.getMetadata() 方法返回的对象中获取此信息。
  • 只是一个猜测,您是否尝试使用整数索引而不是命名参数?例如。 getString(3) 而不是 getString("COLUMN_NAME")
  • 您使用的是哪个版本的 MySQL?
  • 请发布整个堆栈跟踪。
  • @TheImpaler - 我已将所有 JDBC 驱动程序信息添加到帖子正文中,但基本上是 8.0.27

标签: java mysql spring-boot jdbc


【解决方案1】:

该错误似乎是一个协议问题(它预期的字节数比它收到的多),并且鉴于您连接到 MariaDB,而不是 MySQL,您应该使用 MariaDB Connector/J(版本 2.7.3),并且协议前缀jdbc:mariadb:

虽然 MariaDB 最初是 MySQL 的一个分支,但自从它被分叉后就出现了分歧。

【讨论】:

  • 我一使用 MariaDB 驱动程序就可以了。干杯:-D
猜你喜欢
  • 2021-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-03
  • 1970-01-01
  • 1970-01-01
  • 2016-10-18
相关资源
最近更新 更多