数据库元数据获取工具

 

1.  简介

源码地址:https://github.com/wukenaihe/db-meta

邮箱:541931314@qq.com

有任何bug可以直接发送邮件告知承诺会马上进行修改,如果需要添加功能或者改进也希望告知,会及时进行改进。希望能够点赞(\(^o^)/~)

 

数据库的元数据库获取到现在为止并没有太好用的开源框架,最有名气的可能是schemacrawler。不过这个软件实在是太大太大了,不仅包括元数据的获取,还包括表、列等信息的显示。同时它的性能存在巨大弊端,基本上oracle数据库他就不太能用,会把oracle里面的许多临时表、垃圾表等都一股脑儿拉出来,非常可怕。它的接口相对比较简单,getDatabase只有这么一个获取方法,如果你要获取一张表,你也得用这个方法。

如果,不用开源框架,你可以选择用jdbc标准DatabaseMeta接口。使用不方便,需要处理大量的SQLException同时,他也不能获取触发器、存储过程、函数等定义内容。

如果,直接从数据库里面获取数据库元数据,相当复杂。

1.1. 设计目标

  • l  简单,易用
  • l  易用扩展
  • l  线程安全
  • l  高性能

简单,易用:数据库之间的元数据相差非常大,且均不遵守SQL标准。所以,我们把元数据进行了抽象。根据SQL标准及常用内容,组成了一个类树。

易扩展:允许添加别的数据库实现方式,允许方便的重写现有方法。

高性能:轻量,能获取小部分的元数据。

2.  例子

https://github.com/wukenaihe/db-meta-example

Maven

<repositories>

      <repository>

         <id>clojars</id>

         <name>Clojars repository</name>

         <url>https://clojars.org/repo</url>

      </repository>

</repositories>

<dependencies>
        <dependency>
            <groupId>org.clojars.xumh</groupId>
            <artifactId>db-meta</artifactId>
            <version>0.0.1-Release</version>
        </dependency>
<dependencies>

在中国很有可能下载不下来,可以用开源中国上面的maven。不过去缺少依赖logback,需要自己添加下。

<dependency>
  <groupId>com.cgs.dbMeta</groupId>
  <artifactId>db-meta</artifactId>
  <version>0.0.1-Release</version>
</dependency>

<dependency>
   <groupId>ch.qos.logback</groupId>
   <artifactId>logback-classic</artifactId>
   <version>1.0.9</version>
</dependency>

 

http://maven.oschina.net/index.html#nexus-search;quick~db-meta

如何使用maven,大家可以参照:http://maven.oschina.net/help.html

public static void main(String[] args) {

      MysqlDataSource datasource = new MysqlDataSource();

      datasource.setServerName("localhost");

      datasource.setPort(3306);

      datasource.setDatabaseName("dctest");

      datasource.setUser("root");

      datasource.setPassword("123456");  

      MetaLoader metaLoader=new MetaLoaderImpl(datasource);

      Set<String> tableNames=metaLoader.getTableNames();

      System.out.print("数据库中拥有表:");

      System.out.println(tableNames);
     
      Table table=metaLoader.getTable("des");

      PrintUtils.printTable(table);

       Map<String, Procedure> procedures=metaLoader.getProcedures();

//    System.out.println(procedures);

    }

3.  程序结构

3.1. 元数据结构

 

  • Database:数据库,拥有多个Schema
  • Schema:数据集,这个数据库与SQL中的数据集略微不同(Oracle:schema,mySql:catalog,SqlServer:catalog.schema)。这是因为,不同数据库对schema的解释不同造成的。
  • Table:拥有列、主键、外键、约束、触发器、索引和权限。
  • Column:名称、注释、是否为null、类型(java.sql.Types)、类型(数据库类型名称)、精度、小数位数、默认值。
  • 主键:主键名,列名(按照定义的顺序)
  • 外键:外键引用关系、外键删除规则、外键更新规则
  • 索引:名称、唯一性、索引类型(JDBC定义)、页数、定义和列名
  • 约束:名称、约束类型、约束定义(如”D1 Is not null”)
  • 触发器:名称、所属表、定义
  • 权限:授予者、被授予者、权限、是否有授予权限
  • 存储过程:名称、定义(大量信息被压缩在定义中)
  • 函数:名称、定义(大量信息被压缩在定义中)

