Как реализовать переподключение к БД
Я пишу простейший API для генерации капчи на Python 3.8. Ключи доступа у меня хронятсься в MySql на удаленном сервере (хостинге), а программа у меня запущена на локалке. Однако после долгого бездействия подключение к БД теряется, так как на сервере установлен timeout. По началу я думал просто увеличить его, но понимаю что это не выход, так как хочу что бы программа работала 24/7. Вот мой класс базы данных:
class DataBase:
def __init__(self):
self.core = API_Core()
self.connection = pymysql.connect(
host=config.host,
user=config.name,
password=config.passwd,
db=config.name,
charset="utf8",
cursorclass=DictCursor
)
self.cursor = self.connection.cursor()
timeout = 2147482
self.cursor.execute(query=f"""SET SESSION wait_timeout := {timeout};""")
self.connection.commit()
log.debug("db inited")
def add_key(self, access=10, expires=Access_levels.key_live_time)->str:
key = self.core.generate_key()
q = f"""INSERT INTO api_keys (access, api_key, expires) VALUES ({access}, '{key}', {int(time.time()) + expires})"""
cur = self.connection.cursor()
cur.execute(q)
self.connection.commit()
return key
def __check_key_access(self, key: str) -> int:
"""Get access level for key"""
q = f"""SELECT access FROM api_keys WHERE api_key='{key}'"""
cur = self.connection.cursor()
cur.execute(q)
return cur.fetchone()
def do_some_action(self, key: str, action: str):
pass # TODO
acc = self.__check_key_access(key=key)["access"]
if acc >= eval(f"Access_levels.{action}"):
if action == "get_captcha":
return True
# TODO Time limit
if action == "get_unlim_captcha":
return True
if action == "add_new_user":
key = self.add_key()
return key
if action == "del_user":
pass # TODO
if action == "get_user_data":
pass # TODO
Соответственно я сформулировал несколько вопросов: Нужно ли отключаться от БД на время бездействия? И как это реализовать? Как сделать так что бы программа не вылетала с ошибкой, если после долгого бездействия программа пытается отправить запрос к БД? Если можно оставлять соединение открытым и на безопасность/быстродействие/ ресурсы это никак не влияет, то как сделать так что бы сервер не разрывал подключение? Просто не удалять курсоры? Или как?
Ответы (3 шт):
Либо выставить длительное ожидание в MySql
SET GLOBAL connect_timeout=....;
Желательно при работе с базой всегда проверяйте активность подключения.
Возможно Вам стоит рассмотреть пул подключений к базе. Подобная реализация поддерживает пул соединений с базой и каждый раз при работе выдает готовое соединение, после чего возвращает его в пул. Кол-во соединений задаете вы. При этом при работе с другими БД (Oracle, PostgreSQL) возможно задать максимальное число соединений (сколько одновременно может быть открыто) и кол-во открытых на старте.
import mysql
from contextlib import contextmanager
class MSPool:
def __init__(self):
dbconfig = {
"database": "test",
"user": "joe"
}
conn_pool = mysql.pooling.MySQLConnectionPool(pool_name = "mypool",
pool_size = 3,
**dbconfig)
if self.conn_pool:
print("Connection pool created successfully")
@contextmanager
def connect(self):
con = self.conn_pool.get_connection()
try:
yield con
con.commit()
finally:
con.close()
pool = MSPool()
with pool.connect() as conn:
#работа с подключением
Как вариант можно создать методы. Первый будет отвечать за подключение к базе, и хранить объект pymysql.connect в self.connection:
def __init__(self):
self.connection = None
...
def mysql_conn(self):
try:
self.connection = pymysql.connect(
host=config.host,
user=config.name,
password=config.passwd,
db=config.name,
charset="utf8",
cursorclass=DictCursor
)
except pymysql.Error as e:
print('MySQL Error: ' + e.args[1])
Второй, за проверку соединения. Перед запросом проверять подключение, если соединения нет вызывать метод mysql_conn:
def mysql_check_conn(self):
if not self.connection.open:
self.mysql_conn()
Если постоянно идут запросы, то наверно стоит держать соединение открытым.