python MySQLdb 一個連接connection多個cursor
使用MySQLdb時,如果創建一個連接connection,多個線程同時使用,會不會有問題?
在下文中,我們將模擬這種場景,看是否會出現問題。
1.示例
1.1 正常的情況
創建一個連接,兩個線程同時使用這個連接,生成遊標cursor,進行查詢,並輸出結果。
程序啟動後,讓線程1睡眠1s,保證讓線程2線執行。
import MySQLdb import threading import time def get_connection(): host = "127.0.0.1" port = 3306 user = "root" passwd = "Aa123456" conn = MySQLdb.connect(host=host, port=port, user=user,passwd=passwd, connect_timeout=2, charset="utf8") return conn def thread1_runtime(conn, sql): time.sleep(1) cursor = conn.cursor() cursor.execute(sql) ret = cursor.fetchone() thread_name = threading.current_thread().name print("thread name:%s, ret:%s" %(thread_name, ret)) def thread2_runtime(conn, sql): cursor = conn.cursor() cursor.execute(sql) ret = cursor.fetchone() thread_name = threading.current_thread().name print("thread name:%s, ret:%s" %(thread_name, ret)) if __name__ == "__main__": thread1_sql = "select 1" thread2_sql = "select 2" conn = get_connection() thread1 = threading.Thread(target=thread1_runtime, name="thread 001", args=(conn, thread1_sql)) thread2 = threading.Thread(target=thread2_runtime, name="thread 002", args=(conn, thread2_sql)) thread1.start() thread2.start() thread1.join() thread2.join() print("...main exit....")
從結果可以看到,一切正常。
output:
thread name:thread 002, ret:(2,)
thread name:thread 001, ret:(1,)
...main exit....
1.2 異常的情況
以下例子中,程序啟動後,線程1和線程2使用同一連接創建新的遊標cursor,執行查詢。
接著,線程1睡眠1秒,線程2睡眠2秒。
最後各自打印查詢結果。
import MySQLdb import threading import time def get_connection(): host = "127.0.0.1" port = 3306 user = "root" passwd = "Aa123456" conn = MySQLdb.connect(host=host, port=port, user=user,passwd=passwd, connect_timeout=2, charset="utf8") return conn def thread1_runtime(conn, sql): cursor = conn.cursor() cursor.execute(sql) time.sleep(1) ret = cursor.fetchone() thread_name = threading.current_thread().name print("thread name:%s, ret:%s" %(thread_name, ret)) def thread2_runtime(conn, sql): cursor = conn.cursor() cursor.execute(sql) time.sleep(2) ret = cursor.fetchone() thread_name = threading.current_thread().name print("thread name:%s, ret:%s" %(thread_name, ret)) if __name__ == "__main__": thread1_sql = "select 1" thread2_sql = "select 2" conn = get_connection() thread1 = threading.Thread(target=thread1_runtime, name="thread 001", args=(conn, thread1_sql)) thread2 = threading.Thread(target=thread2_runtime, name="thread 002", args=(conn, thread2_sql)) thread1.start() thread2.start() thread1.join() thread2.join() print("...main exit....")
output:
Exception in thread thread 002:
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/threading.py", line 864, in runself._target(*self._args, **self._kwargs)
File "one_conn_mutiple_cursor.py", line 28, in thread2_runtime
cursor.execute(sql)
File "/Users/lanyang/workspace/orange-service/.venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 198, in execute
res = self._query(query)
File "/Users/lanyang/workspace/orange-service/.venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 304, in _query
db.query(q)
File "/Users/lanyang/workspace/orange-service/.venv/lib/python3.6/site-packages/MySQLdb/connections.py", line 217, in query
_mysql.connection.query(self, query)
MySQLdb._exceptions.ProgrammingError: (2014, "Commands out of sync; you can‘t run this command now")
thread name:thread 001, ret:(1,)
...main exit....
從打印結果可以看到,線程1可以正常打印結果,但線程2報錯了。
線程1睡眠先結束,去獲取查詢結果,可以打印。
線程2睡眠後結束,再去獲取查詢結果,已經無法獲取結果了。
2.總結
從上面例子中,我們可以得出結論:
一個連接connection同一個時間點只能有一個cursor,執行sql,並獲取結果。
所以,不要在多個線程中同時使用一個連接connection,否則會出現不可預料的結果。
python MySQLdb 一個連接connection多個cursor