Java 内存数据库中的 h2 JdbcSQLSyntaxErrorException: Table "table_name" 未找到

Java h2 in memory database JdbcSQLSyntaxErrorException: Table "table_name" not found

我正在尝试使用内存数据库测试 JDBC 客户端,因此我可以使用单元测试来测试各种情况。

这是我目前的情况:

模型class(也包含构造函数)

@Entity
@Table(name = "table_name")
public class MyModel {

我有一个客户端 class,我想用它与 postgres 交互,使用 java.sql DriverManager 和 PreparedStatements。

public class MyModelClient {

    private final Connection con;

    public MyModelClient(String url, String user, String password) {
        try {
            con = DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            throw new RuntimeException("uh oh", e);
        }
    }

    public Connection getCon() {
        return con;
    }

    private static String ROWS = "\"uuid\", ...";

    private String insertMyModelQuery() {
        return "INSERT INTO table_name (" + MyModelClient.ROWS + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" +
        "ON CONFLICT(\"uuid\") DO UPDATE SET url=EXCLUDED.url RETURNING uuid;";
    }

    public void insertMyModel(MyModel article) {
        try (PreparedStatement preparedStatement = con.prepareStatement(this.insertMyModelQuery())) {
            preparedStatement.setObject(1, article.uuid);
            ...
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            throw new InsertMyModelException("failed to insert MyModel: " + e.toString(), e);
        }
    }
    
}

我有我想要的单元测试 运行。我希望它通过客户端连接到内存数据库,在测试设置时创建数据库,然后测试我的插入方法。

public class MyModelClientTest {

    static MyModelClient client;
    
    @BeforeAll
    public static void setUp() {
        client = new ArticleClient("jdbc:h2:mem:testdb;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE", "postgres", "mysecretpassword");
         String sql = "-- template"+
            "CREATE TABLE my_model_template ("+
            "    uuid UUID NOT NULL,"+
            ... +
            ");";
        String sql2 = "-- Create table"+
            "CREATE TABLE table_name"+
            "    (LIKE my_model_template)"+
            "    PARTITION BY RANGE (created_datetime);";
            
        try {
            Statement s=client.getCon().createStatement();
            s.execute(sql);
            s.execute(sql2);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void shouldInsertMyModel() {
        System.out.println("TEST---------------------");
        MyModel m = TestMyModelBuilder.build();
        client.insertMyModel(m);
    }
}

我期望发生的事情

设置方法创建 table。我的测试插入到 table

实际发生了什么

记录显示设置为 运行。测试是 运行,但插入失败,因为 table 显然不存在。

failed to insert MyModel: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "table_name" not found;

我的 application.properties 在测试目录中看起来像:

spring.datasource.url=jdbc:h2:mem:testdb;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=postgres
spring.datasource.password=mysecretpassword
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.defer-datasource-initialization=true

当您在 application.properties 文件中使用了错误的方言,或者您验证了错误的数据库时,就会发生这种情况。例如,当你 运行 你的应用程序针对本地 H2 数据库时,最好的选择是删除方言,因为 Hibernate 可以在没有这个 属性 的情况下识别数据库(如果 Hibernate 的版本足够新识别较新的数据库)。另一种解决方案是删除 validate 属性,但我不建议这样做,因为您在启动时没有进行数据库检查:

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update

您对 SQL 的评论中缺少 \n。现在整个 SQL 语句被解释为注释,因此不会执行任何内容。

String sql = "-- template\n"+
            "CREATE TABLE my_model_template ("+
            "    uuid UUID NOT NULL,"+
            ... +
            ");";

类似的东西,或者如果您使用的是较新版本的 Java,您甚至可以使用文本块。

String sql = """-- template
          CREATE TABLE my_model_template (
              uuid UUID NOT NULL,"+
          ... 
          );""";

这适用于 Java 15(启用实验性功能)或 Java 17 或更高版本。