programing

Programming Error: 스레드에서 생성된 SQLite 개체는 동일한 스레드에서만 사용할 수 있습니다.

goodcopy 2023. 1. 10. 21:21
반응형

Programming Error: 스레드에서 생성된 SQLite 개체는 동일한 스레드에서만 사용할 수 있습니다.

프로그래밍은 처음이라서요MySQL을 사용해 본 적은 있지만, Python Flask 웹사이트에서 SQLite를 사용하는 것은 처음입니다.SQLite 대신 MySQL 구문을 사용하지만 문제를 찾을 수 없습니다.

Piece of my code: 

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegisterForm(request.form)
    if request.method=='POST' and form.validate():
        name =  form.name.data 
        email = form.email.data
        username = form.username.data
        password = sha256_crypt.encrypt(str(form.password.data))

        c.execute("INSERT INTO users(name,email,username,password) 
        VALUES(?,?,?,?)", (name, email, username, password))

        conn.commit

        conn.close()

The error:
 File "C:\Users\app.py", line 59, in register c.execute("INSERT INTO users(name,email,username,password) VALUES(?,?,?,?)", (name, email, username, password))
 ProgrammingError: SQLite objects created in a thread can only be used in that 
 same thread.The object was created in thread id 23508 and this is thread id 
 22640

이름, 이메일 사용자 이름, 비밀번호를 HTML 파일로 사용할 수 없는 건가요?이거 어떻게 풀어요?

감사해요.

데이터베이스에 연결할 때 다음을 추가합니다.

conn = sqlite3.connect('your.db', check_same_thread=False)

커서 'c'는 같은 스레드에 생성되지 않습니다.아마 Flask 앱 실행 시 초기화되었을 것입니다.

다음과 같은 동일한 방법으로 SQLite 개체(conneciton 및 커서)를 생성할 수 있습니다.

  @app.route('/')
  def dostuff():
    with sql.connect("database.db") as con:
      name = "bob"
      cur = con.cursor()
      cur.execute("INSERT INTO students (name) VALUES (?)",(name))
      con.commit()
      msg = "Done"
engine = create_engine(
'sqlite:///restaurantmenu.db',
connect_args={'check_same_thread': False}
)

효과가 있다

다음과 같이 시험해 보십시오.

engine=create_engine('sqlite:///data.db', echo=True, connect_args={"check_same_thread": False})

그것은 나에게 효과가 있었다.

제 경우, sqlite 엔진을 생성하는 두 개의 python 파일에 동일한 문제가 있으며, 따라서 다른 스레드로 동작할 수 있습니다.SQL Chemy 문서를 읽으면 두 파일 모두에서 싱글톤 기술을 사용하는 것이 더 나을 것 같습니다.

# maintain the same connection per thread
from sqlalchemy.pool import SingletonThreadPool
engine = create_engine('sqlite:///mydb.db',
                poolclass=SingletonThreadPool)

모든 케이스가 해결되는 것은 아닙니다.즉, 같은 에러가 발생하는 경우가 있습니다만, 간단하게 극복할 수 있어 브라우저 페이지를 갱신할 수 있습니다.코드를 디버깅하기 위해서만 사용하고 있기 때문에, 이것으로 괜찮습니다.보다 영속적인 솔루션을 이용하려면 Postgre와 같은 다른 데이터베이스를 선택해야 합니다.SQL 또는 기타 데이터베이스

같은 문제가 발생하여 콜이 끝날 때마다 접속을 종료하여 해결했습니다.

results = session.query(something, something).all()
session.close()

https://docs.python.org/3/library/sqlite3.html에서 언급하고 @Snidhi Sofpro가 코멘트에서 지적한 바와 같이

기본적으로 check_same_thread는 True이며 작성 스레드만 연결을 사용할 수 있습니다.False를 설정하면 반환된 연결을 여러 스레드로 공유할 수 있습니다.같은 접속으로 여러 스레드를 사용하는 경우 데이터 손상을 방지하기 위해 사용자가 쓰기 작업을 직렬화해야 합니다.

시리얼화를 실현하는 한 가지 방법:

import threading
import sqlite3
import queue
import traceback
import time
import random

work_queue = queue.Queue()

def sqlite_worker():
    con = sqlite3.connect(':memory:', check_same_thread=False)
    cur = con.cursor()
    cur.execute('''
        CREATE TABLE IF NOT EXISTS test (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            text TEXT,
            source INTEGER,
            seq INTEGER
        )
    ''')
    while True:
        try:
            (sql, params), result_queue = work_queue.get()
            res = cur.execute(sql, params)
            con.commit()
            result_queue.put(res)
        except Exception as e:
            traceback.print_exc()

threading.Thread(target=sqlite_worker, daemon=True).start()

def execute_in_worker(sql, params):
    # you might not really need the results if you only use this
    # for writing unless you use something like https://www.sqlite.org/lang_returning.html
    result_queue = queue.Queue()
    work_queue.put(((sql, params), result_queue))
    return result_queue.get(timeout=5)

def insert_test_data(seq):
    time.sleep(random.randint(0, 100) / 100)
    execute_in_worker(
        'INSERT INTO test (text, source, seq) VALUES (?, ?, ?)',
        ['foo', threading.get_ident(), seq]
    )

threads = []
for i in range(10):
    thread = threading.Thread(target=insert_test_data, args=(i,))
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()

for res in execute_in_worker('SELECT * FROM test', []):
    print(res)

# (1, 'foo', 139949462500928, 9)
# (2, 'foo', 139949496071744, 5)
# (3, 'foo', 139949479286336, 7)
# (4, 'foo', 139949487679040, 6)
# (5, 'foo', 139949854099008, 3)
# (6, 'foo', 139949470893632, 8)
# (7, 'foo', 139949862491712, 2)
# (8, 'foo', 139949845706304, 4)
# (9, 'foo', 139949879277120, 0)
# (10, 'foo', 139949870884416, 1)

대로 삽입되어 여전히 whileloopsyslog.syslog..syslog.

이 오류는 에서 호출된 변수에는 없습니다..execute()SQLite가 DB에 액세스하기 위해 사용하는 객체 인스턴스입니다.
다음 사항이 있을 것으로 생각합니다.

conn = sqlite3.connect('your_database.db')
c = conn.cursor()

이 스크립트는 처음 실행할 때 초기화됩니다.
언제?register함수를 호출하면 처음 실행한 스크립트와는 다른 새 스레드가 프로세스를 처리합니다.따라서 이 새로운 스레드에서는 SQLite가 오류로 캡처한 다른 스레드의 오브젝트 인스턴스를 사용하고 있습니다.이러한 인스턴스는 앱 실행 중에 다른 스레드에서 DB에 액세스할 것으로 예상할 경우 데이터가 손상될 수 있기 때문입니다.
따라서 다른 방법으로 동일한 스레드 SQLite 체크 기능을 비활성화하는 대신 호출되는 HTTP 메서드 내에서 DB 연결 및 커서를 초기화해 볼 수 있습니다.
이를 통해 SQLite 객체와 사용률은 런타임에 동일한 스레드 상에 있게 됩니다.

코드는 장황하지만, 데이터에 비동기적으로 액세스 하고 있는 상황에서는 데이터를 보호할 수 있을 뿐만 아니라 데이터의 파손도 방지할 수 있습니다.

안녕하세요?sqlite3에서도 같은 문제가 발생했어요!

  • 나는 그 오류를 이용하여 이 문제를 해결했다.

database.py 파일을 만들었습니다.

-그리고 나는 썼다.

import sqlite3

def dbcon():
    db = sqlite3.connect("your.db")
    cur = db.cursor()
    return cur

그럼 사용하려는 곳에서 가져오기만 하면 됩니다.

from database import dbcon

db = dbcon()

db.execute("INSERT INTO users(name,email,username,password) 
        VALUES(?,?,?,?)", (name, email, username, password))

스레드가 바로 끊어지기 때문에 닫을 필요가 없을지도 모릅니다.포옹! :)

언급URL : https://stackoverflow.com/questions/48218065/programmingerror-sqlite-objects-created-in-a-thread-can-only-be-used-in-that-sa

반응형