前言
使用过Mybatis的都知道有个代码生成工具,Mybatis-Generator,可以生成Mapper文件、Dao类,Model实体文件,非常好用,作为他的扩展Mybatis-Plus也同样有这样的功能,根据数据库中的信息生成Java文件,但是他底层是怎么获取表中字段信息的,应该大部分人不知道,也不常用。
所以今天说说他的原理。
JDBC:DatabaseMetaData
关键类其实就是DatabaseMetaData,通过他可以查看已连接数据库的元数据,如数据库中定义了哪些表,每个表具有哪些列等信息。
DatabaseMetaData接口中有很多方法,不可能介绍全部,可以查看JavaDoc,https://docs.oracle.com/javase/7/docs/api/java/sql/DatabaseMetaData.html。
1.获取DatabaseMetaData
Connection connection = DriverManager.getConnection("","","");
DatabaseMetaData metaData = connection.getMetaData();
2.获取数据库信息
DatabaseMetaData databaseMetaData = connection.getMetaData();
System.out.println(databaseMetaData.getDatabaseMajorVersion());
System.out.println( databaseMetaData.getDatabaseMinorVersion());
System.out.println( databaseMetaData.getDatabaseProductName());
System.out.println(databaseMetaData.getDatabaseProductVersion());
8
0
MySQL
8.0.16
3.数据库驱动版本
System.out.println(databaseMetaData.getDriverMajorVersion());
System.out.println(databaseMetaData.getDriverMinorVersion());
8
0
4.获取数据库所有表、getTables
这个操作用的比较多,可以查询数据库中定义了那些表,返回的是ResultSet,每个表描述都有以下列:
1. TABLE_CAT (表编目)
2. TABLE_SCHEM (表架构)
3. TABLE_NAME (表名)
4. TABLE_TYPE (表类型,有 TABLE”,“ VIEW”,“ SYSTEM TABLE”,“ GLOBAL TEMPORARY”,“ LOCAL TEMPORARY”,“ ALIAS”,“ SYNONYM”)
5. REMARKS (对表的注释)
6. TYPE_CAT (编目类型)
7. TYPE_SCHEM (类型架构)
8. TYPE_NAME (类型名称)
9. SELF_REFERENCING_COL_NAME (不懂)
10. REF_GENERATION (不懂)
参数:
- catalog:要获得表所在的编目,Null表示所有编目。
- schemaPattern:所在的模式,Null表示所有模式。
- tableNamePattern:表名。
- types:一个指出返回何种表的数组。
ResultSet resultSet = databaseMetaData.getTables(null, null, null, new String[]{"TABLE"});
while (resultSet.next()){
System.out.println(resultSet.getString("TABLE_NAME"));
}
5.获取所有列信息、getColumns
ResultSet里面返回的信息也比较多,在官方文档中有24个字段,参数直接置为null就行,下面只说几个常用的字段。
- COLUMN_NAME:列名
- TYPE_NAME:类型
- COLUMN_SIZE:列大小
- DECIMAL_DIGITS:小数位
- REMARKS:备注
- COLUMN_DEF:默认值
- IS_AUTOINCREMENT:是否自增
ResultSet resultSet = databaseMetaData.getColumns(null, null, "tb_course", null);
while (resultSet.next()){
System.out.println("字段"+resultSet.getString(4)+" 类型"+
resultSet.getString("TYPE_NAME"));
}
更具上面信息,就可以生成一个Java类,写个Demo测试一下。
先新建一张表。
public class Generate {
public static void main(String[] args) throws SQLException {
Connection connection = DriverManager.getConnection("","","");
DatabaseMetaData databaseMetaData = connection.getMetaData();
System.out.println(generateModel(databaseMetaData, "tb_course"));
}
private static String convertName(String name){
String newName=name.substring(0,1).toUpperCase()+name.substring(1);
while (newName.indexOf("_")!=-1){
int i = newName.indexOf("_");
if (i==newName.length()-1){
newName=newName.replace("_","");
break;
}
String s = newName.substring(0,i)+newName.substring(i+1,i+2).toUpperCase()+newName.substring(i+2);
newName=s;
}
return newName;
}
private static String createBaseClass(String tabName){
StringBuffer stringBuffer =new StringBuffer();
stringBuffer.append("public class ");
stringBuffer.append(convertName(tabName));
stringBuffer.append("{\n");
stringBuffer.append(" ${fieldSet}\n");
stringBuffer.append("}");
return stringBuffer.toString();
}
private static String createMark(String name){
return "/**\n"+
"*\n"+
"*"+name+
"\n*\n"+
"*/";
}
private static String generateModel(DatabaseMetaData databaseMetaData,String tableName) throws SQLException {
Map<String,Class>map =new HashMap<String, Class>();
map.put("INT",Integer.class);
map.put("VARCHAR",String.class);
map.put("TIMESTAMP", LocalDateTime.class);
map.put("DECIMAL", BigDecimal.class);
ResultSet resultSet = databaseMetaData.getColumns(null, null, "tb_test", null);
List<FieldInfo> fieldInfos =new ArrayList<>();
while (resultSet.next()){
String mark =resultSet.getString("REMARKS");
String cluName = resultSet.getString(4);
mark=(mark==null||mark.length()==0)?cluName:mark;
fieldInfos.add(new FieldInfo(
cluName,
map.get(resultSet.getString("TYPE_NAME")),
mark ));
}
StringBuffer fieldSetBuffer =new StringBuffer();
fieldInfos.forEach(fieldInfo -> {
fieldSetBuffer.append(createMark(fieldInfo.getMark()));
fieldSetBuffer.append("\n");
fieldSetBuffer.append("private ");
fieldSetBuffer.append(fieldInfo.getFieldClass().getSimpleName() +" ");
String name = convertName(fieldInfo.getFiledName())+";";
fieldSetBuffer.append(name.substring(0,1).toLowerCase()+name.substring(1));
fieldSetBuffer.append("\n\n");
});
return createBaseClass(convertName(tableName)).replace("${fieldSet}",fieldSetBuffer);
}
static class FieldInfo{
private String filedName;
private Class fieldClass;
private String mark;
public FieldInfo(String filedName, Class fieldClass, String mark) {
this.filedName = filedName;
this.fieldClass = fieldClass;
this.mark = mark;
}
public String getMark() {
return mark;
}
public void setMark(String mark) {
this.mark = mark;
}
public String getFiledName() {
return filedName;
}
public void setFiledName(String filedName) {
this.filedName = filedName;
}
public Class getFieldClass() {
return fieldClass;
}
public void setFieldClass(Class fieldClass) {
this.fieldClass = fieldClass;
}
@Override
public String toString() {
return "FieldInfo{" +
"filedName='" + filedName + '\'' +
", fieldClass=" + fieldClass +
'}';
}
}
}
最后输出如下:
6.获取所有列信息、getColumns
ResultSet resultSet = databaseMetaData.getPrimaryKeys(null, null, "tb_test");
resultSet.next();
System.out.println(resultSet.getString(4));
输出: