Java 有没有办法使用JDBC检查序列的存在?
我需要以编程方式在数据存储中生成序列,但需要能够检测序列的存在,而不是在序列已经存在时创建序列。有人知道提取此信息所需的JDBC元数据吗 粗略的扫描并不能找到合适的方法;我可以得到所有的表/视图和相关的键/索引等,但不能得到该模式的序列。是否有人知道一种方法,最好是独立于数据库的,但如果不知道,则尽可能多地使用数据库(想想oracle有一个user_sequence表?但这只是一个数据库,我需要支持其他数据库)Java 有没有办法使用JDBC检查序列的存在?,java,sql,jdbc,sequence,Java,Sql,Jdbc,Sequence,我需要以编程方式在数据存储中生成序列,但需要能够检测序列的存在,而不是在序列已经存在时创建序列。有人知道提取此信息所需的JDBC元数据吗 粗略的扫描并不能找到合适的方法;我可以得到所有的表/视图和相关的键/索引等,但不能得到该模式的序列。是否有人知道一种方法,最好是独立于数据库的,但如果不知道,则尽可能多地使用数据库(想想oracle有一个user_sequence表?但这只是一个数据库,我需要支持其他数据库) 提前谢谢据我所知,没有任何直接的方法。因为每个数据库都有自己的生成/处理序列的方法。
提前谢谢据我所知,没有任何直接的方法。因为每个数据库都有自己的生成/处理序列的方法。当它在Oracle中是序列时,它在mysql中是自动加入的(不是一个序列,但与它很接近,或者实现了一些相同的结果),在SQL Server中是标识列,等等 我会做这样的事情-您必须制作一个接口:
interface ISequenceChecker{ // or some name which suits you
SequenceObject getSequence();
}
不同数据库/存储的实现(例如,下面给出的oracle):
有没有办法使用JDBC检查序列的存在
答案是否定的
对序列元数据的支持不是JDBC规范的一部分。如果要查找此信息,需要让代码知道它正在处理的数据库类型,并对用于表示数据库模式的特定于供应商的表执行相关查询,等等
您可能会找到一个第三方Java库来实现这一点。。。但我不知道有一个
实际上,从理论上讲,您可以通过尝试创建一个同名序列来测试序列是否存在。但是,还有其他各种各样的问题,比如处理创建
的不同语法,删除作为测试创建的序列
,诊断特定于供应商的错误代码以确定创建
失败的原因。您最好查询特定于供应商的模式表。您不需要。每个RDBMS都有自己的方式来存储metada信息。其中一些可能与其他类似,但您很难在这些表中找到完全相同的信息
您所能做的最好的事情是使用某种数据字典来识别RDBMS,并从中转到字典上的特定配置以获取此信息
其想法是有一个表来存储数据库,如果它支持序列,那么另一个表具有加载序列信息所需的配置,如序列表、序列列等
然后实现一种获取此信息的方法。我会选择@avijendr-answer(他在我写这篇文章时发布了它)您可以使用hibernate方言api来检索序列。见:
从下面的示例中,您可以看到如何使用方言获取序列详细信息
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();
}
}
}
}
我用Postgres9、Java8和JDBC4.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
因此,对于PostgresJDBC驱动程序,有一个表类型“SEQUENCE”
然后我就这样用,
字符串catalog=“”
字符串tableNamePattern=“%”
String schemaPattern=“my_schema”
ResultSet tablers=cnx.getMetaData().getTables(目录、schemaPattern、tableNamePattern、新字符串[]{“序列”})
tablers.getString(“TABLE_NAME”)
给出找到的每个序列的名称
我制作了一个实用程序类来测试它(在GitHub上)。您使用的是什么数据库?正如我所说的,我需要支持很多数据库,我使用H2(它有创建序列…如果不存在的话),但这是非标准的,但需要支持所有支持序列的公共RDBMS(SQLServer、PostgreSQL、Oracle、H2、NuoDB、Derby、Firebird等)可能重复@NeilStockton-如果你真的阅读了Oracle特定问题的答案,你会意识到他们也回答了你更一般的问题。但我也在下面为您解答了。@NeilStockton-1)如果您希望得到关于如何查询数据库模式的答案,您应该问一下。。。不是“JDBC可以做到”。2) 最新的JDBCAPI是公开的。你不需要问这么多问题就可以找到他们。谢谢你的回复。是的,每个数据存储都有一个变体可能是我的选择。顺便说一句,MySQL中的“auto increment”并不等同于(SQL)序列,后者是一个独立的命名值生成器,而auto increment是特定列的标识,没有名称。有支持标识(自动递增)和顺序的RDBMS,因此有区别。谢谢Neil。我知道它不是等价的,但它是最接近的,否则你必须使用联锁或类似的东西(但仍然不是顺序)。除了我上面提到的,我想不出别的解决办法。快乐的黑客!在Hibernate>=4.x中,有必要将Connection.getMetaData
包装到数据库MetadataDialogResolutionInfo适配器中。如果方言.get…String
方法返回null,我建议抛出异常,因为null
不是文档化的返回值。
* 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