有没有办法使用JDBC检查SEQUENCE的存在?

时间:2014-01-06 10:58:52

标签: java sql jdbc sequence

我需要以编程方式在数据存储区中生成序列,但需要能够检测它们的存在而不是在它们已经存在的情况下创建。有人知道提取这些信息所需的JDBC元数据吗?

DatabaseMetadata进行粗略扫描并未发现合适的方法;我可以获取所有表/视图和关联的键/索引等,但不能获取该模式的序列。有没有人知道一种方法,最好是数据库独立的,但如果没有,那么对于尽可能多的数据库(想想oracle有一个user_sequence表?但这只是一个数据库,我需要支持其他人)。

提前致谢

5 个答案:

答案 0 :(得分:2)

  

使用JDBC检查是否存在SEQUENCE的任何方法?

答案很简单。

SEQUENCE元数据的支持不是JDBC规范的一部分。如果要查找此信息,则需要使代码知道它正在处理的数据库类型,并针对用于表示数据库模式的供应商特定表执行相关查询,等等。

您可能能够找到第三方Java库来执行此操作...但我不知道。


实际上,从理论上讲,您可以通过尝试创建具有相同名称的SEQUENCE来测试CREATE是否存在。但是你会遇到各种其他问题,例如处理SEQUENCE的不同语法,删除你创建的CREATE作为测试,诊断特定于供应商的错误代码以确定{ {1}}失败了。您可能最好不要查询特定于供应商的架构表。

答案 1 :(得分:2)

您可以使用hibernate方言api来检索序列。见:http://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/dialect/Dialect.html

从下面的示例中,您可以看到如何使用方言来获取序列详细信息

