比对两个数据库的字段

   目前所在的项目组距离下个版本上线已经很近了,就面临了一个问题:开发人员在开发库上根据需要增加数据表、数据字段、或者变更了字段类型或者字段长度等等。
   
    由于时间比较紧迫,导致在开发过程中不可能一一把DDL数据库脚本记录下来,在比较大的项目中,比如我所在项目开发的系统大概包含了800张左右的表,字段上10000个的情况下,人工处理明显不可行,所以我们就得通过程序来判断比对,哪些是我们需要新增加的表,哪些是我们需要新增加的字段,哪些是我们需要修改的字段。

    首先是一个 Table 类,代表了我们数据库中的一张表,其中存在String类型的表名、和存放若干个各种字段的HashMap<String, Column>()

Java code
?
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
package  test;
import  java.util.HashMap;
public  class  Table {
     public  String tableName;
     public  HashMap columns =  new  HashMap();
  
     public  Table(String tableName) {
         this .tableName = tableName;
     }
  
     public  String getTableName() {
         return  tableName;
     }
  
     public  void  setTableName(String tableName) {
         this .tableName = tableName;
     }
  
     public  HashMap getColumns() {
         return  columns;
     }
  
     public  void  setColumns(HashMap columns) {
         this .columns = columns;
     }
}


    接着就是一个 Column 类,代表了数据库中的一个字段,其中属性就是字段名、字段类型、字段长度,当然可以根据自己的需求加入更多要素

Java code
?
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
package  test;
public  class  Column {
     public  String columnName;
     public  String dataType;
     public  int  length;
  
     public  Column(String columnName, String dataType,  int  length) {
         this .columnName = columnName;
         this .dataType = dataType;
         this .length = length;
     }
     public  String getColumnName() {
         return  columnName;
     }
     public  void  setColumnName(String columnName) {
         this .columnName = columnName;
     }
     public  String getDataType() {
         return  dataType;
     }
     public  void  setDataType(String dataType) {
         this .dataType = dataType;
     }
     public  int  getLength() {
         return  length;
     }
     public  void  setLength( int  length) {
         this .length = length;
     }
}



    其实这个方法完全可以不用上面两个类的,但是为了写起来理解方便,所以就用了,执行效率其实还不错,几百张表几秒钟就跑完了

    下面是实现这个需求的主要类,写出来的主要目的就是希望能帮我改进一下,毕竟自己写程序没有太多的设计理念和大局观,希望能者修改修改:

Java code
?
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
package  test;
package  test;
  
import  java.io.File;
import  java.io.FileOutputStream;
import  java.io.OutputStream;
import  java.sql.Connection;
import  java.sql.DriverManager;
import  java.sql.PreparedStatement;
import  java.sql.SQLException;
import  java.util.HashMap;
import  java.util.Iterator;
import  java.util.Map;
  
import  com.amarsoft.are.sql.ASResultSet;
import  com.amarsoft.are.sql.Transaction;
import  com.amarsoft.are.util.DataConvert;
  
public  class  CompareTable {
  
     public  static  StringBuffer[] sb = {  new  StringBuffer(),  new  StringBuffer(),
             new  StringBuffer(),  new  StringBuffer(),  new  StringBuffer(),
             new  StringBuffer() };
  
     public  static  Transaction getTransaction_product()  throws  Exception {
         Class.forName( "oracle.jdbc.driver.OracleDriver" );
         Connection conn = DriverManager.getConnection(
                 "jdbc:oracle:thin:@192.168.1.1:1621:orcl" "demo1" "demo1" );
         if  (conn !=  null )System.out.println( "数据库加载成功!" );
         Transaction transaction =  new  Transaction(conn);
         return  transaction;
     }
  
     public  static  Transaction getTransaction_develop()  throws  Exception {
         Class.forName( "oracle.jdbc.driver.OracleDriver" );
         Connection conn = DriverManager.getConnection(
                 "jdbc:oracle:thin:@192.168.1.2:1621:orcl" "demo2" "demo2" );
         if  (conn !=  null )System.out.println( "数据库加载成功!" );
         Transaction transaction =  new  Transaction(conn);
         return  transaction;
     }
  
     public  static  void  main(String[] args)  throws  Exception {
         compareTables();  // 比较数据库
         writeFile();  // 写入文件
     }
  
     /**
      * @author YUJIYU090 比较生产库和开发库的数据表,包括表名、字段名、字段类型、字段长度
      * */
  
