import contextlib
import redis
import pymysql
IS_DEV = False
if IS_DEV:
# 正式版redis
REDIS = {
'host': '**********.redis.rds.aliyuncs.com',
'port': 6379,
'db': 11,
'password': '********'
}
# 正式版數據庫
DB_INFO = {
'host': '************.mysql.rds.aliyuncs.com',
'port': 3306,
'user': 'mysqlsa',
'password': '********',
'db': '*****agent'
}
ADS_INFO = {
'host': '************.ads.aliyuncs.com',
'port': 3306,
'user': 'agent_sa',
'password': '********',
'db': '*****agent'
}
else:
# 測試版 線下 redis
REDIS = {
'host': '192.168.0.8',
'port': 6379,
'db': 10,
'password': '******'
}
# 測試版數據庫
DB_INFO = {
'host': '***********.mysql.rds.aliyuncs.com',
'port': 3306,
'user': 'mysqlsa',
'password': '*******',
'db': '******agent'
}
ADS_INFO = {
'host': '***********.ads.aliyuncs.com',
'port': 3306,
'user': 'mysqlsa',
'password': '********',
'db': '******agent'
}
# 創建數據庫連接池池
class DatabaseConnectPool:
'''
數據庫連接池類 支持多庫多池
'''
def __init__(self, module, credentials, size=10):
'''
:param module: 數據庫驅動 例如 pymysql
:param credentials: 數據庫連接信息
credentials={
'DB_INFO' = {
'host': 'rm-uf6t4r3u8vea8u340971.mysql.rds.aliyuncs.com',
'port': 3306,
'user': 'res_sql',
'password': 'Lansi321',
'db': 'lansi_agent'
}
}
:param size: 每個連接池最大連接數量
'''
self.__module = module
self.__credentials = credentials
self.__databases = {}
self.__size = size
def get(self, pool_name):
'''
根據連接池名稱獲取連接
:param pool_name:
:return:
'''
if pool_name not in self.__credentials:
raise Exception('數據庫信息不存在')
elif pool_name not in self.__databases:
self.__databases[pool_name] = []
self.create_connection(pool_name)
elif not self.__databases[pool_name]:
self.create_connection(pool_name)
con = self.__databases[pool_name].pop()
try:
con.ping()
except Exception as e:
con = e
return con
def create_connection(self, pool_name):
'''
創建數據庫連接
:param pool_name:
:return:
'''
if pool_name not in self.__credentials:
raise Exception('數據庫信息不存在')
db_info = self.__credentials[pool_name]
con = self.__module.connect(**db_info)
self.__databases[pool_name].append(con)
def put(self, pool_name, con):
'''
把數據庫連接放回連接池
:param pool_name:
:param con:
:return:
'''
if isinstance(con, self.__module.connections.Connection):
if len(self.__databases[pool_name]) > self.__size:
con.close()
self.__databases[pool_name].insert(0, con)
else:
try:
con.close()
except:
pass
def __del__(self):
for con_list in self.__databases.values():
for con in con_list:
try:
con.close()
except:
pass
db_info = {
# 連接池名稱: 數據庫信息
'rds': DB_INFO,
'ads': ADS_INFO
}
db_pool = DatabaseConnectPool(pymysql, db_info)
def search_sql_pool(total_sql, pool_name='rds', result_type='dict'):
'''
多庫查詢
:param total_sql: 被執行的sql
:param pool_name: 連接池名稱
:param db_name: 數據庫名
:param result_type: 返回結果類型 默認字典
:return:
'''
# 從數據庫連接池池中獲取連接池
db = db_pool.get(pool_name)
# 如果沒有取出連接 直到取到連接
while isinstance(db, str):
db = db_pool.get(pool_name)
if result_type == 'dict':
try:
with db.cursor(pymysql.cursors.DictCursor) as cursor:
# 使⽤execute⽅法執⾏SQL語句
cursor.execute(total_sql)
# 獲取數據
data = cursor.fetchall()
# 提交
db.commit()
except Exception as e:
data = e
finally:
db_pool.put(pool_name, db)
# 返回列表類型查詢結果
else:
try:
with db.cursor() as cursor:
# 使⽤execute⽅法執⾏SQL語句
cursor.execute(total_sql)
# 獲取數據
data = cursor.fetchall()
# 提交
db.commit()
except Exception as e:
data = e
finally:
db_pool.put(pool_name, db)
return data
def rds_sql(total_sql):
'''
RDS查詢 返回字典
:param total_sql:
:return:
'''
return search_sql_pool(total_sql, pool_name='rds')
def rds_list_sql(total_sql):
'''
RDS查詢 返回列表
:param total_sql:
:return:
'''
return search_sql_pool(total_sql, pool_name='rds', result_type='list')
def ads_sql(total_sql):
'''
ADS查詢 返回字典
:param total_sql:
:return:
'''
return search_sql_pool(total_sql, pool_name='ads')
def ads_list_sql(total_sql):
'''
ADS查詢 返回列表
:param total_sql:
:return:
'''
return search_sql_pool(total_sql, pool_name='ads', result_type='list')
# 創建redis連接池
class RedisConnectPool:
'''
redis連接池 使用的是對redis模塊封裝了一層
'''
def __init__(self, redis_info, size=10):
'''
初始化連接池
:param redis_info: {
'host': '192.168.0.8',
'port': 6379,
'db': 10,
'password': 'Lansi.123'
}
:param size: 每個連接池最大連接數量
'''
self.__redis_info = redis_info
self.__connections = []
self.__size = size
@contextlib.contextmanager
def get(self):
'''
獲取一個連接
:return:
'''
if not self.__connections:
self.create_connection()
con = self.__connections.pop()
con.ping()
yield con
self.put(con)
def create_connection(self):
'''
創建連接
:return:
'''
con = redis.Redis(decode_responses=True, **self.__redis_info)
self.__connections.append(con)
def put(self, con):
'''
把連接放回連接池
:param con:
:return:
'''
if isinstance(con, str):
return
if self.__size < len(self.__connections):
con.close()
elif isinstance(con, redis.client.Redis):
self.__connections.insert(0, con)
else:
try:
con.close()
except:
pass
def __del__(self):
for con in self.__connections:
try:
con.close()
except:
pass
redis_pool = RedisConnectPool(REDIS)
if __name__ == '__main__':
date = rds_sql('select now()')
if isinstance(date, str):
print('ERROR: {}'.format(date))
else:
print(date)
with redis_pool.get() as con:
print(con.keys('*'))
print(con.get('test_key'))