如果Java生产代码中不存在并在JUnit中确认,则创建数据库表

时间:2012-08-10 21:11:53

标签: java sql jdbc junit

我正在用Java编写数据库程序,并且想要创建一个表(如果它还不存在)。我从How can I detect a SQL table's existence in Java?了解了DatabaseMetaData.getTables(),我正在尝试使用它:

private boolean tableExists() throws SQLException {
    System.out.println("tableExists()");

    DatabaseMetaData dbmd = conn.getMetaData();
    ResultSet rs = dbmd.getTables(null, null, this.getTableName(), null);

    System.out.println("TABLE_NAME: " + rs.getString("TABLE_NAME"));

    return rs.getRow() == 1;
}

问题是rs.getRow()总是返回0,即使在创建表之后也是如此。使用rs.getString("TABLE_NAME")会抛出一个异常,指出结果集为空。

我想到的一个可能的解决方案是执行CREATE TABLE语句并捕获所引发的任何异常。但是,我不喜欢在程序的控制流程中使用异常的想法。

FWIW,我正在使用HSQLDB。但是,我想编写独立于RDMS引擎的Java代码。还有另一种方法可以使用DatabaseMetaData.getTables()来做我想做的事吗?或者是否有其他解决方案来编写我的tableExists()方法?

加了:

使用此处给出的建议,我找到了一个似乎适用于我的生产代码的解决方案:

private void createTable() throws SQLException {
    String sqlCreate = "CREATE TABLE IF NOT EXISTS " + this.getTableName()
            + "  (brand           VARCHAR(10),"
            + "   year            INTEGER,"
            + "   number          INTEGER,"
            + "   value           INTEGER,"
            + "   card_count           INTEGER,"
            + "   player_name     VARCHAR(50),"
            + "   player_position VARCHAR(20))";

    Statement stmt = conn.createStatement();
    stmt.execute(sqlCreate);
}

现在我也在编写一个JUnit测试来断言表确实已经创建了:

public void testConstructor() throws Exception {
    try (BaseballCardJDBCIO bcdb = new BaseballCardJDBCIO(this.url)) {
        String query = "SELECT count(*) FROM information_schema.system_tables WHERE table_name = '" + bcdb.getTableName() + "'";
        Connection conn = DriverManager.getConnection(this.url);
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(query);
        Assert.assertTrue(rs.next());
        Assert.assertEquals(1, rs.getInt(1));
        Assert.assertFalse(rs.next());
    }
}

assertEquals()上的此测试失败,并显示以下消息:

FAILED: expected: <1> but was: <0>

4 个答案:

答案 0 :(得分:5)

我找到的解决方案似乎有效:

private void createTable() throws SQLException {
    String sqlCreate = "CREATE TABLE IF NOT EXISTS " + this.getTableName()
            + "  (brand           VARCHAR(10),"
            + "   year            INTEGER,"
            + "   number          INTEGER,"
            + "   value           INTEGER,"
            + "   card_count           INTEGER,"
            + "   player_name     VARCHAR(50),"
            + "   player_position VARCHAR(20))";

    Statement stmt = conn.createStatement();
    stmt.execute(sqlCreate);
}

我必须将IF NOT EXISTS放在我的SQL语句中的正确位置。

答案 1 :(得分:3)

来自Java docs的ResultSet定义:

  

ResultSet对象维护一个指向其当前行的光标   数据。最初,光标位于第一行之前。该   next方法将光标移动到下一行,因为它返回   当ResultSet对象中没有更多行时,它可以是false   在while循环中用于迭代结果集。

因此,您必须始终调用next()方法,否则getRow()将始终返回零,因为光标位于第一行之前。

答案 2 :(得分:1)

为您所寻求的内容构建了mysql功能:http://dev.mysql.com/doc/refman/5.0/en/create-table.html

简而言之:只需在表创建查询的末尾添加IF NOT EXISTS

编辑:
没有一般的方法可以做到这一点。大多数数据库都有一个information_scheme表,但确定信息的查询可能如下所示:

SELECT count(*) FROM information_schema.system_tables WHERE table_schem = 'public' AND table_name = 'user';

这适用于sqlite,mysql,msql,mariadb和postgres +可能很多其他人。

答案 3 :(得分:-2)

我不知道这是否一定会对你的目标有所帮助,但是当我使用Python和MySQL遇到这个问题时,我只是在每个“Create Table”语句之前添加了一个“Drop Table”语句,这样才会运行该脚本会自动删除现有表,然后重建每个表。这可能不适合您的需求,但这是我为类似问题找到成功的解决方案。