如果运行战争,oracle 和 sybase 数据库连接会出现 ClassNotFoundError,但在 eclipse 中工作正常

Ser*_*sly 5 java sql-server oracle sybase spring

我在应用程序中构建了一个功能来测试数据库连接。在本地,我能够测试所有三个数据库 sqlserver、sybase 和 oracle。但如果创建 war 文件并在 Windows/Linux 服务器中运行 war,则 Oracle 和 sybase 会出现上述错误。如果我删除 oracle 或 sybase 代码和依赖项,那么其他人工作正常。\n我已在 /web-inf/lib/ 内签入 war 文件,它有 jtds、ojdbc8 和 jconnect4 lib/dependency\noracle conn 代码

\n
            Class.forName("oracle.jdbc.driver.OracleDriver");\n            connection = DriverManager.getConnection(jdbcUrl, username, password);\n\n
Run Code Online (Sandbox Code Playgroud)\n

Sybase 连接代码

\n
import com.sybase.jdbc4.jdbc.SybDataSource;\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\npublic class SybaseConnectionManager {\n    public static Connection getSybaseConnection(String serverName, String databaseName, String userName, String password, String url) throws DataGeneratorException {\n        SybDataSource ds = new SybDataSource();\n\n        try {\n            ds.setServerName(serverName);\n            ds.setDatabaseName(databaseName);\n            ds.setUser(userName);\n            ds.setPassword(password);\n\n            // Splitting URL by semicolon\n            String[] params = url.split(";");\n            for (String param : params) {\n                String[] props = param.split("=");\n                switch (props[0].toUpperCase()) {\n                    case "PORT":\n                        ds.setPortNumber(Integer.parseInt(props[1]));\n                        break;\n                    case "ENCRYPT_PASSWORD":\n                        ds.setENCRYPT_PASSWORD(props[1]);\n                        break;\n                    case "RETRY_WITH_NO_ENCRYPTION":\n                        ds.setRETRY_WITH_NO_ENCRYPTION(props[1]);\n                        break;\n                    case "JCE_PROVIDER_CLASS":\n                        ds.setJCE_PROVIDER_CLASS(props[1]);\n                        break;\n                }\n            }\n\n            // Get the connection\n            Connection con = ds.getConnection();\n            con.setAutoCommit(false);\n            return con;\n        } catch (SQLException e) {\n            log.error("Handling Sybase Exception", e);\n            throw new DataGeneratorException(e.getMessage());\n        }\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

以下错误来自我测试 oracle 数据库连接时

\n
2023-09-13104:19:14,724Z (UTC+0) [http-nio-9091-exec-7] ERROR o.a.c.c.C.[.[.[. [dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [/testapp] threw exception [handler dispatch failed; nested execption is java.lang.NoClassDefFoundError: could not initialize class oracle.jdbc.OracleDriver] with root cause\njava.lang-ExceptionInInitializerError: Exception java.lang.StackOverflowError [in thread "http-nio-9091-exec-1"]\nat java.base/java.security.AccessController.doPrivileged(Native Method)\nat java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:451)\nat java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)\nat org-springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)\nat java.base/java.lang.Classloader.loadClass(ClassLoader.java:521)\nat java.base/java.lang.ClassLoader.defineClassl(Native Method)\nat java.base/java.lang.ClassLoader.defineClass(Classloader.java:1016)\nat java.base/java.security.SecureClassloader.defineClass(SecureClassLoader.java:174)\nat java.base/java.net.URLClassloader.defineClass(URLClassLoader.java:555)\nat java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:458)\nat java.base/java.net.URLClassloader$1.run(URLClassLoader.java:452)\nat java.base/java.security.AccessController.doPrivileged(Native Method)\nat java.base/java.net.URLClassloader.findClass(URLClassLoader \xe2\x80\xa2Java:451)\nat java. base/ java lang ClassLoader. loadClass(ClassLoader. java: 588)\nat org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)\nat java.base/java.lang.Classloader.loadClass(ClassLoader.java:521)\nat java.base/java.lang.ClassLoader.defineClass1(Native Method)\nat java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)\nat java.base/java.security.SecureClassLoader.defineClass(SecureClassloader.java:174)\nat java.base/java.net.URLClassLoader.defineClass(URLClassloader.java:555)\nat java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:458)\nat java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:452)\nat java.base/java.security.AccessController.doPrivileged(Native Method)\nat java.base/java.net.URLClassloader.findClass(URLClassLoader.java:451)\nat java.base/java.lang.Classloader.loadClass(ClassLoader. java:588)\nat org-springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURlClassloader.java:151)\nat java.base/java.lang.ClassLoader.loadClass(Classloader.java:521)\nat java.base/java.lang.ClassLoader.defineClassi(Native Method)\nat java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)\nat java.base/java.security.SecureClassloader.defineClass(SecureClassloader.java:174)\nat java.base/java.net.URLClassloader.defineClass(URLClassLoader.java:555)\nat java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:458)\nat java .base/java.net.URLClassLoader$1.run(URLClassLoader.java:452)\nat iava.base/iava.security.AccessController.doPrivileged(Native Method)\n
Run Code Online (Sandbox Code Playgroud)\n