     public  static  void  compareTables()  throws  Exception {
  
         // 生产数据库连接
         Transaction trans_product = getTransaction_product();
         Map<String, Table> map_product = getTables(trans_product);
  
         // 开发数据库连接
         Transaction trans_develop = getTransaction_develop();
         Map<String, Table> map_develop = getTables(trans_develop);
  
         // 遍历开发库Map
         for  (Iterator<String> iter_table = map_develop.keySet().iterator(); iter_table
                 .hasNext();) {
             String key_table = (String) iter_table.next();
             Table table_develop = map_develop.get(key_table); // 获得开发库中的表
             Table table_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();) {
                     String key_column = (String) iter_column.next();
                     Column column_develop = table_develop.columns.get(key_column); // 获得开发库中的列
                     Column column_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 );
                     }
                 }
             }
         }
  
         // 遍历生产库Map
         for  (Iterator<String> iter_table = map_product.keySet().iterator(); iter_table
                 .hasNext();) {
             String key_table = (String) iter_table.next();
             Table table_product = map_product.get(key_table); // 尝试从生产库中获得同名表
             Table table_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();) {
                     String key_column = (String) iter_column.next();
                     Column column_product = table_product.columns.get(key_column); // 获得生产库中的列
                     Column column_develop = table_develop.columns.get(key_column); // 尝试从开发库中获得同名列
                     if  (column_develop ==  null ) { // 如果列名为空,说明生产存在,开发不存在
                         append(table_product, column_product,  3 );
                     }
                 }
             }
         }
     }
  
     /**
      * @author YUJIYU090 传入数据库连接,返回数据库中所有TABLE对象的MAP
      * */
     public  static  Map<String, Table> getTables(Transaction transaction)
             throws  Exception {
  
         String sSql =  " select table_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 "
                 " from user_tab_columns where 1=1 Order By table_name,column_name" ;
  
         ASResultSet rs = transaction.getASResultSet(sSql);
  
         Map<String, Table> map =  new  HashMap<String, Table>();
  
         String tableName =  "" ;
         Table table =  null ;
         while  (rs.next()) {
             if  (!tableName.equals(rs.getString( "table_name" ))) { // 一张新表
                 tableName = rs.getString( "table_name" );
                 table =  new  Table(tableName);
                 Column column =  new  Column(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  { // 已存在的表,增加字段
                 Column column =  new  Column(rs.getString( "Column_Name" ), 
                 rs.getString( "Data_Type" ), rs.getInt( "Length" ));
                 table.columns.put(column.columnName, column);
             }
         }
         if  ( null  != rs)
             rs.close();
         transaction.finalize();
         return  map;
     }
  
     /**
      * @author YUJIYU090 根据标示位,追加到满足条件的StringBuffer
      * */
     public  static  void  append(Table table, Column column,  int  flag)
             throws  Exception {
         switch  (flag) {
         case  1 :
             System.out.println( "1、生产存在,开发不存在的表:"  + table.getTableName()); // 跳过
             sb[ 0 ].append(table.getTableName() +  "\n" );
             break ;
         case  2 :
             System.out.println( "2、生产不存在,开发存在的表:"  + table.getTableName()); // 需要人工判断脚本
             sb[ 1 ].append(table.getTableName() +  "\n" );
             break ;
         case  3 :
             System.out.println( "3、生产存在,开发不存在的字段:"  + table.getTableName()
                     " | "  + column.getColumnName()); // 需人工判断如何处理
             sb[ 2 ].append(table.getTableName() +  " | "  + column.getColumnName()
                     "\n" );
             break ;
         case  4 :
             System.out.println( "4、生产不存在,开发存在的字段:"  + table.getTableName()
                     " | "  + column.getColumnName()); // 需要人工判断脚本
             sb[ 3 ].append(table.getTableName() +  " | "  + column.getColumnName()
                     "\n" );
             break ;
         case  5 :
             System.out.println( "5、表和字段都相同,但字段类型不同的内容:"  + table.getTableName()
                     " | "  + column.getColumnName() +  " | "
                     + column.getDataType()); // 需要人工判断脚本
             sb[ 4 ].append(table.getTableName() +  " | "  + column.getColumnName()
                     " | "  + column.getDataType() +  "\n" );
             break ;
         case  6 :
             System.out.println( "6、表和字段、字段类型都相同,但字段长度不同的内容:"
                     + table.getTableName() +  " | "  + column.getColumnName()
                     " | "  + column.getLength()); // 需要人工判断脚本
             sb[ 5 ].append(table.getTableName() +  " | "  + column.getColumnName()
                     " | "  + column.getLength() +  "\n" );
             break ;
         }
     }
  
     /**
      * @author YUJIYU090 将StringBuffer中的值写入文件中
      * */
     public  static  void  writeFile()  throws  Exception {
         String[] fileName = {  "D://table//生产存在,开发不存在的表.txt" ,
                 "D://table//生产不存在,开发存在的表.txt" "D://table//生产存在,开发不存在的字段.txt" ,
                 "D://table//生产不存在,开发存在的字段.txt" ,
                 "D://table//表和字段都相同,但字段类型不同的内容.txt" ,
                 "D://table//表和字段、字段类型都相同,但字段长度不同的内容.txt"  };
  
         for  ( int  i =  0 ; i < fileName.length; i++) {
             File file =  new  File(fileName[i]);
             OutputStream os =  new  FileOutputStream(file);
             os.write(sb[i].toString().getBytes());
             os.flush();
             os.close();
         }
     }
}

猜你喜欢

转载自blog.csdn.net/amelia__liu/article/details/81011272