redis作为缓存,mysql用来做数据实际存储
import ast
import re
import time
import pymysql
import redis
class Settings(object):
#redis 的连接配置
redis_conn_config = dict(
host=‘localhost’,
port=6379,
db=‘0’,
password=None,
encoding=‘utf-8’,
decode_responses=True,
)
# redis 的键名(用set集合做缓存)
redis_key_name = 'data'
# 写入redis异常信息的 存储文件
redis_error_file = 'redis_error.log'
# 每次从 redis中取多少量的数据
redis_pop_num = 100
# mysql的连接配置,并去创建相应的数据库与表
mysql_conn_config = dict(
host='xxxxxxxxxxx',
port=3306,
user='xxx',
password='xxxx',
# 选择数据库,自己创建
database='xxxxx',
charset='utf8',
)
# mysql的连接表名, 写自己创建的数据库下对应的数据表名
mysql_table_name = ''
# mysql中过滤的字段, 进行自定义的设置
mysql_filter_name = ['']
# mysql 异常 信息的保存文件
mysql_error_file = 'mysql_error.log'
# 等待多少秒后 redis中仍无数据,就停止服务
exit_wait_seconds = 10
class Pipeline_to_redis_server(object):
“”“redis管道类,将数据写入到 redis中”""
#建立redis的连接
def init(self, settings=Settings):
self.settings = Settings
self.redis_conn = redis.StrictRedis(**self.settings.redis_conn_config)
# 向redis中加入数据
def add_data(self,data_s:list):
# 拼接 key
redis_sql = 'sadd s%' %self.settings.redis_key_name + ' '
# 遍历数据 data_s 是一个 列表中 嵌套的 字典数据,遍历出来的是 每一个个字典,
for data in data_s:
# \s代表正则表达式中的一个空白字符(可能是空格、制表符、其他空白)。
data_str = re.sub('\s', '', str(data))
redis_sql += data_str + ' '
# 执行sql语句和异常处理
try:
# 执行sql语句,将数据添加到 redis的集合中,集合有去重的功能
self.redis_conn.execute_command(redis_sql)
except:
# 出现写入数据异常,将该数据的 信息写入到 log日志中
with open(self.settings.redis_error_file, 'a') as f:
f.write(str(data_str) + '\n')
class Redis_to_mysql_server(object):
“”“将缓存数据从redis中保存到mysql中”""
def init(self, setting=Settings):
# 加载redis和mysql的配置文件
self.settings = setting
# 创建redis连接对象
self.redis_conn = redis.StrictRedis(**self.settings.redis_conn_config)
# 创建mysql的连接对象
self.mysql_conn = pymysql.Connection(**self.settings.mysql_conn_config)
# 创建mysql的游标对象
cs = self.mysql_conn.cursor()
cs.execute(‘show columns from %s’ % self.settings.mysql_table_name)
# 结果为一个元组里面嵌套着小元组
# 数据格式为 ((‘id’, ‘int(11)’, ‘NO’, ‘PRI’, None, ‘auto_increment’), (‘category1’, ‘varchar(100)’, ‘YES’, ‘’, None, ‘’), (‘category2’, ‘varchar(100)’, ‘YES’, ‘’, None, ‘’), (‘category3’, ‘varchar(100)’, ‘YES’, ‘’, None, ‘’), (‘book_name’, ‘varchar(200)’, ‘YES’, ‘’, None, ‘’))
table_data_s = cs.fetchall()
self.column_name_s = []
for table_data in table_data_s:
# table_data[0]:‘id’,‘category1’,即数据库中的字段名
column_name = table_data[0]
# self.settings.mysql_filter_name:条件过滤字段,可以设定哪些字段不需要
if column_name not in self.settings.mysql_filter_name:
self.column_name_s.append(column_name)
cs.close()
def run(self):
# 创建mysql的游标对象
cs = self.mysql_conn.cursor()
single_field = ''
# 修改 column_name_s列表,因为列表数不能再 sql语句中操作single_field
for field in self.column_name_s:
single_field += '%s,' % field
sql_base = 'insert into %s (%s) values' %(self.settings.mysql_table_name, single_field[0:-1])
# 初始化开始的时间,是为了防止 redis从一开始就没有数据,依然能够执行到 下面的没有数据的逻辑中的 execute_time
# 保证代码的完整性
execute_time = time.time()
while True:
# self.settings.redis_key_name:redis的键名
# self.settings.redis_pop_num:要从redis的集合中拿出的数据的 条数
# redis_data_s:返回的结果是: 对应键下的 100 行数据
redis_data_s = self.redis_conn.execute_command('spop %s %s' %(self.settings.redis_key_name, self.settings.redis_pop_num))
# 如果有数据
if redis_data_s:
# 计算有数据开始的时间
execute_time = time.time()
total_value = ''
for redis_data in redis_data_s:
#要用 ast还原成 字典
data_dict = ast.literal_eval(redis_data)
single_value = ''
for column_name in self.column_name_s:
if column_name in data_dict.keys()
single_value += '"%s",' % data_dict[column_name]
else:
single_value += '"",'
total_value += '(%s),' % single_value[0:-1]
sql_inster = sql_base + total_value[0:-1]
# 执行sql语句
try:
# 通过游标对象执行 sql语句
cs.execute(sql_inster)
self.mysql_conn.commit()
except:
# 如果出现错误 那么 将出现错误的数据 写入到 日志中
with open(self.settings.mysql_error_file, 'a') as f:
f.write(str(redis_data_s) + '\n')
# 如果没有数据
else:
# 获取没有数据时的时间
empty_time = time.time()
# 判断是否满足结束的条件,是 没有数据的时间
# self.settings.exit_wait_seconds:这里设置的10秒,超过这个时间如果还没有数据 就表明 数据已读取完。
if empty_time - execute_time > self.settings.exit_wait_seconds:
return "finished"
测试运行
if name == ‘main’:
redis_server = Pipeline_to_redis_server(Settings)
setting = Settings()
setting.mysql_table_name = ‘t_data’
setting.mysql_filter_name = [‘id’]
server = Redis_to_mysql_server(setting)
server.run()