写在文前:本文中的代码经过翻阅相关库的文档和阅读CSDN中前辈的代码整理而成,在此先感谢这些前辈们的文章,由于打的太杂太多,无法一一告知,敬请原谅。
由于公司业务的需求,需要把生产数据库的一个表定时备份到本地的数据库相应的表上,由于在生产数据库上的账号只有只读权限,使用Navicat做定时任务的话效率低资源占用高并且不稳定,所以写 了 一个python脚本来做增量备份。
1、全量备份数据表
2、获取本地数据表的最大ID
3、查询生产表>本地表最大ID的数据
4、获取生产表查询结果
5、把4的查询结果导入本地数据库
脚本需要用到pymysq、pandas、sqlalchemy、os、datetime这三个库,如果没有的话需要先安装。安装使用PIP方式:
pip install 库名
查询已安装的库:
pip list
以下是脚本的代码部份:
# 导入相关的代码块
import pymysql
import pandas as pd
import os
from datetime import datetime
from sqlalchemy import create_engine
from sqlalchemy.types import NVARCHAR, Float, Integer
start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 获取开始时间 格式为年-月-日 时:分:秒
os.getcwd() # 返回当前进程的工作目录,如果要导出导入本地文件时要用到。
# 使用connect连接数据库
# 连接本地数据库
db1 = pymysql.connect("localhost", # 本地数据库地址
"root", # 数据库账号
"password", # 密码
"data", # 数据库名字
charset="utf8" #字符编码)
# 获取游标并执行
cursor = db1.cursor(pymysql.cursors.DictCursor)
cursot = db1.cursor()
查询本地表中最后的一条数据,由于这张表的ID是自动增长列,所以新增行的ID肯定比当前ID大。我们先查询出本地表的最后一个ID
# SQL查询语句查询最后行的ID
eng1 = '''SELECT
table.id AS `最新条目`
FROM
table
ORDER BY table.id DESC LIMIT 1 '''
# 执行SQL语句
try:
cursor.execute(eng1)
df = cursor.fetchone()
df = ('%(最新条目)d' % df) # 由于查询结果是字典,所以在这里需要转换一下,只需要获取它的值并转换成int重新定义
print(df) # 查看转换后的效果,方便调试用,实际运行时可以注释掉
except:
print('查询错误:变量df没有定义!') # try执行错误提示
db1.close() # 断开db1数据库连接
到这一步已经定位到了本地表的最后一条数据。接下来要做的是查询并获得生产表的新增的行。
#同样的方法,先连接生产表数据库
db2 = pymysql.connect("localhost", # 生产数据库地址
"root", # 生产数据库账号
"password", # 生产数据库密码
"data", # 生产数据库名字
charset="utf8" #字符编码)
# 获取游标并执行
cursor = db2.cursor(pymysql.cursors.DictCursor)
cursot = db2.cursor()
# 查询生产表的对比本地表的新数据
eng2 = '''SELECT * FROM table WHERE table.id > %s ''' % df #查询比本地表新的数据
try:
cursor.execute(eng2)
df2 = cursor.fetchall()
row = cursor.rowcount # 返回执行结果影响的行数
# print(df2)
# 导出为CSV文件
print('导出中……') # 调试用,正式运行时可不要
inp = pd.DataFrame(df2) # 查询结果是字典,由于我们要使用pd.to_sql,所以要先转为DataFrame
inp.to_csv('data.csv', sep=',',index=False) # 导到本地CSV文件,如果更新数据量大时可用,
# 再使用时需用pd.to_csv()导入
# print(inp) # 打印查询结果,调试用
print('导出完成!') # 调试用。
except:
print('错误:变量inp没有被定义!')
print(inp)
db2.close() # 关闭db2连接,注意每次使用connect连接完成后需要断开
这一步完成后,已经获得了完整的新数据,可以在运行目录中打开data.csv文件查看结果(注,可以不导出CSV文件,只保留DataFrame转换即可)。
接下来开始进行把数据导入本地mysql中。注意pd.to_sql()不能使用pymysql.connect连接,所以我们用sqlalchemy进行连接数据库
# 建立本地数据库连接
engine = create_engine('mysql+pymysql://root:password@localhost:3306/data')
con = engine.connect()
# 自定义函数:pandas类型和sql类型转换
def map_types(inp):
dtypedict = {}
for i, j in zip(inp.columns, inp.dtypes):
if "object" in str(j):
dtypedict.update({i: NVARCHAR(length=255)})
if "float" in str(j):
dtypedict.update({i: Float(precision=2, asdecimal=True)})
if "int" in str(j):
dtypedict.update({i: Integer()})
return dtypedict
# 自定义函数赋值变量
dtypedict = map_types(inp)
# 将数据导入mysql
inp.to_sql(name='table', con=con, if_exists='append', index=False, dtype=dtypedict)
stop_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 获取结束时间
print('从%s开始-%s结束,本次共备份%s条数据' % (start_time,stop_time,row)) # 打印执行结果,调试用。
# 用TXT记录运行日志
txt = open('log.txt','a') # 以增加写入的方式打开txt文件
txt.write(''从%s开始-%s结束,本次共备份%s条数据 \n' % (start_time,stop_time,row)')
txt.close()
pd.to_sql()参数:name=‘表名’,con=连接方式,if_exists= append:追加 /replace:删除原表,建立新表再添加 /fail:什么都不干。dtype = 数据类型,这里使用的是自定义函数中转换的数据类型。
补充一下:使用SQLAlchemy连接数据库时可能会提示缺少MYSQLdb而出错,由于python3已经不再兼容MYSQLdb了,当提示需要安装MYSQLdb时,我们要安装mysqlclient这个库,同样使用pip install安装即可。
本人还是处于学习PYTHON的阶段,如有错误,敬请指正,谢谢!
本文介绍了一种使用Python脚本进行数据库增量备份的方法,通过对比本地和生产数据库的ID,实现数据的高效同步。

2万+

被折叠的 条评论
为什么被折叠?



