H2嵌入式模式下Trigger类找不到问题及Maven类路径配置咨询
H2触发器类找不到问题解决(VSCode Maven项目)
问题场景
创建了继承org.h2.api.Trigger的自定义触发器类com.gamebad.storagemanager.data.triggers.MyTrigger,执行以下SQL创建触发器:
CREATE TABLE IF NOT EXISTS TEST(NAME CHARACTER VARYING(255)) CREATE TRIGGER IF NOT EXISTS MY_TRIGGER ON TEST BEFORE INSERT FOR EACH ROW CALL 'com.gamebad.storagemanager.data.triggers.MyTrigger'
在VSCode中直接运行Maven项目时,出现类找不到错误:
org.h2.jdbc.JdbcSQLSyntaxErrorException: Error creating or initializing trigger "MY_TRIGGER" object, class "com.gamebad.storagemanager.data.triggers.MyTrigger", cause: "org.h2.message.DbException: Class ""com.gamebad.storagemanager.data.triggers.MyTrigger"" not found [90086-224]"; see root cause for details; SQL statement: CREATE TRIGGER IF NOT EXISTS "PUBLIC"."MY_TRIGGER" BEFORE INSERT ON "PUBLIC"."TEST" FOR EACH ROW CALL "com.gamebad.storagemanager.data.triggers.MyTrigger" [90043-232] at com.h2database@2.3.232/org.h2.message.DbException.getJdbcSQLException(DbException.java:644) at com.h2database@2.3.232/org.h2.engine.SessionRemote.readSQLException(SessionRemote.java:663) at com.h2database@2.3.232/org.h2.engine.SessionRemote.readException(SessionRemote.java:646) at com.h2database@2.3.232/org.h2.engine.SessionRemote.done(SessionRemote.java:620) at com.h2database@2.3.232/org.h2.command.CommandRemote.executeUpdate(CommandRemote.java:225) at com.h2database@2.3.232/org.h2.jdbc.JdbcPreparedStatement.execute(JdbcPreparedStatement.java:262) at com.gamebad.storagemanager/com.gamebad.storagemanager.data.DatabaseController.lambda$6(DatabaseController.java:117) at com.gamebad.storagemanager/com.gamebad.storagemanager.data.DatabaseController.lambda$2(DatabaseController.java:81) at com.gamebad.storagemanager/com.gamebad.storagemanager.data.DatabaseController.execute(DatabaseController.java:65) at com.gamebad.storagemanager/com.gamebad.storagemanager.data.DatabaseController.execute(DatabaseController.java:78) at com.gamebad.storagemanager/com.gamebad.storagemanager.data.DatabaseController.execute(DatabaseController.java:76) at com.gamebad.storagemanager/com.gamebad.storagemanager.data.DatabaseController.execute(DatabaseController.java:75) at com.gamebad.storagemanager/com.gamebad.storagemanager.data.DatabaseController.execute(DatabaseController.java:117) at com.gamebad.storagemanager/com.gamebad.storagemanager.Main.test(Main.java:49) at com.gamebad.storagemanager/com.gamebad.storagemanager.Main.main(Main.java:172)
但将项目打包为包含所有依赖的单个Jar包后运行正常,能正确加载触发器类。
原因
VSCode直接运行项目时,H2的类加载器与应用程序的类加载器隔离,无法访问到项目编译后的自定义触发器类;而打包成fat jar后,所有类都在同一Jar包内,类加载器能统一加载所有类。
解决方案
1. 使用Maven exec插件统一类路径
在pom.xml中添加exec-maven-plugin配置,确保运行时类路径包含项目编译类和所有依赖:
<build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>3.1.0</version> <configuration> <!-- 替换为你的主类全路径 --> <mainClass>com.gamebad.storagemanager.Main</mainClass> <includeProjectDependencies>true</includeProjectDependencies> <includePluginDependencies>false</includePluginDependencies> <classpathScope>compile</classpathScope> </configuration> </plugin> </plugins> </build>
配置完成后,在VSCode的Maven面板中执行exec:java命令运行项目,而非直接运行Main类。
2. 指定H2使用应用类加载器
在建立H2连接时,添加CLASS_LOADER参数,指定H2使用应用中的某个类的类加载器来加载触发器:
// 替换为你的H2连接URL,CLASS_LOADER值为主类全路径 String url = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;CLASS_LOADER=com.gamebad.storagemanager.Main"; Connection conn = DriverManager.getConnection(url, "sa", "");
3. 查看当前运行类路径
如果需要验证类路径是否正确,可在代码中添加以下代码打印当前类路径:
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); if (contextClassLoader instanceof URLClassLoader urlClassLoader) { for (URL url : urlClassLoader.getURLs()) { System.out.println("类路径项: " + url.getFile()); } }
也可以在VSCode的运行配置中添加-verbose:class参数,启动时会打印所有类的加载来源,方便排查类加载问题。
内容的提问来源于stack exchange,提问作者Ibrahim Rashwan El-Gebaly
相关产品推荐
相关产品推荐

