5

我正在用 Java 编写一个数据库程序,如果它不存在,我想创建一个表。我DatabaseMetaData.getTables()如何在 Java 中检测 SQL 表的存在?我正在尝试使用它:

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,即使在创建表之后也是如此。Usingrs.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

4 回答 4

8

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

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 语句中的正确位置。

于 2012-08-10T21:37:05.890 回答
3

根据ResultSetJava 文档的定义:

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

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

于 2012-08-10T21:18:42.110 回答
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 + 可能还有很多其他的。

于 2012-08-10T21:13:46.857 回答
-2

我不知道这是否一定有助于实现您的目标,但是当我使用 Python 和 MySQL 遇到这个问题时,我只是在每个“创建表”语句之前添加了一个“删除表”语句,这样就可以自动运行脚本删除现有表,然后重建每个表。这可能无法满足您的需求,但这是我发现成功解决类似问题的一种解决方案。

于 2012-08-10T21:15:06.997 回答