1. 程式人生 > >python MySQLdb 一個連接connection多個cursor

python MySQLdb 一個連接connection多個cursor

exception you 連接 etc reading runt ora connect str

使用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 run

self._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