H2 具有自定义 Java 别名和多进程环境中的 javac 编译器问题



自定义函数别名定义为的 H2 数据库:

create alias to_date as $$
    java.util.Date toDate(java.lang.String dateString, java.lang.String pattern) {
        try {
          return new java.text.SimpleDateFormat(javaPattern).parse(dateString);
        } catch(java.text.ParseException e) {
          throw new java.lang.RuntimeException(e);
        }
      }
$$;

H2 初始化为:

jdbc:h2:mem:testdb;INIT=runscript from 'classpath:create_alias.sql

这用于测试,在 Jenkins 实例上同时为多个项目执行。有时此类测试会失败并显示以下错误:

Could not get JDBC Connection; nested exception is org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "javac: file not found: org/h2/dynamic/TO_DATE.java
Usage: javac <options> <source files>
use -help for a list of possible options
"; SQL statement:

create alias to_date as $$
    java.util.Date toDate(java.lang.String dateString, java.lang.String pattern) {
    ....

我的猜测是org.h2.util.SourceCompiler假设当时只有一个h2实例在运行,并将生成的Java源代码写入"java.io.tmpdir",该源代码在同一帐户下运行的所有进程之间共享。我建议以下解决方法:

Index: SourceCompiler.java
===================================================================
--- SourceCompiler.java (revision 5086)
+++ SourceCompiler.java (working copy)
@@ -40,7 +40,15 @@
      */
     final HashMap<String, Class<?>> compiled = New.hashMap();
-    private final String compileDir = Utils.getProperty("java.io.tmpdir", ".");
+    private final String compileDir;
+    
+    {
+       // use random folder under java.io.tmpdir so multiple h2 could compile at the same time
+       // without overwriting each other files
+       File tmp = File.createTempFile("h2tmp", ".tmp");
+       tmp.mkdir();
+       compileDir = tmp.getAbsolutePath();
+    }
     static {
         Class<?> clazz;

我应该打开支持票证还是有解决此问题的方法?

您可以使用javax.tools.JavaCompiler API并为内存中的JavaFileManager提供自己的实现,以完全避免创建这些临时文件。

顺便说一句,Janino 还支持 javax.tools.JavaCompiler API。

我在运行多个 Jenkins 执行器和使用 Arquillian/Wildfly/H2 集成测试配置时遇到了同样的问题。我通过在测试standalone.xml中将java.io.tmpdir属性设置为构建目录找到了解决方法。

最新更新