3.2. API

通过等级来进行控制,这样能够避免读取不必要的信息而影响性能。

 

标准

驱动信息(JDBC

Yes  Yes  Yes 

数据库信息

 Yes Yes   Yes

 Yes Yes  Yes 

主键

 Yes  Yes Yes 

约束

 No

Yes  Yes 

视图(视为表)

  No

  No

Yes 

索引

  No

 Yes Yes 

外键

  No

Yes  Yes 

权限

  No

  No

 Yes

触发器

  No

  No

Yes 

 Yse   Yes
Yes 

 

MetaLoader接口

方法

说明

Set<String> getTableNames()

获取表名(当前Schema)

Table getTable(String tableName)

获取表(标准级别)

Table getTable(String tableName,SchemaInfoLevel schemaLevel)

如上

Table getTable(String tableName,SchemaInfo schemaInfo)

获取指定Schema下的,特定表

Set<SchemaInfo> getSchemaInfos()

获取数据下的Schema信息

Schema getSchema()

获取当前schema

Schema getSchema(SchemaInfo schemaInfo)

获取指定的schema元数据

Set<String> getProcedureNames()

获取当前schema存储过程名称

Procedure getProcedure(String procedureName)

获取存储过程

Map<String,Procedure> getProcedures()

获取当前schema存储过程集合

Set<String> getTriggerNames()

获取当前schema触发器名称

Trigger getTrigger(String triggerName)

获取指定的触发器

Map<String, Trigger> getTriggers()

获取当前schema触发器集合

Set<String> getFunctionNames()

获取当前函数名称

Function getFunction(String name)

获取指定的函数

Map<String, Function> getFunctions()

获取当前schema函数集合

Database getDatabase()

获取数据库元数据(标准)

Database getDatabase(SchemaInfoLevel level)

获取指定级别的数据库元数据

 

4.  设计过程

不同的数据库,获取元数据的方式必然不同,从这一点来看,我们需要一个策略模式。策略模式也方便进行扩展。

数据库决定之后,实际上也已经决定会使用哪个具体实现。所以,在程序中实现方式的建立将交由一个工程,根据数据库类型自动建立。

我们的数据库要求是线程安全的,所以要求不具有状态,每一个方法都具有获取连接、关闭连接等步骤,所以我们在这里使用了一个模板模式。MetaLoader的方法还是比较复杂的。所以,我们抽象除了一个MetaCrawler接口,进行细化,MetaLoader的方法实现可以通过MetaCrawler的组合实现。

部分实现,我们使用的是DatabaseMeta,任何数据库都是一样的。但是部分信息如触发器、存储过程、函数等信息,DatabaseMeta是获取不到的,又要分开实现。所以,毫无疑问,我们这里也使用了模板模式。

 

JDBC的异常为SQLException异常,抛出的异常都必须接住,会让代码结构非常混乱。同时,在close的方法抛出的异常,通常交给开发人员是无法进行任何处理的。所以,我们选择catch这类无法处理的异常,然后进行日志输出。

4.1. 线程安全

public Procedure getProcedure(String procedureName) {

      Connection con = JDBCUtils.getConnection(dataSource);

      MetaCrawler metaCrawler=null;

      Procedure p;

      try{

         metaCrawler=factory.newInstance(con);

         p=metaCrawler.getProcedure(procedureName);

         return p;

      }catch(DataAccessException e){

         logger.debug(e.getMessage(),e);

         throw new DatabaseMetaGetMetaException("Get tables error!", e);

      }finally{

         JDBCUtils.closeConnection(con);

      }

}

 

在方法的开始位置会获取一个连接,然后通过工厂创建一个实例。在方法的末尾关闭连接。整个过程都是无状态的,所以是线程安全的。

posted @ 2014-04-17 14:50  无可奈何SOS  阅读(6907)  评论(0编辑  收藏  举报