2011-07-16 113 views
3

我在Arch Linux x86_64上使用Python 3.2.1。
我想在一個線程,定時循環類似於下面的一些代碼,更新SQLite數據庫:python:如何共享與隊列線程之間的sqlite連接?

import sqlite3 
from threading import Timer 
from queue import Queue 

class DBQueue(Queue): 
    def give(self, item): 
     self.task_done() 
     self.join() 
     self.put(item) 
     return True 


def timer(): 
    print('A') 
    Timer(3, add).start() 


def add(): 
    print('B') 
    db = qdb.get() 
    cur = db.cursor() 
    cur.execute('INSERT INTO Foo (id) VALUES (NULL)') 
    qdb.give(db) 
    timer() 

qdb = DBQueue() 
# SOLUTION #1: 
# qdb.put(sqlite3.connect(':memory:', check_same_thread=False)) 
# SOLUTION #2: see Eli Bendersky's answer 
qdb.put(sqlite3.connect(':memory:')) 
db = qdb.get() 
cur = db.cursor() 
cur.execute('CREATE TABLE Foo (id INTEGER PRIMARY KEY)') 
qdb.give(db) 
timer() 

不幸返回:

A 
B 
Exception in thread Thread-1: 
Traceback (most recent call last): 
    File "/usr/lib/python3.2/threading.py", line 736, in _bootstrap_inner 
    self.run() 
    File "/usr/lib/python3.2/threading.py", line 942, in run 
    self.function(*self.args, **self.kwargs) 
    File "/home/dario/dev/python/prova/src/prova4.py", line 27, in add 
    cursor = db.cursor() 
sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread.The object was created in thread id 140037302638336 and this is thread id 140037262886656 

僅僅共享光標不提供更好的結果:

conn = sqlite3.connect(':memory:') 
qdb.put(conn.cursor()) 

我敢肯定我沒有在所有了解如何使用隊列線程之間共享數據庫,CA有人幫助我嗎? 謝謝!

+1

兩美分:不要在Python中使用線程,而應使用多處理,並在每個進程中使用單獨的數據庫連接。 – James

+0

謝謝,我會看看多處理,但是,請參閱我在Eli的回答中的評論,我想避免多個連接,因爲我不想提交更改。在這種情況下真的不可能使用隊列嗎? – kynikos

+0

如果我用'check_same_thread = False'連接到數據庫,如果我正在使用隊列,會是危險的嗎? – kynikos

回答

2

您不需要Queue - 只需從兩個線程使用單獨的連接到同一個數據庫。請記住,單獨的連接將數據提交到數據庫時,您不應期望排序太多。對待它就好像你有兩個不同的程序實例同時訪問數據庫。


如果由於某種原因你覺得你絕對必須共享一個連接,然後再嘗試這樣的:因爲你打從一個線程創建SQLite的對象,並在另一個使用它們的問題,爲什麼不委派任務在單線程中處理db/connection,並通過Queue與其他人進行通信。更具體地說:

  • 線程DB_thread:「擁有」連接。從其他線程獲取命令,執行它們,將結果放入「結果隊列」中。線程A,B,C:將「命令」傳遞到隊列中,並從「結果隊列」中獲取結果。

請注意,這些命令不是SQLite對象。

+0

謝謝,但是在真正的程序中,我使用的是文件數據庫,而不是:memory :,我不想提交更改,直到我明確保存它; python文檔說:「當一個數據庫被多個連接訪問,並且其中一個進程修改數據庫時,SQLite數據庫被鎖定,直到該事務被提交」,但是我會試一試,並在這裏報告結果 – kynikos

+0

這是正如我記得的那樣,如果我使用多個連接,我必須提交更改以使它們可用於其他連接,並且我想避免這種情況。真的不可能用sqlite使用隊列嗎?否則,我將不得不復制整個數據庫:內存:或使用臨時文件... – kynikos

+0

@kynikos:我已經更新了答案 –