问题描述
目前所在的项目组距离下个版本上线已经很近了,就面临了一个问题:开发人员在开发库上根据需要增加数据表、数据字段、或者变更了字段类型或者字段长度等等。由于时间比较紧迫,导致在开发过程中不可能一一把DDL数据库脚本记录下来,在比较大的项目中,比如我所在项目开发的系统大概包含了800张左右的表,字段上10000个的情况下,人工处理明显不可行,所以我们就得通过程序来判断比对,哪些是我们需要新增加的表,哪些是我们需要新增加的字段,哪些是我们需要修改的字段。首先是一个Table类,代表了我们数据库中的一张表,其中存在String类型的表名、和存放若干个各种字段的HashMap<String,Column>()packagetest;importjava.util.HashMap;publicclassTable{publicStringtableName;publicHashMapcolumns=newHashMap();publicTable(StringtableName){this.tableName=tableName;}publicStringgetTableName(){returntableName;}publicvoidsetTableName(StringtableName){this.tableName=tableName;}publicHashMapgetColumns(){returncolumns;}publicvoidsetColumns(HashMapcolumns){this.columns=columns;}}
接着就是一个Column类,代表了数据库中的一个字段,其中属性就是字段名、字段类型、字段长度,当然可以根据自己的需求加入更多要素packagetest;publicclassColumn{publicStringcolumnName;publicStringdataType;publicintlength;publicColumn(StringcolumnName,StringdataType,intlength){this.columnName=columnName;this.dataType=dataType;this.length=length;}publicStringgetColumnName(){returncolumnName;}publicvoidsetColumnName(StringcolumnName){this.columnName=columnName;}publicStringgetDataType(){returndataType;}publicvoidsetDataType(StringdataType){this.dataType=dataType;}publicintgetLength(){returnlength;}publicvoidsetLength(intlength){this.length=length;}}
其实这个方法完全可以不用上面两个类的,但是为了写起来理解方便,所以就用了,执行效率其实还不错,几百张表几秒钟就跑完了下面是实现这个需求的主要类,写出来的主要目的就是希望能帮我改进一下,毕竟自己写程序没有太多的设计理念和大局观,希望能者修改修改:packagetest;packagetest;importjava.io.File;importjava.io.FileOutputStream;importjava.io.OutputStream;importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.PreparedStatement;importjava.sql.SQLException;importjava.util.HashMap;importjava.util.Iterator;importjava.util.Map;importcom.amarsoft.are.sql.ASResultSet;importcom.amarsoft.are.sql.Transaction;importcom.amarsoft.are.util.DataConvert;publicclassCompareTable{publicstaticStringBuffer[]sb={newStringBuffer(),newStringBuffer(),newStringBuffer(),newStringBuffer(),newStringBuffer(),newStringBuffer()};publicstaticTransactiongetTransaction_product()throwsException{Class.forName("oracle.jdbc.driver.OracleDriver");Connectionconn=DriverManager.getConnection("jdbc:oracle:thin:@192.168.1.1:1621:orcl","demo1","demo1");if(conn!=null)System.out.println("数据库加载成功!");Transactiontransaction=newTransaction(conn);returntransaction;}publicstaticTransactiongetTransaction_develop()throwsException{Class.forName("oracle.jdbc.driver.OracleDriver");Connectionconn=DriverManager.getConnection("jdbc:oracle:thin:@192.168.1.2:1621:orcl","demo2","demo2");if(conn!=null)System.out.println("数据库加载成功!");Transactiontransaction=newTransaction(conn);returntransaction;}publicstaticvoidmain(String[]args)throwsException{compareTables();//比较数据库writeFile();//写入文件}/***@authorYUJIYU090比较生产库和开发库的数据表,包括表名、字段名、字段类型、字段长度**/publicstaticvoidcompareTables()throwsException{//生产数据库连接Transactiontrans_product=getTransaction_product();Map<String,Table>map_product=getTables(trans_product);//开发数据库连接Transactiontrans_develop=getTransaction_develop();Map<String,Table>map_develop=getTables(trans_develop);//遍历开发库Mapfor(Iterator<String>iter_table=map_develop.keySet().iterator();iter_table.hasNext();){Stringkey_table=(String)iter_table.next();Tabletable_develop=map_develop.get(key_table);//获得开发库中的表Tabletable_product=map_product.get(key_table);//尝试从生产库中获得同名表if(table_product==null){//如果获得表为空,说明开发存在,生产不存在append(table_develop,null,2);}else{//表相同,判断字段、字段类型、字段长度for(Iterator<String>iter_column=table_develop.columns.keySet().iterator();iter_column.hasNext();){Stringkey_column=(String)iter_column.next();Columncolumn_develop=table_develop.columns.get(key_column);//获得开发库中的列Columncolumn_product=table_product.columns.get(key_column);//尝试从生产库中获得同名列if(column_product==null){//如果列名为空,说明开发存在,生产不存在append(table_develop,column_develop,4);}else{//说明两者都存在if(!column_develop.dataType.equals(column_product.dataType))//字段类型不一致append(table_develop,column_develop,5);if(column_develop.length!=column_product.length)//字段长度不一致append(table_develop,column_develop,6);}}}}//遍历生产库Mapfor(Iterator<String>iter_table=map_product.keySet().iterator();iter_table.hasNext();){Stringkey_table=(String)iter_table.next();Tabletable_product=map_product.get(key_table);//尝试从生产库中获得同名表Tabletable_develop=map_develop.get(key_table);//获得开发库中的表if(table_develop==null){//如果获得表为空,说明开发存在,生产不存在append(table_product,null,1);}else{//表相同,判断字段、字段类型、字段长度for(Iterator<String>iter_column=table_product.columns.keySet().iterator();iter_column.hasNext();){Stringkey_column=(String)iter_column.next();Columncolumn_product=table_product.columns.get(key_column);//获得生产库中的列Columncolumn_develop=table_develop.columns.get(key_column);//尝试从开发库中获得同名列if(column_develop==null){//如果列名为空,说明生产存在,开发不存在append(table_product,column_product,3);}}}}}/***@authorYUJIYU090传入数据库连接,返回数据库中所有TABLE对象的MAP**/publicstaticMap<String,Table>getTables(Transactiontransaction)throwsException{StringsSql="selecttable_name,Column_Name,Data_Type,"+"DECODE(DATA_TYPE,'NUMBER',DATA_PRECISION,'VARCHAR2',"+"DATA_LENGTH,'VARCHAR',DATA_LENGTH,'CHAR',DATA_LENGTH,0)Length,"+"NVL(DATA_SCALE,0)SCALE,DECODE(NULLABLE,'N','1','0')NULLABLE"+"fromuser_tab_columnswhere1=1OrderBytable_name,column_name";ASResultSetrs=transaction.getASResultSet(sSql);Map<String,Table>map=newHashMap<String,Table>();StringtableName="";Tabletable=null;while(rs.next()){if(!tableName.equals(rs.getString("table_name"))){//一张新表tableName=rs.getString("table_name");table=newTable(tableName);Columncolumn=newColumn(rs.getString("Column_Name"),rs.getString("Data_Type"),rs.getInt("Length"));table.columns.put(column.columnName,column);map.put(rs.getString("table_name"),table);}else{//已存在的表,增加字段Columncolumn=newColumn(rs.getString("Column_Name"),rs.getString("Data_Type"),rs.getInt("Length"));table.columns.put(column.columnName,column);}}if(null!=rs)rs.close();transaction.finalize();returnmap;}/***@authorYUJIYU090根据标示位,追加到满足条件的StringBuffer**/publicstaticvoidappend(Tabletable,Columncolumn,intflag)throwsException{switch(flag){case1:System.out.println("1、生产存在,开发不存在的表:"+table.getTableName());//跳过sb[0].append(table.getTableName()+"n");break;case2:System.out.println("2、生产不存在,开发存在的表:"+table.getTableName());//需要人工判断脚本sb[1].append(table.getTableName()+"n");break;case3:System.out.println("3、生产存在,开发不存在的字段:"+table.getTableName()+"|"+column.getColumnName());//需人工判断如何处理sb[2].append(table.getTableName()+"|"+column.getColumnName()+"n");break;case4:System.out.println("4、生产不存在,开发存在的字段:"+table.getTableName()+"|"+column.getColumnName());//需要人工判断脚本sb[3].append(table.getTableName()+"|"+column.getColumnName()+"n");break;case5:System.out.println("5、表和字段都相同,但字段类型不同的内容:"+table.getTableName()+"|"+column.getColumnName()+"|"+column.getDataType());//需要人工判断脚本sb[4].append(table.getTableName()+"|"+column.getColumnName()+"|"+column.getDataType()+"n");break;case6:System.out.println("6、表和字段、字段类型都相同,但字段长度不同的内容:"+table.getTableName()+"|"+column.getColumnName()+"|"+column.getLength());//需要人工判断脚本sb[5].append(table.getTableName()+"|"+column.getColumnName()+"|"+column.getLength()+"n");break;}}/***@authorYUJIYU090将StringBuffer中的值写入文件中**/publicstaticvoidwriteFile()throwsException{String[]fileName={"D://table//生产存在,开发不存在的表.txt","D://table//生产不存在,开发存在的表.txt","D://table//生产存在,开发不存在的字段.txt","D://table//生产不存在,开发存在的字段.txt","D://table//表和字段都相同,但字段类型不同的内容.txt","D://table//表和字段、字段类型都相同,但字段长度不同的内容.txt"};for(inti=0;i<fileName.length;i++){Filefile=newFile(fileName[i]);OutputStreamos=newFileOutputStream(file);os.write(sb[i].toString().getBytes());os.flush();os.close();}}}
我写代码一向是属于有点野路子型的,大师级别的人看了别笑话,希望给出中肯的建议原文发布于我的博客:
解决方案
解决方案二:
额,表示LZ在osc上发过
解决方案三:
其实这里才是首发,后面发现人气太少了,就发到OSC了
解决方案四:
用得着这么费劲么?每个库都把表结构导出来,用文本比较工具比较一下呗。
解决方案五:
先把表导出为文本文件,再用程序比较文件内容,个人感觉能快些。毕竟800多张表。
解决方案六:
你好,我现在在做这个,看了你写的东西,很适合我,DataConvert,ASResultSet这两个包,能给我发一下吗,348685378@qq.com,我的邮箱,谢谢啊
解决方案七:
好贴应该加精
解决方案八:
你好,我现在在做这个,看了你写的东西,很适合我,DataConvert,ASResultSet,Transaction这两个包,能给我发一下吗,582376043@qq.com,我的邮箱,谢谢啊
解决方案九:
引用3楼bao110908的回复:
用得着这么费劲么?每个库都把表结构导出来,用文本比较工具比较一下呗。
确实
解决方案十:
非要写代码去比对?你写的代码还要测试,就算测了还不一定准确,废工又费劲,你们项目经理是怎么同意这种方案的。直接结构导出来,比对工具这么多,分分钟搞定,准确率几乎100%。大项目还敢这么玩,想死了。。。
解决方案十一:
你好,我现在在做这个,看了你写的东西,很适合我,DataConvert,ASResultSet,Transaction这两个包,能给我发一下吗,414715257@qq.com,我的邮箱,谢谢啊