【问题标题】:Embedding an H2 Database within the WEB-INF Directory在 WEB-INF 目录中嵌入 H2 数据库
【发布时间】:2015-05-30 18:06:30
【问题描述】:

我有一个嵌入式 H2 数据库,我想将其放入 Web 应用程序的 WEB-INF 目录中。

在 JDBC url 中引用它的正确方法是什么?

理想情况下,我想要一个既适用于 WAR,又适用于扩展 WAR(如果可能)的解决方案。

感谢您的帮助!

仅供参考,我尝试了以下方法:

jdbc:h2:/WEB-INF/data/myDB;CIPHER=AES

但这会导致:

org.h2.jdbc.JdbcSQLException: A file path that is implicitly relative to the current working directory is not allowed in the database URL "jdbc:h2:/WEB-INF/data/myDB;CIPHER=AES". Use an absolute path, ~/name, ./name, or the baseDir setting instead. [90011-187]

将其更改为: jdbc:h2:./WEB-INF/data/myDB;CIPHER=AES

导致以下错误,这清楚地表明它试图将我的数据库放在 Tomcat 的 bin 目录中,而不是我想要的真正的 WEB-INF 目录中:

org.h2.jdbc.JdbcSQLException: Error while creating file "C:/Program Files/Apache Software Foundation/Tomcat 7.0/bin/WEB-INF" [90062-187]

【问题讨论】:

  • 根据您需要支持的应用程序服务器,您应该小心将文件放入 webinf。 Websphere 在这方面非常挑剔。你写入数据库还是只读的?最好允许将数据库存储在单独的目录中并允许配置路径
  • 它是只读的,只能部署在Tomcat上,最好是WAR格式。
  • 程序文件不允许写入,换个路径试试
  • 我知道我不允许在 Program Files 中写入。 WEB-INF 目录也不在 Tomcat 的 bin 目录下。我显示错误的重点是相对路径没有达到预期的效果。
  • 如果你的例子符合现实不会有什么坏处;-)

标签: jdbc h2 web-inf


【解决方案1】:

我设法使嵌入式解决方案在没有 AES 的情况下像这样工作:

try {
    Class.forName("org.h2.Driver");
    Connection conn = DriverManager.getConnection(
        "jdbc:h2:" + getServletContext().getRealPath("/") + 
        "/WEB-INF/data/myDB", "sa", "");
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("SELECT * FROM INFORMATION_SCHEMA.TABLES");
    while (rs.next()) {
    }
    rs.close();
    stmt.close();
    conn.close();
} catch(SQLException e) {
} catch(ClassNotFoundException e) {
} finally {
}

这是在 Tomcat8 上使用 H2 1.3.176 测试的。它应该与 H2 1.4 和 CIPHER=AES 一起使用,前提是嵌入式数据库已经在我猜的 war 文件中。

思路如下:你需要获取绝对路径,而部署路径可能不一样,具体取决于你部署war文件的方式。

所以我们需要使用 servlet 上下文并请求真实路径。为此,我们使用getServletContext().getRealPath("/") 并根据您的需要附加/WEB-INF/data/myDB

我没有测试CIPHER=AES 部分,因为我从未使用过它。

更新:

获得对 servlet 上下文的良好引用是很棘手的。可以使用原始请求,获取底层会话,然后进入 servlet 上下文。

但最好在应用程序在 Tomcat 中部署/启动后立即打开嵌入式 H2 数据库,并在应用程序停止后立即正确关闭。

为了执行此操作,需要使用侦听器。这是我提出的更新我之前答案的建议。这次解决方案是完整的 AES CIPHER,应该很容易插入到您的代码中。

建议:监听java代码也可以很方便的修改启动H2 tcp服务器,对开启自动混合模式(embedded+tcp)很有用。

在 web.xml 文件中添加 3 行:

<listener>
  <listener-class>com.mine.MyServletContextListener</listener-class>
</listener>

文件 MyServletContextListener.java:

package com.mine;

import javax.servlet.*;
import java.sql.*;

public class MyServletContextListener implements ServletContextListener {
  Connection conn;

  public void contextInitialized(ServletContextEvent sce) {

    try {
      Class.forName("org.h2.Driver");
      conn = DriverManager.getConnection( "jdbc:h2:" + sce.getServletContext().getRealPath("/") + "/WEB-INF/data/myDB;CIPHER=AES", "sa", "aespassword dbpassword");
      Statement stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery("SELECT * FROM INFORMATION_SCHEMA.TABLES");
      while (rs.next()) {
      }
      rs.close();
      stmt.close();
    } catch(SQLException e) {
    } catch(ClassNotFoundException e) {
    } finally {
    }

  }

  public void contextDestroyed(ServletContextEvent sce) {

    try {
      conn.close();
    } catch(SQLException e) {
    } finally {
    }

  }

}

【讨论】:

  • @Doug:最后我没有用servlet进入tcp模式。我想这会让你在使用嵌入式模式时获得更好的表现,无论战争在哪里展开。
  • @Doug 你测试过我建议的修复方法吗?
  • @Doug 请确保将此代码放在扩展 HttpServlet 的类中,否则 getServletContext() 将不可用。由于我没有您的代码的完整视图,您的里程可能会有所不同......
  • @Doug 我修复了如何在不使用请求的情况下获取 servlet 上下文,而是使用侦听器。
  • 对不起,我刚刚回到这个:-)。我通过将数据库放在内存中暂时解决了这个问题,但我将切换到上下文侦听器选项。这绝对是我正在寻找的更多内容,但是我在网上找到的 Context Listener 示例仍然无法处理 WEB-INF 数据库。感谢您花时间整理出一个很好的答案!
猜你喜欢
  • 2017-03-05
  • 1970-01-01
  • 2016-01-22
  • 1970-01-01
  • 2023-03-19
  • 2022-01-20
  • 2011-05-22
  • 2012-10-22
  • 2018-06-13
相关资源
最近更新 更多