繁体   English   中英

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

[英]Any way to check for the existence of a SEQUENCE using JDBC?

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

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

提前致谢

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

答案很简单。

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

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


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

您可以使用hibernate dialect 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();
                }
            }
        }
}

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

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

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

不同数据库/存储的实现(下面给出oracle的EG):

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

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

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

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

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

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

为了检索序列列表,我在做什么:

  1. 首先,使用java.sql.DatabaseMetaData#getTableTypes列出实体类型

结果是:

 * 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,有一个表格类型“SEQUENCE”。

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

    String catalog =“”;
    String tableNamePattern =“%”;
    String schemaPattern =“my_schema”;
    ResultSet tablesRS = cnx.getMetaData()。getTables(catalog,schemaPattern,tableNamePattern,new String [] {“SEQUENCE”});

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

我做了一个实用程序类ExtractMetadataUtil来测试它(在GitHub上)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM