在测试环境下使用的数据库跟生产环境的数据库不一致,当我们的测试环境下的数据库完成测试准备更新到生产环境上的数据库时候,需要准备更新脚本,真是一不小心没记下来就会忘了改了哪里,哪里添加了什么,这个真是非常让人头疼。因此我就试着用Python来实现自动的生成更新脚本,以免我这烂记性,记不住事。
主要操作如下:
1.在原先 basedao.py 中添加如下方法,这样旧能很方便的获取数据库的数据,为测试数据库和生产数据库做对比打下了基础。
1 def select_database_struts(self):
2 '''
3 查找当前连接配置中的数据库结构以字典集合
4 '''
5 sql = '''SELECT COLUMN_NAME, IS_NULLABLE, COLUMN_TYPE, COLUMN_KEY, COLUMN_COMMENT
6 FROM information_schema.`COLUMNS`
7 WHERE TABLE_SCHEMA="%s" AND TABLE_NAME="{0}" '''%(self.__database)
8 struts = {}
9 for k in self.__primaryKey_dict.keys():
10 self.__cursor.execute(sql.format(k))
11 results = self.__cursor.fetchall()
12 struts[k] = {}
13 for result in results:
14 struts[k][result[0]] = {}
15 struts[k][result[0]]["COLUMN_NAME"] = result[0]
16 struts[k][result[0]]["IS_NULLABLE"] = result[1]
17 struts[k][result[0]]["COLUMN_TYPE"] = result[2]
18 struts[k][result[0]]["COLUMN_KEY"] = result[3]
19 struts[k][result[0]]["COLUMN_COMMENT"] = result[4]
20 return self.__config, struts
2.编写对比的Python脚本
1 '''
2 数据库迁移脚本, 目前支持一下几种功能:
3 1.生成旧数据库中没有的数据库表执行 SQL 脚本(支持是否带表数据),生成的 SQL 脚本在 temp 目录下(表名.sql)。
4 2.生成添加列 SQL 脚本,生成的 SQL 脚本统一放在 temp 目录下的 depoyed.sql 中。
5 3.生成修改列属性 SQL 脚本,生成的 SQL 脚本统一放在 temp 目录下的 depoyed.sql 中。
6 4.生成删除列 SQL 脚本,生成的 SQL 脚本统一放在 temp 目录下的 depoyed.sql 中。
7 注意事项:
8 1.系统必须配置 mysql 的环境变量,确保 mysqldump 指令能执行。
9 2.数据库表必须带有主键。
10 '''
11 import json, os, sys
12 from basedao import BaseDao
13
14 temp_path = sys.path[0] + "/temp"
15 if not os.path.exists(temp_path):
16 os.mkdir(temp_path)
17
18 def main(old, new, has_data=False):
19 '''
20 @old 旧数据库(目标数据库)
21 @new 最新的数据库(源数据库)
22 @has_data 是否生成结构+数据的sql脚本
23 '''
24 clear_temp() # 先清理 temp 目录
25 old_config, old_struts = old
26 new_config, new_struts = new
27 for new_table, new_fields in new_struts.items():
28 if old_struts.get(new_table) is None:
29 gc_sql(new_config["user"], new_config["password"], new_config["database"], new_table, has_data)
30 else:
31 cmp_table(old_struts[new_table], new_struts[new_table], new_table)
32
33 def cmp_table(old, new, table):
34 '''
35 对比表结构生成 sql
36 '''
37 old_fields = old
38 new_fields = new
39
40 sql_add_column = "ALTER TABLE `{TABLE}` ADD COLUMN `{COLUMN_NAME}` {COLUMN_TYPE} COMMENT '{COLUMN_COMMENT}';\n"
41 sql_change_column = "ALTER TABLE `{TABLE}` CHANGE `{COLUMN_NAME}` `{COLUMN_NAME}` {COLUMN_TYPE} COMMENT '{COLUMN_COMMENT}';\n"
42 sql_del_column = "ALTER TABLE `{TABLE}` DROP {COLUMN_NAME};"
43
44 if old_fields != new_fields:
45 f = open(sys.path[0] + "/temp/deploy.sql", "a", encoding="utf8")
46 content = ""
47 for new_field, new_field_dict in new_fields.items():
48 old_filed_dict = old_fields.get(new_field)
49 if old_filed_dict is None:
50 # 生成添加列 sql
51 content += sql_add_column.format(TABLE=table, **new_field_dict)
52 else:
53 # 生成修改列 sql
54 if old_filed_dict != new_field_dict:
55 content += sql_change_column.format(TABLE=table, **new_field_dict)
56 pass
57 # 生成删除列 sql
58 for old_field, old_field_dict in old_fields.items():
59 if new_fields.get(old_field) is None:
60 content += sql_del_column.format(TABLE=table, COLUMN_NAME=old_field)
61
62 f.write(content)
63 f.close()
64
65 def gc_sql(user, pwd, db, table, has_data):
66 '''
67 生成 sql 文件
68 '''
69 if has_data:
70 sys_order = "mysqldump -u%s -p%s %s %s > %s/%s.sql"%(user, pwd, db, table, temp_path, table)
71 else:
72 sys_order = "mysqldump -u%s -p%s -d %s %s > %s/%s.sql"%(user, pwd, db, table, temp_path, table)
73 try:
74 res = os.system(sys_order)
75 if res == 0:
76 print("生成%s表sql文件。"%table)
77 except Exception as e:
78 print(e)
79
80 def clear_temp():
81 '''
82 每次执行的时候调用这个,先清理下temp目录下面的旧文件
83 '''
84 if os.path.exists(temp_path):
85 files = os.listdir(temp_path)
86 for file in files:
87 f = os.path.join(temp_path, file)
88 if os.path.isfile(f):
89 os.remove(f)
90 print("临时文件目录清理完成")
91
92 if __name__ == "__main__":
93 test1_config = {
94 "user" : "root",
95 "password" : "root",
96 "database" : "test1",
97 }
98 test2_config = {
99 "user" : "root",
100 "password" : "root",
101 "database" : "test2",
102 }
103
104 test1_dao = BaseDao(**test1_config)
105 test1_struts = test1_dao.select_database_struts()
106
107 test2_dao = BaseDao(**test2_config)
108 test2_struts = test2_dao.select_database_struts()
109
110 main(test2_struts, test1_struts)
目前只支持了4种SQL脚本的生成。