public static void main(String[] args) {
        Connection jdbcConnection = null;
        try {
            jdbcConnection = DriverManager.getConnection("", "", "");
            String sequenceName = "xyz" ; // name of sequence for check
        System.out.println("Check Sequence :" + checkSequenceName(sequenceName, jdbcConnection));
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
        if(jdbcConnection != null) {
            try {
                jdbcConnection.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

public static boolean checkSequenceName(String sequenceName, Connection conn) throws JDBCConnectionException, SQLException {
    DialectResolver dialectResolver = new StandardDialectResolver();
    Dialect dialect =  dialectResolver.resolveDialect(conn.getMetaData());

    if ( dialect.supportsSequences() ) {
        String sql = dialect.getQuerySequencesString();
        if (sql!=null) {

            Statement statement = null;
            ResultSet rs = null;
            try {
                statement = conn.createStatement();
                rs = statement.executeQuery(sql);

                while ( rs.next() ) {
                    if(sequenceName.equals(rs.getString(1))) {
                        return true;
                    }
                }
            }
            finally {
                if (rs!=null) rs.close();
                if (statement!=null) statement.close();
            }

        }
    }
    return false;
}

如果您不想使用hibernate,那么您必须创建自定义顺序特定实现。 自定义实现的示例代码

interface SequenceQueryGenerator {
    String getSelectSequenceNextValString(String sequenceName);
    String getCreateSequenceString(String sequenceName, int initialValue, int incrementSize); 
    String getDropSequenceStrings(String sequenceName); 
    String getQuerySequencesString(); 
}


class OracleSequenceQueryGenerator implements SequenceQueryGenerator {

    @Override
    public String getSelectSequenceNextValString(String sequenceName) {
        return "select " + getSelectSequenceNextValString( sequenceName ) + " from dual";
    }

    @Override
    public String getCreateSequenceString(String sequenceName,
            int initialValue, int incrementSize) {
        return "create sequence " + sequenceName +  " start with " + initialValue + " increment by " + incrementSize;
    }

    @Override
    public String getDropSequenceStrings(String sequenceName) {
        return "drop sequence " + sequenceName;
    }

    @Override
    public String getQuerySequencesString() {
        return "select sequence_name from user_sequences";
    }

}


class PostgresSequenceQueryGenerator implements SequenceQueryGenerator {

    @Override
    public String getSelectSequenceNextValString(String sequenceName) {
        return "select " + getSelectSequenceNextValString( sequenceName );
    }

    @Override
    public String getCreateSequenceString(String sequenceName,
            int initialValue, int incrementSize) {
        return "create sequence " + sequenceName + " start " + initialValue + " increment " + incrementSize;
    }

    @Override
    public String getDropSequenceStrings(String sequenceName) {
        return "drop sequence " + sequenceName;
    }

    @Override
    public String getQuerySequencesString() {
        return "select relname from pg_class where relkind='S'";
    }

}


public boolean checkSequence (String sequenceName, SequenceQueryGenerator queryGenerator, Connection conn) throws SQLException {
        String sql = queryGenerator.getQuerySequencesString();
        if (sql!=null) {

            Statement statement = null;
            ResultSet rs = null;
            try {
                statement = conn.createStatement();
                rs = statement.executeQuery(sql);

                while ( rs.next() ) {
                    if(sequenceName.equals(rs.getString(1))) {
                        return true;
                    }
                }
            }
            finally {
                if (rs!=null) rs.close();
                if (statement!=null) statement.close();
            }

        }
        return false;
    }

public static void main(String[] args) {
        Connection jdbcConnection = null;
        try {
            jdbcConnection = DriverManager.getConnection("", "", "");
            String sequenceName = "xyz" ; // name of sequence for check
            System.out.println(checkSequence(sequenceName, new OracleSequenceQueryGenerator(), jdbcConnection));
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if(jdbcConnection != null) {
                try {
                    jdbcConnection.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
}

答案 2 :(得分:1)

我所知道的并没有任何直接的方法。因为每个数据库都有自己的生成/处理序列的方式。当它在Oracle中的序列时,它是 auto_incriment (不是序列但接近它或者在某些结果上有相同的结果)在mysql中,标识列在< strong> SQL Server 等

我会做这样的事情 - 你必须建立一个界面:

interface ISequenceChecker{ // or some name which suits you
    SequenceObject getSequence();
}

不同数据库/商店的实施(以下给出oracle的E.G):

public class OracleSequenceChecker implements ISequenceChecker{
   OracleSequenceObject getSequence(){
    // some jdbc or similar call
    // to get SELECT SEQUENCE_NAME.NEXTVAL FROM DUAL
   }
}

答案 3 :(得分:1)

你没有。每个RDBMS都有您自己的方式来存储您的metada信息。其中一些可能与其他类似,但你很难在thoose表上找到完全相同的信息。

您可以做的最好的事情是某种数据字典来识别RDBMS,并从那里转到字典上的特定配置以获取此信息。

这个想法是有一个存储数据库的表,如果它支持序列,那么另一个表具有加载序列信息所需的配置,如序列表,序列列等。

然后实现一种获取此信息的方法。我会去@avijendr回答(他在我写这篇文章时发帖)

答案 4 :(得分:0)

我使用Postgres 9,Java 8和JDBC 4.2进行了测试。

在这里检索序列列表我做了什么:

  1. 首先,列出具有java.sql.DatabaseMetaData#getTableTypes
  2. 的实体类型

    结果是:

     * FOREIGN TABLE
     * INDEX
     * MATERIALIZED VIEW
     * SEQUENCE
     * SYSTEM INDEX
     * SYSTEM TABLE
     * SYSTEM TOAST INDEX
     * SYSTEM TOAST TABLE
     * SYSTEM VIEW
     * TABLE
     * TEMPORARY INDEX
     * TEMPORARY SEQUENCE
     * TEMPORARY TABLE
     * TEMPORARY VIEW
     * TYPE
     * VIEW
    

    所以对于Postgres JDBC Driver,有一个表类型&#34; SEQUENCE&#34;。

    1. 然后我像这样使用java.sql.DatabaseMetaData#getTables

      字符串目录=&#34;&#34;;
      String tableNamePattern =&#34;%&#34 ;;
      字符串schemaPattern =&#34; my_schema&#34 ;;
      ResultSet tablesRS = cnx.getMetaData()。getTables(catalog,schemaPattern,tableNamePattern,new String [] {&#34; SEQUENCE&#34;});

    2. tablesRS.getString("TABLE_NAME")给出了每个序列的名称。

      我制作了一个实用工具类ExtractMetadataUtil来测试它(在GitHub上)。