zoukankan      html  css  js  c++  java
  • 通过jdbc获取数据库中的表结构 主键 各个表字段类型及应用生成实体类

    http://www.cnblogs.com/lbangel/p/3487796.html

    1、JDBC中通过MetaData来获取具体的表的相关信息。可以查询数据库中的有哪些表,表有哪些字段,字段的属性等等。MetaData中通过一系列getXXX函数,将这些信息存放到ResultSet里面,然后返回给用户。关于MetaData的说明网上也有不少,这里我只是从我自身学习的角度来记录一下简单使用JDBC以及获取数据表相关信息的方法。 

    DatabaseMetaData dbmd = con.getMetaData(); 
    rs = dbmd.getColumns(con.getCatalog(), schema, tableName, null); 
    rs.getString(DATA_TYPE) // java.sql.Types 的 SQL 类型 
    rs.getString(COLUMN_SIZE) //列的大小。对于 char 或 date 类型,列的大小是最大字符数,对于 numeric 和 decimal 类型,列的大小就是精度。 
    rs.getString(DECIMAL_DIGITS) //小数部分的位数

      2、下面就是我的JDBC下的获取表信息的代码了。我是以MySQL 5.0作为测试平台的。可以通过下面四个步骤来实现:

    按 Ctrl+C 复制代码
    按 Ctrl+C 复制代码
    复制代码
    每个列描述都有以下列: 
    
    TABLE_CAT String => 表类别(可为 null) 
    TABLE_SCHEM String => 表模式(可为 null) 
    TABLE_NAME String => 表名称 
    COLUMN_NAME String => 列名称 
    DATA_TYPE int => 来自 java.sql.Types 的 SQL 类型 
    TYPE_NAME String => 数据源依赖的类型名称,对于 UDT,该类型名称是完全限定的 
    COLUMN_SIZE int => 列的大小。 
    BUFFER_LENGTH 未被使用。 
    DECIMAL_DIGITS int => 小数部分的位数。对于 DECIMAL_DIGITS 不适用的数据类型,则返回 Null。 
    NUM_PREC_RADIX int => 基数(通常为 10 或 2) 
    NULLABLE int => 是否允许使用 NULL。 
    columnNoNulls - 可能不允许使用 NULL 值 
    columnNullable - 明确允许使用 NULL 值 
    columnNullableUnknown - 不知道是否可使用 null 
    REMARKS String => 描述列的注释(可为 null) 
    COLUMN_DEF String => 该列的默认值,当值在单引号内时应被解释为一个字符串(可为 null) 
    SQL_DATA_TYPE int => 未使用 
    SQL_DATETIME_SUB int => 未使用 
    CHAR_OCTET_LENGTH int => 对于 char 类型,该长度是列中的最大字节数 
    ORDINAL_POSITION int => 表中的列的索引(从 1 开始) 
    IS_NULLABLE String => ISO 规则用于确定列是否包括 null。 
    YES --- 如果参数可以包括 NULL 
    NO --- 如果参数不可以包括 NULL 
    空字符串 --- 如果不知道参数是否可以包括 null 
    SCOPE_CATLOG String => 表的类别,它是引用属性的作用域(如果 DATA_TYPE 不是 REF,则为 null) 
    SCOPE_SCHEMA String => 表的模式,它是引用属性的作用域(如果 DATA_TYPE 不是 REF,则为 null) 
    SCOPE_TABLE String => 表名称,它是引用属性的作用域(如果 DATA_TYPE 不是 REF,则为 null) 
    SOURCE_DATA_TYPE short => 不同类型或用户生成 Ref 类型、来自 java.sql.Types 的 SQL 类型的源类型(如果 DATA_TYPE 不是 DISTINCT 或用户生成的 REF,则为 null) 
    IS_AUTOINCREMENT String => 指示此列是否自动增加 
    YES --- 如果该列自动增加 
    NO --- 如果该列不自动增加 
    空字符串 --- 如果不能确定该列是否是自动增加参数 
    COLUMN_SIZE 列表示给定列的指定列大小。对于数值数据,这是最大精度。对于字符数据,这是字符长度。对于日期时间数据类型,这是 String 表示形式的字符长度(假定允许的最大小数秒组件的精度)。对于二进制数据,这是字节长度。对于 ROWID 数据类型,这是字节长度。对于列大小不适用的数据类型,则返回 Null。 
    
    
    参数:
    catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为 "" 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围
    schemaPattern - 模式名称的模式;它必须与存储在数据库中的模式名称匹配;该参数为 "" 表示获取没有模式的那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围
    tableNamePattern - 表名称模式;它必须与存储在数据库中的表名称匹配
    columnNamePattern - 列名称模式;它必须与存储在数据库中的列名称匹配 
    复制代码

      3、获取所有表 

    String catalog = conn.getCatalog(); //catalog 其实也就是数据库名  
    ResultSet tablesResultSet = dbMetaData.getTables(catalog,null,null,new String[]{"TABLE"});  
    while(tablesResultSet.next()){  
        String tableName = tablesResultSet.getString("TABLE_NAME");  
    }  

    tablesResultSet 中有以下列: 

    复制代码
    TABLE_CAT String => 表类别(可为 null)
    TABLE_SCHEM String => 表模式(可为 null)
    TABLE_NAME String => 表名称
    TABLE_TYPE String => 表类型。典型的类型是 "TABLE"、"VIEW"、"SYSTEM TABLE"、"GLOBAL TEMPORARY"、"LOCAL TEMPORARY"、"ALIAS" 和 "SYNONYM"。
    REMARKS String => 表的解释性注释
    TYPE_CAT String => 类型的类别(可为 null)
    TYPE_SCHEM String => 类型模式(可为 null)
    TYPE_NAME String => 类型名称(可为 null)
    SELF_REFERENCING_COL_NAME String => 有类型表的指定 "identifier" 列的名称(可为 null)
    REF_GENERATION String => 指定在 SELF_REFERENCING_COL_NAME 中创建值的方式。这些值为 "SYSTEM"、"USER" 和 "DERIVED"。(可能为 null)
    复制代码

      4、某个表的主键 

    String tableName = ...;  
    ResultSet primaryKeyResultSet = dbMetaData.getPrimaryKeys(catalog,null,tableName);  
    while(primaryKeyResultSet.next()){  
        String primaryKeyColumnName = primaryKeyResultSet.getString("COLUMN_NAME");  
    }  
    复制代码
    primayKeyResultSet 有以下几列: 
    
    TABLE_CAT String => 表类别(可为 null)
    TABLE_SCHEM String => 表模式(可为 null)
    TABLE_NAME String => 表名称
    COLUMN_NAME String => 列名称
    KEY_SEQ short => 主键中的序列号(值 1 表示主键中的第一列,值 2 表示主键中的第二列)。
    PK_NAME String => 主键的名称(可为 null)
    复制代码

      5、某个表的外键 

     
    ResultSet foreignKeyResultSet = dbMetaData.getImportedKeys(catalog,null,tableName);  
    while(foreignKeyResultSet.next()){  
        String fkColumnName = foreignKeyResultSet.getString("FKCOLUMN_NAM");  
        String pkTablenName = foreignKeyResultSet.getString("PKTABLE_NAME");  
        String pkColumnName = foreignKeyResultSet.getString("PKCOLUMN_NAME");  
    }  
    复制代码
    foreignKeyResultSet 有以下几列: 
    
    PKTABLE_CAT String => 被导入的主键表类别(可为 null)
    PKTABLE_SCHEM String => 被导入的主键表模式(可为 null)
    PKTABLE_NAME String => 被导入的主键表名称
    PKCOLUMN_NAME String => 被导入的主键列名称
    FKTABLE_CAT String => 外键表类别(可为 null)
    FKTABLE_SCHEM String => 外键表模式(可为 null)
    FKTABLE_NAME String => 外键表名称
    FKCOLUMN_NAME String => 外键列名称
    KEY_SEQ short => 外键中的序列号(值 1 表示外键中的第一列,值 2 表示外键中的第二列)
    UPDATE_RULE short => 更新主键时外键发生的变化
    DELETE_RULE short => 删除主键时外键发生的变化
    PK_NAME String => 主键的名称(可为 null)
    FK_NAME String => 外键的名称(可为 null)
    DEFERRABILITY short => 是否可以将对外键约束的评估延迟到提交时间
    复制代码

      6、应用:

      大多数数据库有许多主键,但是在一个表中不允许两条记录的同一个主键具有相同的值。可以使用Java Database Connectivity(JDBC)来判断一个数据表的主键。 JDBC具有强大的元数据处理能力。java.sql.Connection类和java.sql.ResultSet类可以通过调用其getMetaData方法进行反射。可以通过下面两个方法:

    //这两个方法都可以获取主外键信息,只是参照物不同
    metaData.getExportedKeys("数据库名称", "schema", "表名");
    metaData.getImportedKeys(catalog, null, tablename);

    package cn.test;

    import java.io.File;
    import java.io.FileOutputStream;
    import java.sql.Connection;
    import java.sql.DatabaseMetaData;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;

    public class TestAll {
    private static String path = "D:\tool\project\DynamicTable\src\cn\test\entity";
    private static String pkname = "com.mysql.jdbc.Driver";
    private static String url = "jdbc:mysql://192.168.1.220:3306/Person";
    private static String[] classNames = new String[] { "ShipStopping",
    "ArriveShip", "TBLUserType" };
    private static Map<String, String> fkTableNamesAndPk = new HashMap<String, String>();

    public static void main(String[] args) {
    test();
    }

    public static void test() {
    Connection conn = null;
    DatabaseMetaData metaData = null;
    ResultSet rs = null;
    ResultSet crs = null;
    try {
    Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
    conn = DriverManager.getConnection(url, "admin", "123");
    String catalog = conn.getCatalog(); // catalog 其实也就是数据库名
    metaData = conn.getMetaData();
    File dirFile = new File(path);
    if (!dirFile.exists()) {
    dirFile.mkdirs();
    }
    // 获取表
    rs = metaData.getTables(null, "%", "%", new String[] { "TABLE" });
    while (rs.next()) {
    String tablename = rs.getString("TABLE_NAME");
    String classname = getClassNameByTableName(tablename);
    StringBuffer sb = new StringBuffer();
    StringBuffer sbpackage = new StringBuffer();
    sbpackage.append("package cn.test.entity; ");
    sbpackage.append("import javax.persistence.Column; ");
    sbpackage.append("import javax.persistence.Entity; ");
    sbpackage.append("import javax.persistence.GeneratedValue; ");
    sbpackage.append("import javax.persistence.Id; ");
    sbpackage.append("import javax.persistence.Table; ");
    sb.append(" @Entity ");
    sb.append("@Table(name = "" + tablename + "") ");
    sb.append("public class " + classname
    + " implements java.io.Serializable { ");
    // 获取当前表的列
    crs = metaData.getColumns(null, "%", tablename, "%");
    // 获取被引用的表,它的主键就是当前表的外键
    fkTableNamesAndPk.clear();
    ResultSet foreignKeyResultSet = metaData.getImportedKeys(catalog, null, tablename);
    while (foreignKeyResultSet.next()) {
    String pkTablenName = foreignKeyResultSet.getString("PKTABLE_NAME"); // 外键表
    String fkColumnName = foreignKeyResultSet.getString("FKCOLUMN_NAME"); // 外键
    if (!fkTableNamesAndPk.containsKey(fkColumnName))
    fkTableNamesAndPk.put(fkColumnName, pkTablenName);
    }
    // foreignKeyResultSet.close();
    while (crs.next()) {
    String columnname = crs.getString("COLUMN_NAME");
    String columntype = crs.getString("TYPE_NAME");
    System.out.println("--------------------------"+ columntype);
    if (existFKColumn(columnname)) {
    String fkclassname = getClassNameByTableName(fkTableNamesAndPk.get(columnname));
    sbpackage.append("import " + pkname + "." + fkclassname+ "; ");
    sb.append(" /** */ ");
    sb.append(" private " + fkclassname + " " + columnname+ "; ");
    } else {
    sb.append(" /** */ ");
    sb.append(" private "+ getFieldType(columntype, sbpackage) + " "+ columnname + "; ");
    }
    }
    sb.append("}");
    File file = new File(dirFile, classname + ".java");
    if (file.exists()) {
    file.delete();
    }
    getTitle(sbpackage, classname);
    FileOutputStream outputStream = new FileOutputStream(file);
    outputStream.write(sbpackage.toString().getBytes());
    outputStream.write(sb.toString().getBytes());
    outputStream.close();
    System.out.println(classname + " create success ... ");
    }
    } catch (Exception e) {
    e.printStackTrace(System.out);
    } finally {
    try {
    if (null != rs) {
    rs.close();
    }
    if (null != conn) {
    conn.close();
    }
    } catch (Exception e2) {
    }
    }
    }

    /**
    * 根据表名获取类名称
    *
    * @param tablename
    * @return
    */
    private static String getClassNameByTableName(String tablename) {
    String classname = getClassName(tablename);
    for (String name : classNames) {
    if (name.toLowerCase().equals(tablename.toLowerCase())) {
    classname = name;
    }
    }
    return classname;
    }

    private static boolean existFKColumn(String columnname) {
    if (fkTableNamesAndPk != null) {
    if (fkTableNamesAndPk.containsKey(columnname))
    return true;
    }
    return false;
    }

    /**
    * 适合表名为单个单词, 例如:表名是TBLUSER 类名是TBLUser;当表名是USER 类名是User;当表面是USERTYPE(两个单词)
    * 时,类名是Usertype,如果要 UserType,将期望的类名添加到classNames字段中(与数据库表名一致 不区分大小写)。
    *
    * @param tablename
    * @return
    */
    public static String getClassName(String tablename) {
    String res = tablename.toLowerCase();
    if (tablename.startsWith("TBL")) {
    return tablename.substring(0, 4) + res.substring(4);
    }
    return tablename.substring(0, 1).toUpperCase() + res.substring(1);
    }

    /**
    * 设置字段类型 MySql数据类型
    *
    * @param columnType
    * 列类型字符串
    * @param sbpackage
    * 封装包信息
    * @return
    */
    public static String getFieldType(String columnType, StringBuffer sbpackage) {
    /*
    * tinyblob tinyblob byte[]
    tinytext varchar java.lang.string
    blob blob byte[]
    text varchar java.lang.string
    mediumblob mediumblob byte[]
    mediumtext varchar java.lang.string
    longblob longblob byte[]
    longtext varchar java.lang.string
    enum('value1','value2',...) char java.lang.string
    set('value1','value2',...) char java.lang.string
    */
    columnType = columnType.toLowerCase();
    if (columnType.equals("varchar") || columnType.equals("nvarchar")
    || columnType.equals("char")
    // || columnType.equals("tinytext")
    // || columnType.equals("text")
    // || columnType.equals("mediumtext")
    // || columnType.equals("longtext")
    ) {
    return "String";
    } else if (columnType.equals("tinyblob")
    ||columnType.equals("blob")
    ||columnType.equals("mediumblob")
    ||columnType.equals("longblob")) {
    return "byte[]1111";
    } else if (columnType.equals("datetime")
    ||columnType.equals("date")
    ||columnType.equals("timestamp")
    ||columnType.equals("time")
    ||columnType.equals("year")) {
    sbpackage.append("import java.util.Date; ");
    return "Date";
    } else if (columnType.equals("bit")
    ||columnType.equals("int")
    ||columnType.equals("tinyint")
    ||columnType.equals("smallint")
    // ||columnType.equals("bool")
    // ||columnType.equals("mediumint")
    // ||columnType.equals("bigint")
    ) {
    return "int";
    } else if (columnType.equals("float")) {
    return "Float";
    } else if (columnType.equals("double")) {
    return "Double";
    } else if (columnType.equals("decimal")) {
    // sbpackage.append("import java.math.BigDecimal; ");
    // return "BigDecimal";
    }
    return "ErrorType";
    }

    /**
    * 设置类标题注释
    *
    * @param sbpackage
    * @param className
    */
    public static void getTitle(StringBuffer sbpackage, String className) {
    SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
    sbpackage.append(" /** ");
    sbpackage.append("* ");
    sbpackage.append("* 标题: " + className + "<br/> ");
    sbpackage.append("* 说明: <br/> ");
    sbpackage.append("* ");
    sbpackage.append("* 作成信息: DATE: " + format.format(new Date())
    + " NAME: author ");
    sbpackage.append("* ");
    sbpackage.append("* 修改信息<br/> ");
    sbpackage.append("* 修改日期 修改者 修改ID 修改内容<br/> ");
    sbpackage.append("* ");
    sbpackage.append("*/ ");
    }

    }

  • 相关阅读:
    【剑指offer】19 顺时针打印矩阵
    【剑指offer】18 二叉树的镜像
    【剑指offer】17 树的子结构
    【剑指offer】16 合并两个排序的链表
    【剑指offer】15 反转链表
    【剑指offer】14 链表中倒数第k个结点
    【剑指offer】13 调整数组顺序使奇数位于偶数前面
    【剑指offer】12 数值的整数次方
    【剑指offer】11 二进制中1的个数
    数据库-第九节:ORM模型迁移
  • 原文地址:https://www.cnblogs.com/fx2008/p/5407371.html
Copyright © 2011-2022 走看看