前言
随着PostgreSQL数据库越来越被广泛的应用,它的优势也逐渐被广泛的认可。但针对该数据库的工具却较少。由于工作需要,经常有对PostgreSQL数据库进行比对生成升级脚本的需求,故本人使用python编写了一个PostgreSQL数据库比对程序和大家共同交流学习。(文章的最后将提供源程序的下载地址)
一、功能介绍
比对程序实现了对两个数据库的结构进行比较并生成差异化更新脚本。
比对的内容如下:
1、表结构比比较:包含表、字段、字段注释、序列、约束、索引、触发器的比较。
2、视图比较:包含普通视图和物化视图的比较,并生成创建或者修改脚本。
3、函数比较:函数(存储过程)的比较,并生成新建或者修改脚本。
4、外部表比较:外部表进行比较,并生成新建或者修改脚本。
二、代码目录结构
1、下图为代码的目录结构展开截图及说明
2、下面为程序运行界面
三、核心源代码解析
1、bin目录下main.py
import core.schemaSync as core
import PySimpleGUI as sg
import time
# 定义需要执行的任务
my_list = ['表', '视图', '函数', '外部表']
# 定义进度条
progressbar = [[sg.ProgressBar(len(my_list), orientation='h', size=(51, 10), bar_color=('#f47920', '#46485f'), key='progressbar')]]
# 定义输出窗口尺寸
output_win = [[sg.Output(size=(78, 20))]]
# 窗口布局
layout = [[sg.Frame('执行进度', layout=progressbar)],
[sg.Frame('输出信息', layout=output_win)],
[sg.Submit('开 始'), sg.Cancel('退 出')]]
window = sg.Window('PostgreSQL数据库比较程序', layout)
progress_bar = window['progressbar']
while True:
event, values = window.read(timeout=10)
# 点击按钮退出
if event == '退 出' or event is None:
break
# 点击按钮开始
elif event == '开 始':
file_name = ''
# 循环要执行的任务
for i, item in enumerate(my_list):
if i == 0:
print(item + ' 比对开始...')
file_name = core.sync_table()
print(item+' 比对完成!(含字段及注释、序列、约束、索引、触发器的比对)\n')
if i == 1:
print(item + ' 比对开始...')
core.sync_view()
print(item+' 比对完成!(含普通视图、物化视图)\n')
if i == 2:
print(item + ' 比对开始...')
core.sync_function()
print(item+' 比对完成!\n')
if i == 3:
print(item + ' 比对开始...')
core.sync_foreign_table()
print(item+' 比对完成!\n')
time.sleep(1)
# 更新进度条
progress_bar.UpdateBar(i + 1)
# 输出生成脚本的路径
print('差异脚本路径:' + file_name)
2、conf目录下config.ini
[database]
#postgre_src
pg_host_src=192.168.10.70
pg_port_src=5432
pg_user_src=postgres
pg_pwd_src=***
pg_db_src=data_use
#postgre_dst
pg_host_dst = 192.168.10.71
pg_port_dst=5432
pg_user_dst=postgres
pg_pwd_dst=***
pg_db_dst=data_use
[common]
output_file_name=updScript.sql
log_dir=
3、core目录下的schemaSync.py
import os
from util.connDB import getConn
from util.logger import log
import sqlConfig
from util.commonFunction import commonFunction
import util.readConfig as readConfig
# 对比表、字段及注释、序列、约束、索引、触发器
def sync_table():
try:
# 获取源数据库连接
global sourceConn,targetConn,sourceCursor,targetCursor
sourceConn, sourceCursor = getConn('postgre_src')
# 获取目标数据库连接
targetConn, targetCursor = getConn('postgre_dst')
# 求源和目标表的差集
sourceCursor.execute(sqlConfig.selectTable)
targetCursor.execute(sqlConfig.selectTable)
sourceTable = sourceCursor.fetchall()
targetTable = targetCursor.fetchall()
tableReslut=set(sourceTable) - set(targetTable)
tableName = ''
for item in tableReslut:
tableName=tableName+','+item[0]
tableName=str(tableName[1:])
# print(tableName)
# 导出新增表
cf=commonFunction()
file_name=cf.dumpTable(tableName)
# 对比序列
# 求源和目标序列的差集
sourceCursor.execute(sqlConfig.selectSequence % tableName.replace(",", "','"))
targetCursor.execute(sqlConfig.selectSequence % tableName.replace(",", "','"))
sourceSequence = sourceCursor.fetchall()
targetSequence = targetCursor.fetchall()
sequenceReslut = list(set(sourceSequence) - set(targetSequence))
# print(sequenceReslut)
for itemReslut in sequenceReslut:
sequence_name = itemReslut[0]
if (sequence_name != ''):
str_sql = "create sequence " + sequence_name + ";"
# print(str_sql)
# 追加写入到指定文件
with open(file_name, mode='a+', encoding="utf-8") as w:
w.write("-- Sequence compares" + "\n" + str_sql + "\n")
# 对比字段
# 求源和目标字段的差集
sourceCursor.execute(sqlConfig.selectColumn % tableName.replace(",","','"))
targetCursor.execute(sqlConfig.selectColumn % tableName.replace(",","','"))
sourceColumn = sourceCursor.fetchall()
targetColumn = targetCursor.fetchall()
columnReslut = list(set(sourceColumn) - set(targetColumn))
# 对列表根据表名称和字段名称排序
columnReslut.sort()
#print(columnReslut)
if(len(columnReslut)>0):
# 追加写入到指定文件
with open(file_name, mode='a+', encoding="utf-8") as w:
w.write("\n--\n-- Column compares\n--\n" + "\n")
# 外循环,对比后的差集字段
for itemReslut in columnReslut:
table_name = itemReslut[0]
column_name = itemReslut[1]
column_type = itemReslut[2]
column_default = itemReslut[3]
description = itemReslut[4]
# print(itemReslut[0],itemReslut[1],itemReslut[2],itemReslut[3],itemReslut[4],itemReslut[5])
# 内循环,目标库的字段
column_exists = 0
for itemTarget in targetColumn:
# 表名称和字段名称相等
if(table_name == itemTarget[0] and column_name == itemTarget[1]):
column_exists = column_exists+1