import os import subprocess import pymysql from update.utils.git_util import GitUtil from dingxin_toolbox_drf.settings import BASE_DIR from update.utils.git_util import GitUtil class DbCompare: def __init__(self, target_ip, short_release): self.target_server = target_ip self.target_user = 'test' self.target_pwd = 'cine123456' self.target_port = '3306' self.target_release = short_release self.cine_sql_path = os.path.join(BASE_DIR, 'dx', 'sql', GitUtil(short_release).get_db_name() + '.sql') self.diff_sql_path = os.path.join(BASE_DIR, 'dx', 'temp', self.target_server + '_diff.sql') self.clear_diff_sql_path = os.path.join(BASE_DIR, 'dx', 'temp', self.target_server + '_diff_clear.sql') self.create_sql_path = os.path.join(BASE_DIR, 'dx', 'temp', self.target_server + '_create.sql') # 生成对比文件 def gen_diff_file(self): print('开始生成差异文件') if os.path.exists(self.diff_sql_path): print(f'删除之前生成的差异文件 {self.diff_sql_path}') os.remove(self.diff_sql_path) if os.path.exists(self.diff_sql_path): print('删除失败') print('删除成功') # serv_host = '127.0.0.1' # serv_user = 'dingxin' # serv_pwd = 'cine123456' # serv_port = '3306' serv_host = '172.16.3.112' serv_user = 'test' serv_pwd = 'cine123456' serv_port = '3306' server_1 = f'--server1={serv_user}:{serv_pwd}@{serv_host}:{serv_port}' server_2 = f'--server2={self.target_user}:{self.target_pwd}@{self.target_server}:{self.target_port}' git_util = GitUtil(self.target_release) db_name = git_util.get_db_name() cmd = f'mysqldiff {server_1} {server_2} --changes-for=server2 --difftype=sql --force --quiet --skip-table-options {db_name}:cine > {self.diff_sql_path}' print('执行命令', cmd) # result = os.system(cmd) # print('执行返回结果:', result >> 8) result = subprocess.getstatusoutput(cmd) if result[0] != 0: print('执行失败:', result[1]) print('执行成功:', result[1]) return self.diff_sql_path # 针对降级的情况,需要屏蔽掉语句中的drop语句,此处可能有错误的风险,待验证 def remove_drop(self): # 如果清理后的文件存在则删除 print('开始处理差异文件,清除Drop命令等') if os.path.exists(self.clear_diff_sql_path): print(f'清理之前生成的文件 {self.clear_diff_sql_path}') os.remove(self.clear_diff_sql_path) if os.path.exists(self.clear_diff_sql_path): print('清理失败') print('清理成功') # 打开生成的差异sql,如果遇到ALTER语句则进入alter模式,将ALTER下面的语句写入temp中,如果是DROP就跳过,当遇到换行时就结束alter模式,把temp写入主列表 with open(self.diff_sql_path, 'r', encoding='utf-8') as f: sql_list = [] temp = [] alter = 0 alter_definer = 0 for line in f.readlines(): if line.strip().startswith('ALTER TABLE'): temp.append(line) alter = 1 # elif line.strip().startswith('DROP INDEX'): # pass # elif line.strip().startswith('DROP COLUMN'): # pass elif line.strip().startswith('[PASS]'): pass elif line.strip().startswith('+'): pass elif line.strip().startswith('-'): pass elif line.strip().startswith('@'): pass elif line.strip().startswith('ALTER DEFINER'): temp.append(line) alter_definer = 1 elif line.strip() == '': if len(temp) > 1 and alter_definer == 0: sql_list.extend(temp) if alter_definer == 1: alter_definer = 0 sql_list.extend('\n') temp = [] alter = 0 else: if alter == 1 or alter_definer == 1: temp.append(line) else: sql_list.append(line) f.close() # 将清洗过的sql列表写入文件 with open(self.clear_diff_sql_path, 'w', encoding='utf-8') as f: f.writelines(sql_list) print('生成新的对比文件:', self.clear_diff_sql_path) f.close() # 生成新表sql def gen_create_file(self): # 如果有已生成的文件则删除 print('开始生成创建文件') if os.path.exists(self.create_sql_path): print(f'清理之前生成的文件 {self.create_sql_path}') os.remove(self.create_sql_path) if os.path.exists(self.create_sql_path): print('清除失败') print('清除成功') # 在生成的差异文件中查找原始版本没有,目标版本中存在的表明 create_sql_list = [] with open(self.diff_sql_path, 'r', encoding='utf-8') as f: for line in f.readlines(): if line.startswith('# TABLE'): create_sql_list.append(line.split(':')[1].strip()) f.close() # 通过上步中找到的表名,在目标版本的cine.sql中查找创建表的sql语句,并组成sql语句列表 create_table_sql_list = ['USE `cine`;\n\n'] with open(self.cine_sql_path, 'r', encoding='utf-8') as f: content = f.read() for sql in content.split(';\n'): for table in create_sql_list: if f'CREATE TABLE `{table}`' in sql: create_table_sql_list.append(sql + ';\n\n') f.close() # 将上步中的sql语句列表些入create.sql文件中 with open(self.create_sql_path, 'w', encoding='utf-8') as f: f.writelines(create_table_sql_list) print('生成新的创建文件:', self.create_sql_path) f.close() return self.create_sql_path # 执行差异 def exec_diff_sql(self): self.gen_diff_file() self.remove_drop() self.gen_create_file() diff_cmd = f'mysql -h{self.target_server} -P{self.target_port} -u{self.target_user} -p{self.target_pwd} < {self.clear_diff_sql_path}' create_cmd = f'mysql -h{self.target_server} -P{self.target_port} -u{self.target_user} -p{self.target_pwd} < {self.create_sql_path}' print('执行命令:', diff_cmd) # diff_result = os.system(diff_cmd) # print('diff_result', diff_result) diff_result = subprocess.getstatusoutput(diff_cmd) if diff_result[0] != 0: print('执行失败:', diff_result[1]) print('执行成功:', diff_result[1]) print('执行命令:', create_cmd) # create_result = os.system(create_cmd) # print('create_result', create_result) create_result = subprocess.getstatusoutput(create_cmd) if create_result[0] != 0: print('执行失败:', create_result[1]) print('执行成功:', create_result[1]) return '数据库对比成功' if diff_result[0] == 0 and create_result[0] == 0 else '数据库对比失败' + diff_result[ 1] + create_result[1]