如何在可执行JAR内部连接内嵌的Apache Derby数据库JAR包
解决方案
核心原因
你硬编码的src/main/resources/dbs.jar是开发阶段的本地文件系统路径,可执行JAR打包完成后,dbs.jar是嵌套在JAR内部的类路径资源,不属于文件系统上的独立文件,而Derby默认的jar:协议仅支持读取文件系统中独立存在的JAR包,无法直接识别嵌套JAR的内部资源路径。
方案1:运行时解压数据库JAR到临时目录(兼容性最强,支持读写)
这是最稳妥的实现方式,不需要依赖特殊类加载器,同时支持对数据库的读写操作:
- 首先将嵌套在内部的dbs.jar资源读取后写入到系统临时目录
- 用临时目录下dbs.jar的绝对路径构造JDBC连接字符串
示例代码:
public static void queryDatabase() throws IOException { // 读取classpath下的dbs.jar资源,注意替换为你实际的类名 InputStream dbJarIn = YourClassName.class.getResourceAsStream("/dbs.jar"); if (dbJarIn == null) { throw new IOException("未找到内嵌的数据库JAR资源"); } // 创建临时文件 File tempDbJar = File.createTempFile("dbs", ".jar"); tempDbJar.deleteOnExit(); // JVM退出时自动删除临时文件 // 写入临时文件 try (FileOutputStream out = new FileOutputStream(tempDbJar)) { byte[] buffer = new byte[1024]; int len; while ((len = dbJarIn.read(buffer)) != -1) { out.write(buffer, 0, len); } } finally { dbJarIn.close(); } // 构造正确的连接字符串 String connectionUrl = String.format("jdbc:derby:jar:(%s)employees", tempDbJar.getAbsolutePath()); try (Connection conn = DriverManager.getConnection(connectionUrl)) { RowSetFactory factory = RowSetProvider.newFactory(); CachedRowSet cachedRowSet = factory.createCachedRowSet(); cachedRowSet.setCommand("select id,salary,filingStatus from employees"); cachedRowSet.execute(conn); while (cachedRowSet.next()) { System.out.print(cachedRowSet.getString("id") + " "); System.out.print(cachedRowSet.getFloat("salary") + " "); System.out.println(cachedRowSet.getString("filingStatus")); } } catch (SQLException exception) { exception.printStackTrace(); } }
方案2:使用Derby的classpath协议(仅支持只读场景)
如果你的数据库仅用于查询不需要写入,可以直接用Derby内置的classpath路径前缀,不需要写具体JAR路径,Derby会自动在整个类路径中查找数据库:
// 直接使用classpath前缀,employees是数据库名 String connectionUrl = "jdbc:derby:classpath:employees";
这个方案的前提是dbs.jar被正确包含在可执行JAR的类路径中,Maven打包后resources下的文件默认都会放到类路径根目录,符合要求。
IDE运行正常的原因说明
IDE运行时会将src/main/resources目录作为文件系统目录直接加入类路径,此时dbs.jar是独立存在的磁盘文件,所以硬编码的路径可以正常识别,打包后资源被嵌套进JAR,路径就失效了。
内容的提问来源于stack exchange,提问作者kyleryan1291
相关产品推荐
相关产品推荐

