该 Maven 程序使用阿里官方提供的 Java API,读取存储在 ODPS 上的数据表,通过字符串处理,自动生成它们的数据字典,并将数据字典存储到本地的 MySQL 数据库中。
参考文档 MaxCompute Java SDK
SDK Java Doc
简述 在 ODPS 上大概存储了 200,000+ 万张表,需要拉取数据字典,即所有英文表名、表名中文注释、表中字段名、表中字段名中文注释。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 //需要的数据组成一列,那么就把列作为对象 //col.java import java.util.List; public class col { private String tablename; public String getTablename() { return tablename; } public void setTablename(String tablename) { this.tablename = tablename; } public String getTablename_CN() { return tablename_CN; } public void setTablename_CN(String tablename_CN) { this.tablename_CN = tablename_CN; } public String getFieldname() { return fieldname; } public void setFieldname(String fieldname) { this.fieldname = fieldname; } public String getFieldname_CN() { return fieldname_CN; } public void setFieldname_CN(String fieldname_CN) { this.fieldname_CN = fieldname_CN; } private String tablename_CN; private String fieldname; private String fieldname_CN; }
接下去是数据连接,通过配置 pom.xml 获得所需要的 Java 连接 MySQL 驱动包
1 2 3 4 5 <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.39</version> </dependency>
通用的 DBConnection 数据库连接文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import java.sql.*; public class DBConnection { private static String driverName="com.mysql.jdbc.Driver";//在 MySQL 8.0 中合理 private static String userName="root"; private static String userPwd="123456"; private static String dbName="*";//自己建的 database 名 public static Connection getDBConnection() { String url1="jdbc:mysql://localhost/"+dbName; String url2="?user="+userName+"&password="+userPwd; String url3="&useUnicode=true&characterEncoding=utf-8"; String url=url1+url2+url3; Connection con=null; try { Class.forName(driverName); con=DriverManager.getConnection(url); }catch(Exception e) { e.printStackTrace(); } return con; } public static void closeDB(Connection con,PreparedStatement pstm,ResultSet rs) { if(rs!=null) try{ rs.close(); }catch(SQLException e) { e.printStackTrace(); } if(pstm!=null) try{ pstm.close(); }catch(SQLException e) { e.printStackTrace(); } if(con!=null) try{ con.close(); }catch(SQLException e) { e.printStackTrace(); } } }
简单的 MySQL 数据库 插入操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import java.sql.ResultSet;import com.mysql.jdbc.*;import odpstest.DBConnection;public class colDao { public int saveCol (col c ) { Connection con = null ; PreparedStatement pstmt = null ; ResultSet rs = null ; con = (Connection) DBConnection.getDBConnection(); int row = 0 ; String sql="insert into data(tablename,tablename_CN,fieldname,fieldname_CN) values(?,?,?,?)" ; try { pstmt = (PreparedStatement) con.prepareStatement(sql); pstmt.setString(1 , c.getTablename()); pstmt.setString(2 , c.getTablename_CN()); pstmt.setString(3 , c.getFieldname()); pstmt.setString(4 , c.getFieldname_CN()); row = pstmt.executeUpdate(); }catch (Exception e) { e.printStackTrace(); }finally { DBConnection.closeDB(con, pstmt, rs); } return row; } }
导出数据字典的步骤:
执行 SQL 语句show tables
,用 like
关键字找出含有需要字段的所有表名。在这个时候出来的结果如图,只有高亮的才是需要的表名:
做字符串处理操作,取出表名。
在程序中安排循环,对每一个表名执行desc
语句操作,得到这个表的结构描述,具体到字段,每张表都不一样的。举例,结构描述如图:
进行字符串处理,取出表描述信息中的字段名、字段中文注释。
最后将取出的四个字段组成一个列对象中的四个变量,存储这个列对象进入本地 MySQL 数据库中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 import java.util.ArrayList; import java.sql.*; import java.util.List; import com.aliyun.odps.Instance; import com.aliyun.odps.Odps; import com.aliyun.odps.OdpsException; import com.aliyun.odps.account.Account; import com.aliyun.odps.account.AliyunAccount; import com.aliyun.odps.data.Record; import com.aliyun.odps.task.SQLTask; public class Sql { private static final String accessId = "*"; private static final String accessKey = "*";//以上两项在信息页上都能找到,就是Access Key 的 ID/Secret private static final String endPoint = "http://service.*/api";//自己项目的api private static final String project = "*";//项目名 private static final String sql = "show tables like '*_330801_*';"; public static void main(String[] args) { Account account = new AliyunAccount(accessId, accessKey); Odps odps = new Odps(account); odps.setEndpoint(endPoint); odps.setDefaultProject(project); Instance i; String tablename = null, tablename_CN = null; try { i = SQLTask.run(odps, sql); i.waitForSuccess(); List<Record> tables = SQLTask.getResult(i); int cout = 0; int table_num=0; String name =""; for(Record table:tables){//负责取table table_num++; String[] table_pattern = table.get(0).toString().split(":"); tablename = table_pattern[1]; System.out.println(tablename); String sql_describe="desc "+tablename+" ;";//该语句负责展示每个表的表结构 Instance ins = SQLTask.run(odps, sql_describe); ins.waitForSuccess(); List<Record> describes = null; try { describes = SQLTask.getResult(ins); String[] tablename_CN_pattern = describes.get(1).get(0).toString().split(":"); tablename_CN = tablename_CN_pattern[1].replace("|", "").trim(); if(tablename_CN.equals("")) { tablename_CN="null"; } System.out.println(tablename_CN); int temp=0; for(Record describe_column:describes) { String columns=describe_column.get(0).toString(); //System.out.println(columns); if(temp>12&&columns.indexOf("------")==-1) {//保证在---最终分隔符之前 String[] pattern = describe_column.get(0).toString().split("\\|");//注意正则,用“|”分割 String fieldname = pattern[1].trim(); String fieldname_CN = pattern[4].trim(); System.out.println("fieldname: "+fieldname); if(fieldname_CN.equals("")) { fieldname_CN="null"; } System.out.println("fieldname_CN: "+fieldname_CN); col column = new col();//创建新的一列对象 column.setTablename(tablename); column.setTablename_CN(tablename_CN); column.setFieldname(fieldname); column.setFieldname_CN(fieldname_CN); colDao colDao = new colDao(); int flag= colDao.saveCol(column); if(flag==1) { System.out.println("success!"); } } temp++; } } catch (Exception e) { cout++; name += tablename+" & "; } } System.out.println(table_num+" tables, "+cout+" errors: "+name); } catch (OdpsException e) { e.printStackTrace(); } } }
最后给出建表语句:
1 2 3 4 5 6 7 8 9 10 CREATE TABLE `zjsjt`.`data` ( `iddata` INT NOT NULL AUTO_INCREMENT, `tablename` VARCHAR(500) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL, `tablename_CN` VARCHAR(500) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL, `fieldname` VARCHAR(500) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL, `fieldname_CN` VARCHAR(500) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL, PRIMARY KEY (`iddata`)) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci;
补充 如果是单纯只需要表名列名或者注释的,在 Table 里面有个 Schema 对象,可以顺着取列对象,具体参见接口文档。这个字符串处理方法针对只能靠 desc 表名
方法提取基本结构信息的要求。