目前所在的项目组距离下个版本上线已经很近了,就面临了一个问题:开发人员在开发库上根据需要增加数据表、数据字段、或者变更了字段类型或者字段长度等等。
由于时间比较紧迫,导致在开发过程中不可能一一把DDL数据库脚本记录下来,在比较大的项目中,比如我所在项目开发的系统大概包含了800张左右的表,字段上10000个的情况下,人工处理明显不可行,所以我们就得通过程序来判断比对,哪些是我们需要新增加的表,哪些是我们需要新增加的字段,哪些是我们需要修改的字段。
首先是一个 Table 类,代表了我们数据库中的一张表,其中存在String类型的表名、和存放若干个各种字段的HashMap<String, Column>()
接着就是一个 Column 类,代表了数据库中的一个字段,其中属性就是字段名、字段类型、字段长度,当然可以根据自己的需求加入更多要素
其实这个方法完全可以不用上面两个类的,但是为了写起来理解方便,所以就用了,执行效率其实还不错,几百张表几秒钟就跑完了
下面是实现这个需求的主要类,写出来的主要目的就是希望能帮我改进一下,毕竟自己写程序没有太多的设计理念和大局观,希望能者修改修改:
由于时间比较紧迫,导致在开发过程中不可能一一把DDL数据库脚本记录下来,在比较大的项目中,比如我所在项目开发的系统大概包含了800张左右的表,字段上10000个的情况下,人工处理明显不可行,所以我们就得通过程序来判断比对,哪些是我们需要新增加的表,哪些是我们需要新增加的字段,哪些是我们需要修改的字段。
首先是一个 Table 类,代表了我们数据库中的一张表,其中存在String类型的表名、和存放若干个各种字段的HashMap<String, Column>()
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 类,代表了数据库中的一个字段,其中属性就是字段名、字段类型、字段长度,当然可以根据自己的需求加入更多要素
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;
}
}
|
其实这个方法完全可以不用上面两个类的,但是为了写起来理解方便,所以就用了,执行效率其实还不错,几百张表几秒钟就跑完了
下面是实现这个需求的主要类,写出来的主要目的就是希望能帮我改进一下,毕竟自己写程序没有太多的设计理念和大局观,希望能者修改修改:
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();
}
}
}
|