@thevalakas

Python sqlite, почему возникает ошибка?

Отправляю запросы к базе sqlite возникает вот такая ошибка

Traceback (most recent call last):
File "C:/Users/Arseniy/PycharmProjects/RouletteBot/bot.py", line 24, in
bot.polling(none_stop=True)
File "C:\Users\Arseniy\AppData\Local\Programs\Python\Python36-32\lib\site-packages\telebot\__init__.py", line 244, in polling
self.__threaded_polling(none_stop, interval, timeout)
File "C:\Users\Arseniy\AppData\Local\Programs\Python\Python36-32\lib\site-packages\telebot\__init__.py", line 268, in __threaded_polling
self.worker_pool.raise_exceptions()
File "C:\Users\Arseniy\AppData\Local\Programs\Python\Python36-32\lib\site-packages\telebot\util.py", line 103, in raise_exceptions
six.reraise(self.exc_info[0], self.exc_info[1], self.exc_info[2])
File "C:\Users\Arseniy\AppData\Local\Programs\Python\Python36-32\lib\site-packages\six.py", line 686, in reraise
raise value
File "C:\Users\Arseniy\AppData\Local\Programs\Python\Python36-32\lib\site-packages\telebot\util.py", line 54, in run
task(*args, **kwargs)
File "C:/Users/Arseniy/PycharmProjects/RouletteBot/bot.py", line 21, in send_welcome
user_register(message.from_user.id)
File "C:/Users/Arseniy/PycharmProjects/RouletteBot/bot.py", line 14, in user_register
result = db.query('SELECT * FROM users WHERE tele_id=?', [(user_id)])
File "C:\Users\Arseniy\PycharmProjects\RouletteBot\db.py", line 9, in query
self.cur.execute(sql, args)
sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread.The object was created in thread id 6620 and this is thread id 9420

Код в котором отправляю запрос
import config
import msg
import sqlite3
from db import db
import telebot

db = db('users.db')

bot = telebot.TeleBot(config.TOKEN)

def user_register(user_id):
     user_id = str(user_id)

     result = db.query('SELECT * FROM users WHERE tele_id=?', [(user_id)])

     if len(result.fetchall()) == 0:
          db.query('INSERT INTO users (tele_id) VALUES (?)', [(user_id)])

@bot.message_handler(commands=['start'])
def send_welcome(message):
     user_register(message.from_user.id)
     bot.send_message(message.chat.id, msg.MSG_WELCOME)

bot.polling(none_stop=True)


Код класса с подключением
import sqlite3

class db:
    def __init__(self, db):
        self.con = sqlite3.connect(db)
        self.cur = self.con.cursor()

    def query(self, sql, args):
        self.cur.execute(sql, args)
        self.con.commit()
        return self.cur

    def __del__(self):
        self.con.close()
  • Вопрос задан
  • 5202 просмотра
Решения вопроса 1
@nirvimel
telebotиспользует threading, функции с декоратором message_handler вызываются из потока на его тредпуле. Курсор sqlite3, созданный в конструкторе db из главного потока, не может быть использован в вызове send_welcome -> user_register -> db.query из другого потока.

Перенесите создание курсора cur = self.con.cursor() в метод query и сделайте его локальной переменной.
Или кешируйте создаваемые курсоры в threading.local, если производительность в этой точке критична (не думаю, что это так, исходя из задач бота).
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@igreklpofrss
Для будущих искателей ответа на вопрос. Смотрю вопрос популярный, задавали его 3 года назад, но никто не указал простое решение. Во-первых, SQLIte говорит, что не может работать в нескольких потоках. В ошибке он говорит, что объект соединения с БД был создан в одном потоке, а вы вызываете соединение в другом. Во-вторых, было ли это возможно раньше, когда задавали вопрос, не знаю, но есть простое решение ошибки. Можно "включить" поддержку многопоточности отключив проверку потока в котором вызывается объект. Отключить с помощью аргумента check_same_thread. Но стоит учитывать, что данные могут быть повреждены или неправильно записаны при одновременной записи в БД из разных потоков. Поэтому, если такое может быть, стоит написать "обёртку" с регулировкой потоков или очереди запросов пользователей.

conn = sqlite3.connect(path_db, check_same_thread=False)
Ответ написан
Комментировать
Ваш ответ на вопрос

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

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