如何修复 Apache Ignite 中的 "Could not initialize class org.apache.ignite.IgniteJdbcThinDriver" 错误?

How to fix "Could not initialize class org.apache.ignite.IgniteJdbcThinDriver" error in Apache Ignite?

问题

我正在尝试使用 Apache Ignite 内置工具 SQLLine 连接到 Apache Ignite 服务器。我收到错误:java.lang.NoClassDefFoundError: Could not initialize class org.apache.ignite.IgniteJdbcThinDriver

背景

我在一个容器中安装了 Apache Ignite 运行,在另一个容器中安装了 CentOS7 运行。同一网络中的两个容器 运行(双向 ping 都有效)。尝试过的连接是从 CentOS7 到 Apache Ignite。

Apache Ignite 似乎 运行 仅使用默认配置就可以了。在 CentOS7 容器中,我安装了 Oracle JDK 12.0.1 并且我在一个文件夹中有 Apache Ignite 2.7.0 二进制文件.我还设置了 IGNITE_HOME 环境变量。

在这里,(https://apacheignite-sql.readme.io/docs/sqlline),它说我可以连接到我的集群:./sqlline.sh --verbose=true -u jdbc:ignite:thin://127.0.0.1/。但是,这会引发前面提到的错误。

SQLLine 应随 Ignite JDBC 驱动程序一起提供。我试过手动下载它们 (https://apacheignite-sql.readme.io/docs/jdbc-driver#section-multiple-endpoints)。当我下载据说是 ignite-core-{version}.jar 的驱动程序时,我把它放在与 sqlline.jar 个文件相同的文件夹中。

输出

[root@bc72c4fbf47e bin]# ./sqlline.sh
sqlline version 1.3.0
sqlline> !connect jdbc:ignite:thin://172.19.0.2/
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.apache.ignite.internal.util.GridUnsafe (file:/var/tmp/apache-ignite/libs/ignite-core-2.7.0.jar) to field java.nio.Buffer.address
WARNING: Please consider reporting this to the maintainers of org.apache.ignite.internal.util.GridUnsafe
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
java.lang.NoClassDefFoundError: Could not initialize class org.apache.ignite.IgniteJdbcThinDriver
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:415)
    at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:555)
    at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:547)
    at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:449)
    at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:426)
    at sqlline.SqlLine.findRegisteredDriver(SqlLine.java:1568)
    at sqlline.SqlLine.scanForDriver(SqlLine.java:1542)
    at sqlline.Commands.connect(Commands.java:1074)
    at sqlline.Commands.connect(Commands.java:1001)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at sqlline.ReflectiveCommandHandler.execute(ReflectiveCommandHandler.java:38)
    at sqlline.SqlLine.dispatch(SqlLine.java:791)
    at sqlline.SqlLine.begin(SqlLine.java:668)
    at sqlline.SqlLine.start(SqlLine.java:373)
    at sqlline.SqlLine.main(SqlLine.java:265)

结论

我应该能够在 sqlline 中使用 !connect jdbc:ignite:thin://172.19.0.2/ 命令连接到我的 Ignite 服务器。 这不起作用,并抛出 Could not initialize class org.apache.ignite.IgniteJdbcThinDriver IgniteJDBCThinDriver 是 installed/available.

建议使用 Java 8,因为 Apache Ignite 2.7.0 没有完整的 Java 12 支持。否则你可以尝试 tinkering with JVM options.

谢谢@alamar,成功了!

我卸载了用 RPM 安装的 JDK12。 查看包名: rpm -qa | grep jdk。 删除包: rpm -e jdk-12.0.1-12.0.1-ga.x86_64.

我在一个孤立的系统上工作,所以我从另一台机器上下载并传输了 JDK8.rpm。 安装 JDK8: rpm -ihv jdk-8u211-linux-x64.rpm.

现在当我运行: ./sqlline.sh --verbose=true -u jdbc:ignite:thin://172.19.0.2, 我得到: issuing: !connect jdbc:ignite:thin://172.19.0.2/ '' '' org.apache.ignite.IgniteJdbcTh Connecting to jdbc:ignite:thin://172.19.0.2/ Connected to: Apache Ignite (version 2.7.0#20181130-sha1:256ae401) Driver: Apache Ignite Thin JDBC Driver (version 2.7.0#20181130-sha1:256ae401) Autocommit status: true Transaction isolation: TRANSACTION_REPEATABLE_READ sqlline version 1.3.0.

我现在可以查询我的数据库了。

我在以下非常奇怪的情况下遇到了这个错误:

我的 Maven java 项目的依赖项有 Apache-Ignite 作为依赖项。当我在无效路径(例如文件夹 ./result 不存在的 ./result/r.sqlite 中打开与 SQLite 数据库的连接时)发生此错误(使用驱动程序 org.xerial.sqlite-jdbc:v3.30.1.)所以这个调用

Class.forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection("jdbc:sqlite:result.sqlite")

将导致此堆栈跟踪:

Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class org.apache.ignite.IgniteJdbcThinDriver
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:398)
    at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:555)
    at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:674)
    at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:251)
    at MyClass.myMethod(MyClass.java:154)

所以解决方案显然是确保文件夹存在于应该创建 sqlite 数据库的位置。

添加 JVM 参数

--add-opens java.base/java.nio=ALL-UNNAMED

帮我解决了问题。