如何读取数据库视图元数据
How to read database view metadata
我正在尝试使用 Java 和 Spring 读取 MySQL 数据库的 table 结构。我得到的代码(基于本网站上的其他答案)是:
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();
}
}
如果我使用我的任何数据库 table 的名称调用此代码,它会完美运行。但是,当我传递任何数据库视图的名称时,出现以下异常:
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.forEach(DatabaseMetaData.java:2162)
at com.mysql.cj.jdbc.DatabaseMetaData.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
但我又得到了相同的 SQL异常 - 数组越界异常。
有什么想法吗?
额外
以下代码转储所有数据库 table 列,但在将视图引入架构后立即失败并出现相同的异常
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 错误吗?
更新
我的 POM 中给出的 JDBC 驱动程序是:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
metaData.getDriverVersion()
returns mysql-connector-java-8.0.27 (Revision: e920b979015ae7117d60d72bcc8f077a839cd791)
我也尝试过 8.0.21 和 5.1.49 版本,但它们的行为方式相同。
这是 运行 在 Windows 11 PC 上 Java 17.0.1
在上面的代码中,我突出显示了导致异常的行 - 它是创建我需要处理的结果的行(在我尝试读取任何列之前)
WRT 堆栈跟踪 - 我捕获的异常是 java.sql.SQLException
- 它没有包含在任何东西中。
我正在与之交谈的数据库在 Raspberry Pi 上。详情如下:
- 版本: 10.3.23-MariaDB-0+deb10u1 (Raspbian 10)
- 编译用于: debian-linux-gnueabihf (armv7l)
错误似乎是一个协议问题(它期望的字节数比接收到的字节数多),并且鉴于您连接的是 MariaDB,而不是 MySQL,您应该使用 MariaDB Connector/J (版本 2.7.3)和协议前缀 jdbc:mariadb:
.
尽管 MariaDB 最初是 MySQL 的一个分支,但自从它被分支后就出现了分歧。
我正在尝试使用 Java 和 Spring 读取 MySQL 数据库的 table 结构。我得到的代码(基于本网站上的其他答案)是:
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();
}
}
如果我使用我的任何数据库 table 的名称调用此代码,它会完美运行。但是,当我传递任何数据库视图的名称时,出现以下异常:
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.forEach(DatabaseMetaData.java:2162)
at com.mysql.cj.jdbc.DatabaseMetaData.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
但我又得到了相同的 SQL异常 - 数组越界异常。
有什么想法吗?
额外
以下代码转储所有数据库 table 列,但在将视图引入架构后立即失败并出现相同的异常
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 错误吗?
更新
我的 POM 中给出的 JDBC 驱动程序是:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.27</version> </dependency>
metaData.getDriverVersion()
returns mysql-connector-java-8.0.27 (Revision: e920b979015ae7117d60d72bcc8f077a839cd791)
我也尝试过 8.0.21 和 5.1.49 版本,但它们的行为方式相同。
这是 运行 在 Windows 11 PC 上 Java 17.0.1
在上面的代码中,我突出显示了导致异常的行 - 它是创建我需要处理的结果的行(在我尝试读取任何列之前)
WRT 堆栈跟踪 - 我捕获的异常是
java.sql.SQLException
- 它没有包含在任何东西中。我正在与之交谈的数据库在 Raspberry Pi 上。详情如下:
- 版本: 10.3.23-MariaDB-0+deb10u1 (Raspbian 10)
- 编译用于: debian-linux-gnueabihf (armv7l)
错误似乎是一个协议问题(它期望的字节数比接收到的字节数多),并且鉴于您连接的是 MariaDB,而不是 MySQL,您应该使用 MariaDB Connector/J (版本 2.7.3)和协议前缀 jdbc:mariadb:
.
尽管 MariaDB 最初是 MySQL 的一个分支,但自从它被分支后就出现了分歧。