通過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;\r\n\r\n");
sbpackage.append("import javax.persistence.Column;\r\n");
sbpackage.append("import javax.persistence.Entity;\r\n");
sbpackage.append("import javax.persistence.GeneratedValue;\r\n");
sbpackage.append("import javax.persistence.Id;\r\n");
sbpackage.append("import javax.persistence.Table;\r\n\r\n");
sb.append("\r\n@Entity\r\n");
sb.append("@Table(name = \"" + tablename + "\")\r\n");
sb.append("public class " + classname
+ " implements java.io.Serializable {\r\n");
// 獲取當前表的列
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+ ";\r\n");
sb.append("\t/** */\r\n");
sb.append("\tprivate " + fkclassname + " " + columnname+ ";\r\n");
} else {
sb.append("\t/** */\r\n");
sb.append("\tprivate "+ getFieldType(columntype, sbpackage) + " "+ columnname + ";\r\n");
}
}
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;\r\n");
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;\r\n");
// 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("\r\n/**\r\n");
sbpackage.append("*\r\n");
sbpackage.append("* 標題: " + className + "<br/>\r\n");
sbpackage.append("* 說明: <br/>\r\n");
sbpackage.append("*\r\n");
sbpackage.append("* 作成信息: DATE: " + format.format(new Date())
+ " NAME: author\r\n");
sbpackage.append("*\r\n");
sbpackage.append("* 修改信息<br/>\r\n");
sbpackage.append("* 修改日期 修改者 修改ID 修改內容<br/>\r\n");
sbpackage.append("*\r\n");
sbpackage.append("*/\r\n");
}

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM