由于项目需求以及模块化的需要,此次初版中简单实现了MySQL的封装的升级版,和redis与MySQL的互动,不是很成熟先写出来慢慢改。
配置:
import hashlib
import redis
import pymysql
import time
import json
from DBUtils.PooledDB import PooledDB
"""
利用redis的集合不允许添加重复元素来进行去重
"""
b = {"user": "root",
"passwd": "Lohas123",
"host": "121.40.52.101",
"db": 'price',
"port": 3306,
"charset": 'utf8'
}
class Sql_all:
__mysql_pool=None
__redis=None
#redis连接池初始化配置,此处各位同仁一定注意游标和连接不能全局化,否则全局就一个连接并且一旦释放程序就会报错
def __init__(self):
self.re_con=Sql_all.getredisconn()
# sql连接池
@staticmethod
def getmysqlconn():
if Sql_all.__mysql_pool is None:
__mysql_pool = PooledDB(creator=pymysql, mincached=3, maxcached=20, host=b["host"], user=b["user"],
passwd=b["passwd"], db=b["db"], port=b["port"], charset=b["charset"])
return __mysql_pool.connection()
#redis
@staticmethod
def getredisconn():
if Sql_all.__redis is None:
r= redis.ConnectionPool(host='121.43.198.91', port=6379, db=0,password='Lohas3520')#,password='Lohas3520'
__redis_pool = redis.StrictRedis(connection_pool=r)
return __redis_pool
MySQL封装
#Mysql insert/update/delete
def mysql_insert(self, sql='',value=(),insert_statue=1,_id=None):
"""
实现数据库insert/update/delete
:param _id就是在只插入一个的情况下返回一个id并改变_id值,不用传值默认None,
:param insert_statue: 插入状态int值,1为单词插入一个,2为插入多个值,三或以上为删除或修改模式,默认为1
:param sql: 插入的sql格式
:param value: 当插入一个值时为tuple/list,多个值时为tuple(tuple)/list[list],非插入状态下value可为()
:return:
"""
my_coon = Sql_all.getmysqlconn()
my_cur = my_coon.cursor(cursor=pymysql.cursors.DictCursor)
try:
print('op_insert',sql)
if insert_statue==1:
my_cur.execute(sql,value)
_id = my_cur.lastrowid#获取插入的id
elif insert_statue==2:
my_cur.executemany(sql,value)
else:
my_cur.execute(sql, value)
print("修改中")
my_coon.commit()
print("修改成功")
self.dispose(my_coon,my_cur)
if _id == 0:
return True
return True,_id
except Exception as e:
print(e)
my_coon.rollback()
self.dispose(my_coon,my_cur)
print("修改失败请检查sql语句")
return 0
#Mysql查询
def mysql_select(self,sql='',select_satue=2,num=None,param=None):
"""
实现MySQL数据库取的功能
:param sql:sql查询语句如有体条件,把条件传入param
:param param:可选参数,条件列表值(元祖/列表),默认None
:param num:当只需要查询一部分时候,默认None
:param select_satue,可选状态int类型(或能被转成int得值),1为查询一条,2为查询所有,
3或其他为查询一部分(三种状态都是在指定条件下返回的数量)此时需传入参数num,默认2查询所有
:return:
"""
#必须每次重连并释放,否则数据库会异常的阻塞导致程序无法进行
my_coon = Sql_all.getmysqlconn()
my_cur = my_coon.cursor(cursor=pymysql.cursors.DictCursor)
try:
if param == None:
count=int(my_cur.execute(sql)) # 执行sql
else:
count =int(my_cur.execute(sql,param))
# print(count)
#此处count》0即为查找到值
if count >0:
# print(count)
if int(select_satue)==2:
select_res = my_cur.fetchall()# 返回结果为字典
elif int(select_satue)==1:
select_res=my_cur.fetchone()
else:
select_res=my_cur.fetchmany(num)
else:
select_res=False
print("查询成功")
self.dispose(my_coon,my_cur)
return select_res
except Exception as e:
print('select except ',e)
self.dispose(my_coon,my_cur)
print("查询失败请检查sql语句")
return None
def dispose(self,my_coon,my_cur):
my_coon.close()
my_cur.close()
redis操作
#redis压缩url
def compressed(self,value):
sha1obj = hashlib.sha1()
sha1obj.update(value.encode('utf-8'))
hash_value = sha1obj.hexdigest()
return hash_value
#redis操作(需要被管道监控的前提),0模式为长度对比去重(利用redis管道特性
锁住url或关键字进行去重,在把数据持久化到MySQL),1模式为分页计数
(先利用redis管道锁住page在用MySQL分页)
def redis_operation(self,key,sql_statue,value=None):
"""
:param sql_statue操作redis的模式
:param r:redis连接
:param value:add的数据或者添加的页码数,先压缩在添加
:param key:项目所使用的集合名称,建议如下格式:”projectname:task_remove_repeate“
:return:
"""
# while True:
try:
pipe = self.getredisconn().pipeline()
pipe.watch(key)
# 开启事务
pipe.multi()
#去重模式,长度对比去重
if sql_statue==0:
hash_value = self.compressed(value)
long_1 = self.re_con.scard(key)
self.re_con.sadd(key, hash_value)
long_2 = self.re_con.scard(key)
return long_1,long_2
#翻页模式
elif sql_statue==1:
pageindex=int(self.re_con.get(key))
pageindex += 10
self.re_con.set(key,pageindex)
return pageindex
except Exception as e:
print("redis报错了:",e)
#添加到redis中,数据需要去重的情况使用set比较好
#def add_redis(self,url, set_name,r=None):
# r.sadd(set_name,url)
redis数据到MySQL
#实时取数据到mysql,超过30分钟退出(此状态是数据下载完毕才会有)这个要写到爬虫中去。还没想好如何和上面insert部分结合
def redis_put(self,key):
num=0
while True:
if num>=600:
break
if self.re_con.scard(key)>0:
num=0
h =self.re_con.spop(key)
try:
result=json.loads(str(h,encoding='utf-8').replace("'", "\""))
except Exception as e:
print(e)
self.error_file(h)
continue
else:
num+=1
time.sleep(5)
# #上文json.loads()处理时未明原因报错,此错误线下实验无问题,此处处理异常跳过,收集出错项。###错误待考证
def error_file(self,h):
with open('elong_error_file.txt','w',encoding="utf-8") as f:
f.write(str(h,encoding='utf-8').replace("'", "\""))
def redis_close(self,pool):
"""
释放redis连接池
:param pool:
:return:
"""
pool.disconnect()
由于此篇文章还没写完,目标了也是封装程一个sql组件,当然可能会有些鸡肋,毕竟还有ORM 这个东西,在加上实际上很多东西是已有的,此处了只是想看能不能满足工作需求。不完善的地方请多多指教