我正在尝试使用 JDBC 和 mysql-connector-java 在带有 Graalvm 的图像上执行基本的 SQL 查询(问题的原因)。
显然每个尝试将 GraalVM 与 JDBC/MySQL 和 Docker 结合使用的人每次都会遇到同样的问题。
我遇到以下异常
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.mysql.cj.Constants.<clinit>(Constants.java:49)
at com.mysql.cj.util.Util.<clinit>(Util.java:67)
at com.mysql.cj.conf.ConnectionUrl$Type.getImplementingInstance(ConnectionUrl.java:241)
at com.mysql.cj.conf.ConnectionUrl$Type.getConnectionUrlInstance(ConnectionUrl.java:211)
at com.mysql.cj.conf.ConnectionUrl.getConnectionUrlInstance(ConnectionUrl.java:280)
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:195)
at java.sql.DriverManager.getConnection(DriverManager.java:681)
at java.sql.DriverManager.getConnection(DriverManager.java:229)
at com.me.test.Main.testJDBC(Main.java:73)
at com.me.test.Main.main(Main.java:94)
Caused by: java.lang.RuntimeException: Can't load resource bundle due to underlying exception java.util.MissingResourceException: Can't find bundle for base name com.mysql.cj.LocalizedErrorMessages, locale en_US
at com.mysql.cj.Messages.<clinit>(Messages.java:60)
... 10 more
Caused by: java.util.MissingResourceException: Can't find bundle for base name com.mysql.cj.LocalizedErrorMessages, locale en_US
at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:2045)
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1683)
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1586)
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1549)
at java.util.ResourceBundle.getBundle(ResourceBundle.java:858)
at com.mysql.cj.Messages.<clinit>(Messages.java:58)
... 10 more
我的 Dockerfile
FROM ghcr.io/graalvm/graalvm-ce:latest
RUN gu install native-image
WORKDIR /tmp/dist
ADD ./app.jar ./app.jar
COPY ./reflect-config.json ./reflect-config.json
RUN native-image -jar ./app.jar --verbose --no-fallback
RUN microdnf install zip
ADD bootstrap bootstrap
RUN chmod +x bootstrap
RUN chmod +x ./app
RUN zip -j function.zip bootstrap app
ENTRYPOINT ["./app"]
我的 pom 文件中的依赖项
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>21.5.0.0</version>
</dependency>
最后是我的java代码:
public void testJDBC() throws SQLException, IOException {
String url = "jdbc:mysql://foo.blabla.aws-region.rds.amazonaws.com:3306/database";
String user = "root";
String password = "password";
try(java.sql.Connection conn = java.sql.DriverManager.getConnection(url, user, password)){
doSomething(conn);
}
}
编辑1:
我遵循了 Mark Rotteveel 的建议,并添加了一个 “resource-config.json” 文件,其中包含以下内容:
{
"resources": {
"includes": [
{"pattern": "com.mysql.cj.LocalizedErrorMessages.properties"}
]
}
}
并在“native-image.properties”文件中添加以下内容
Args = -H:EnableURLProtocols=http,https -H:ReflectionConfigurationFiles=/tmp/dist/reflect-config.json -H:ResourceConfigurationFiles=/tmp/dist/resource-config.json
修复了当前错误,但正如预期的那样,我们有了一个新错误:
Exception in thread "main" java.lang.ClassCastException: com.mysql.cj.exceptions.CJException cannot be cast to com.mysql.cj.exceptions.WrongArgumentException
at com.mysql.cj.util.Util.getInstance(Util.java:169)
at com.mysql.cj.util.Util.getInstance(Util.java:174)
at com.mysql.cj.conf.ConnectionUrl$Type.getImplementingInstance(ConnectionUrl.java:241)
at com.mysql.cj.conf.ConnectionUrl$Type.getConnectionUrlInstance(ConnectionUrl.java:211)
at com.mysql.cj.conf.ConnectionUrl.getConnectionUrlInstance(ConnectionUrl.java:280)
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:195)
at java.sql.DriverManager.getConnection(DriverManager.java:681)
at java.sql.DriverManager.getConnection(DriverManager.java:229)
at com.me.test.Main.testJDBC(Main.java:77)
at com.me.test.Main.main(Main.java:98)
编辑2:
我在文件“reflect-config.json”中配置了以下内容
[
{
"name": "com.mysql.cj.conf.url.SingleConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.FailoverDnsSrvConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.LoadBalanceDnsSrvConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.ReplicationDnsSrvConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.XDevApiDnsSrvConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.FailoverConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.LoadBalanceConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.conf.url.ReplicationConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
}, {
"name": "com.mysql.cj.conf.url.XDevApiConnectionUrl",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.log.Jdk14Logger",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.log.NullLogger",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.log.Slf4JLogger",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.cj.log.StandardLogger",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.mysql.jdbc.Driver",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"name":"oracle.jdbc.OracleDriver",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"oracle.jdbc.driver.T4CDriverExtension",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name" : "oracle.jdbc.driver.T2CDriverExtension",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"oracle.net.ano.Ano",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"oracle.net.ano.AuthenticationService",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"oracle.net.ano.DataIntegrityService",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"oracle.net.ano.EncryptionService",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"oracle.net.ano.SupervisorService",
"methods":[{"name":"<init>","parameterTypes":[] }]
}
]
但由于某种原因出现连接错误(使用 AWS RDS 和 host.docker.internal 进行测试)。
Exception in thread "main" java.sql.SQLNonTransientConnectionException: Cannot connect to MySQL server on foo.blabla.aws-region.rds.amazonaws.com:3,306.
Make sure that there is a MySQL server running on the machine/port you are trying to connect to and that the machine this software is running on is able to connect to this host/port (i.e. not firewalled). Also make sure that the server has not been started with the --skip-networking flag.
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:110)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:73)
at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:462)
at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:241)
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:198)
at java.sql.DriverManager.getConnection(DriverManager.java:681)
at java.sql.DriverManager.getConnection(DriverManager.java:229)
at com.me.test.Main.testJDBC(Main.java:104)
at com.me.test.Main.main(Main.java:125)
Caused by: java.lang.ClassCastException: com.mysql.cj.exceptions.CJException cannot be cast to com.mysql.cj.exceptions.UnableToConnectException
at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:825)
at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:448)
... 6 more
此错误仅在使用 “ghcr.io/graalvm/graalvm-ce:latest” 时发生,如果我使用其他虚拟机,例如 “amazoncorretto:18-alpine” 一切都很完美。
完整源代码:https://github.com/ederbaum/MySQLGraalVM
有什么可行的解决办法吗?