当我也在测试 sybase conn 时,它说相同的 classnotfounderror,无法初始化类 com.sybase.jdbc4.jdbc.sybdriver\n 对于 oracle,我使用 ojdbc8 对于 sybase jconnect4\n 如果我删除,则会出现 1 个更奇怪的事情sybase conn 和依赖项 oracle 的代码工作正常,反之亦然\n两者不能一起工作,我猜会发生冲突,但不确定如何解决它

\n

Ish*_*han 1

通过聊天继续讨论...

\n

问题似乎是同时使用了 2 个数据库驱动程序。\nDriverManager.getConnection()调用时,似乎无法获取必须使用哪个驱动程序。理想情况下应该如此。第一个参数“url”告诉该getConnection方法应使用哪个驱动程序。\n不过,如果仅检查一个数据库连接,并且仅保留一个驱动程序,则它可以工作。一旦添加了 2 个驱动程序并尝试检查这两个驱动程序,则两个驱动程序之一都会失败。这似乎是错误的。这应该可以正常工作。但仍然没有。

\n

理想情况下,应该找到其根本原因。但如果没有,另一种选择是使用小型控制台应用程序。每个数据库一个。

\n
java -cp ojdbc8.jar -jar oraclechecker.jar\n
Run Code Online (Sandbox Code Playgroud)\n

\n
java -cp sybase.jar -jar sybasechecker.jar\n
Run Code Online (Sandbox Code Playgroud)\n

这些可以像这样调用和测试。这将导致单独的 JVM 初始化 - 每个初始化都有一个不同的数据库驱动程序,而且只有一个。

\n

主Web应用程序可以使用

\n
Process p = Runtime.getRuntime().exec("java", "-cp", "ojdbc8.jar", "-jar", "oraclechecker.jar");\n
Run Code Online (Sandbox Code Playgroud)\n

像这样的命令将它们称为外部命令。\nWeb 应用程序本身不需要任何数据库驱动程序。

\n

这只是其中一种可能性...

\n

检查以下问题:\n如何在同一应用程序中使用多个 JDBC 驱动程序?

\n

它还表示 2 个不同的数据库驱动程序可以并行工作。第一个参数urlDriverManager.getConnection确定使用哪个驱动程序。例如jdbc:mysql:jdbc:oracle:thin:

\n

我也在本地 Tomcat 10 中尝试了相同的操作。创建了一个testdb.jsp

\n
<%@page import="java.sql.ResultSet"%>\n<%@page import="java.sql.PreparedStatement"%>\n<%@page import="java.sql.DriverManager"%>\n<%@page import="java.sql.Connection"%>\n<html>\n<body>\n    <pre>\n<%\n    Class.forName("oracle.jdbc.OracleDriver");\n    Class.forName("com.mysql.cj.jdbc.Driver");\n\n    String[][] connDetails = { { "jdbc:mysql://localhost:3306/test", "xxxxx", "xxxxx", "SELECT CURRENT_TIMESTAMP()" },\n            { "jdbc:oracle:thin:@xxxxx:xxxxx/xxxxx", "xxxxx", "xxxxx", "SELECT CURRENT_TIMESTAMP FROM DUAL" } };\n\n    for (String[] cd : connDetails) {\n        try (Connection conn = DriverManager.getConnection(cd[0], cd[1], cd[2])) {\n            out.println("Connected successfully to " + cd[0]);\n            try (PreparedStatement stmt = conn.prepareStatement(cd[3]); ResultSet rs = stmt.executeQuery()) {\n                while (rs.next()) {\n                    out.println("\\t" + rs.getTimestamp(1));\n                }\n            }\n        } catch (Exception x) {\n            out.println("Error: " + x);\n        }\n    }\n%>\n    </pre>\n</body>\n</html>\n
Run Code Online (Sandbox Code Playgroud)\n
D:\\apache-tomcat-10.1.8\\webapps\\ROOT>tree /F\nFolder PATH listing for volume Data\nVolume serial number is XXXXX\nD:.\n\xe2\x94\x82   index.jsp\n\xe2\x94\x82   RELEASE-NOTES.txt\n\xe2\x94\x82   testdb.jsp\n\xe2\x94\x82\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80WEB-INF\n    \xe2\x94\x82   web.xml\n    \xe2\x94\x82\n    \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80lib\n            mysql-connector-j-8.0.33.jar\n            ojdbc11.jar\n
Run Code Online (Sandbox Code Playgroud)\n

启动了雄猫。调用 http://localhost:8080/testdb.jsp 会导致:

\n
Connected successfully to jdbc:mysql://localhost:3306/test\n    2023-09-14 12:28:51.0\nConnected successfully to jdbc:oracle:thin:@xxxxx:xxxxx/xxxxx\n    2023-09-14 12:29:08.360942\n
Run Code Online (Sandbox Code Playgroud)\n