@alwaystried

Почему pymysql выдает Already Closed?

Возник конфузъ, из-за которого не работает важная часть кода - просмотр баланса. Причем все было нормально, все работало. Но ни с того ни с сего, код просто стал выдавать Alredy Closed. Прошу помощи у вас, опытные!

Код самого бота:

@dp.callback_query_handler(text="Пополнение")
async def buyit(message: types.Message):
    add_bal = InlineKeyboardMarkup().add(
        InlineKeyboardButton(text="❎ Назад", callback_data="start"),
        InlineKeyboardButton(text=" Пополнить счет", callback_data="balance_add")
    )
    if not db.user_exists(message.from_user.id):
        db.add_user(message.from_user.id)
    global mny
    mny = db.user_money(message.from_user.id)
    await bot.send_message(message.from_user.id,
                           f"\nВаш счет: {db.user_money(message.from_user.id)} руб.", reply_markup=add_bal)


Код для базы данных:

class Database:
    def __init__(self):
        self.connection = pymysql.connect(host='localhost', port=3306, user='root', password='',
                                          db='aiodb')
        self.cursor = self.connection.cursor()

    def user_exists(self, user_id):
        with self.connection:
            result = self.cursor.execute("SELECT * FROM users WHERE teleid = (%s)", (user_id,))
            print(result)
            return bool(result)

    def user_money(self, user_id):
        with self.connection:
            result = self.cursor.execute("SELECT money FROM users WHERE teleid = (%s)", (user_id,))
            rows = self.cursor.fetchall()
            print(result)
            for result in rows:
                print(rows)
                print(result)
            return result[0]


И собственно сама ошибка:

ERROR:asyncio:Task exception was never retrieved
future: <Task finished name='Task-9' coro=<Dispatcher._process_polling_updates() done, defined at /Users/redwest/PycharmProjects/pythonProject/venv/lib/python3.10/site-packages/aiogram/dispatcher/dispatcher.py:407> exception=Error('Already closed')>
Traceback (most recent call last):
  File "/Users/redwest/PycharmProjects/pythonProject/db.py", line 32, in user_money
    result = self.cursor.execute("SELECT money FROM users WHERE teleid = (%s)", (user_id,))
  File "/Users/redwest/PycharmProjects/pythonProject/venv/lib/python3.10/site-packages/pymysql/cursors.py", line 148, in execute
    result = self._query(query)
  File "/Users/redwest/PycharmProjects/pythonProject/venv/lib/python3.10/site-packages/pymysql/cursors.py", line 310, in _query
    conn.query(q)
  File "/Users/redwest/PycharmProjects/pythonProject/venv/lib/python3.10/site-packages/pymysql/connections.py", line 547, in query
    self._execute_command(COMMAND.COM_QUERY, sql)
  File "/Users/redwest/PycharmProjects/pythonProject/venv/lib/python3.10/site-packages/pymysql/connections.py", line 793, in _execute_command
    raise err.InterfaceError(0, "")
pymysql.err.InterfaceError: (0, '')

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/redwest/PycharmProjects/pythonProject/venv/lib/python3.10/site-packages/aiogram/dispatcher/dispatcher.py", line 415, in _process_polling_updates
    for responses in itertools.chain.from_iterable(await self.process_updates(updates, fast)):
  File "/Users/redwest/PycharmProjects/pythonProject/venv/lib/python3.10/site-packages/aiogram/dispatcher/dispatcher.py", line 235, in process_updates
    return await asyncio.gather(*tasks)
  File "/Users/redwest/PycharmProjects/pythonProject/venv/lib/python3.10/site-packages/aiogram/dispatcher/handler.py", line 116, in notify
    response = await handler_obj.handler(*args, **partial_data)
  File "/Users/redwest/PycharmProjects/pythonProject/venv/lib/python3.10/site-packages/aiogram/dispatcher/dispatcher.py", line 283, in process_update
    return await self.callback_query_handlers.notify(update.callback_query)
  File "/Users/redwest/PycharmProjects/pythonProject/venv/lib/python3.10/site-packages/aiogram/dispatcher/handler.py", line 116, in notify
    response = await handler_obj.handler(*args, **partial_data)
  File "/Users/redwest/PycharmProjects/pythonProject/main.py", line 404, in buyit
    mny = db.user_money(message.from_user.id)
  File "/Users/redwest/PycharmProjects/pythonProject/db.py", line 31, in user_money
    with self.connection:
  File "/Users/redwest/PycharmProjects/pythonProject/venv/lib/python3.10/site-packages/pymysql/connections.py", line 360, in __exit__
    self.close()
  File "/Users/redwest/PycharmProjects/pythonProject/venv/lib/python3.10/site-packages/pymysql/connections.py", line 404, in close
    raise err.Error("Already closed")
pymysql.err.Error: Already closed
  • Вопрос задан
  • 546 просмотров
Пригласить эксперта
Ответы на вопрос 2
Vindicar
@Vindicar
RTFM!
В питоне блок with обычно используется для освобождения некоторого ресурса независимо от исхода выполнения кода в блоке with (нормальное выполнение, исключение, ранний return).
В случае с соединением с СУБД, with self.connection: освобождает ресурс, т.е. закрывает это соединение, по завершению блока with. Если тебе нужно, чтобы соединение не закрывалось, не используй with.

Я подозреваю, что ты написал with "потому что в туториале так написано".
Ответ написан
Комментировать
shabelski89
@shabelski89
engineer
в конструкторе создаются объекты подключения и курсора
self.connection = pymysql.connect(host='localhost', port=3306, user='root', password='',
                                          db='aiodb')
        self.cursor = self.connection.cursor()


а в блоке выполнения кода, ты используешь with, открывая заново соединение но без курсора.
можно попробовать типа такого
class Database:
    def __init__(self, config):
        self.config = config
        self.connection = pymysql.connect(**self.config)

    def execute(self, query: str, params: tuple = None):
        try:
            with self.connection as connect:
                cursor = connect.cursor()
                if params is not None:
                    cursor.execute(query, params)
                else:
                    cursor.execute(query)
                return cursor.fetchall()
        except OperationalError as Error:
            print(Error)


обработку типа есть юзер или нет лучше отдельным методом
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы