mysqlclient操作MySQL關係型資料庫

Winter發表於2019-05-06

本篇文章主要講解mysqlclient操作MySQL關係型資料庫,安裝mysqlclient的命令列: pip install mysqlclient

然後建立一個名為XKD_Python_Course的資料庫和一張名為students的資料庫表,我們先在命令列工具裡面檢視一下表名是否存在,登入mysql資料庫的命令列: mysql -uroot -p ,然後 show databases; ,發現沒有XKD_Python_Course這個資料庫,那我們就建立一個: create database XKD_Python_Course; ,建立完再: show databases; 一下,可以看到XKD_Python_Course資料庫已經存在了

XKD_Python_Course資料庫

  • 然後我們可以使用命令列: use XKD_Python_Course; 進入這個庫,然後開始建立資料庫表;

CREATE TABLE `students` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

建立表

  • 然後可以通過命令列: show create table students; ,檢視一下建立表的建立;

檢視錶建立

  • 還可以通過命令列: desc students; ,檢視錶的結構;

表結構

  • 此時我們已經建立好了資料庫和資料庫表,然後我們需要授權使用者,設定密碼,授權成功之後一定要記得重新整理許可權;

grant all on XKD_Python_Course.* to 'zengzeng'@'%' identified by '123456';
# 重新整理許可權
flush privileges;

  • 授權後我們可以退出,然後登入我們剛剛授權的使用者: mysql -uzengzeng -p123456 ,就可以成功登入,登入後可以 show databases; 檢視一下剛剛建立的資料庫

檢視資料庫

  • 然後我們可以看到裡面有兩個資料庫,如果我們想操作XKD_Python_Cours,那我們就需要使用: use XKD_Python_Course

運算元據庫

剛剛我們安裝的mysqlclient中有一個MySQLdb類,我們可以用這個MySQLdb類去操作mysql資料庫

  • 插入操作 ,在插入之前我們可以先檢視一下資料表裡是否已經存在這條資料: select * from students; ,然後可以放心的進行插入了

import MySQLdb
connect = None   # 連線物件
cursor = None    # 遊標物件
try:
    # 連線物件
    connect = MySQLdb.connect(host='localhost',   # 主機地址
                                  user='zengzeng',    # 賬號
                                  password='123456',   # 密碼
                                  database='XKD_Python_Course',  # 資料庫名
                                  use_unicode=True,
                                  charset='utf8')   # 指定字符集
    # 遊標物件
    cursor = connect.cursor()   # 通過連線物件呼叫cursor()
except Exception as e:
    print(e)
    connect.close()
try:
    if cursor:
        result = cursor.execute("insert into students (name, age) values ('Angle', 18)")  # 插入操作
        print('result = {}'.format(result))
        connect.commit()   # 提交
except Exception as e:
    print(e)
    connect.rollback()   # 回滾
finally:
    if cursor:
        cursor.close()
    if connect:
        connect.close()

執行程式碼,返回的結果是result = 1,表示操作了一行資料,這時我們檢視資料庫表 select * from students; ,是不是發現表中多了一條資料啊;

查詢

  • 批量插入資料 ,就是在插入資料的地方增加一個for迴圈,我們來試一下一次插入10條資料;

import MySQLdb
connect = None   # 連線物件
cursor = None    # 遊標物件
try:
    # 連線物件
    connect = MySQLdb.connect(host='localhost',   # 主機地址
                                  user='zengzeng',    # 賬號
                                  password='123456',   # 密碼
                                  database='XKD_Python_Course',  # 資料庫名
                                  use_unicode=True,
                                  charset='utf8')   # 指定字符集
    # 遊標物件
    cursor = connect.cursor()   # 通過連線物件呼叫cursor()
except Exception as e:
    print(e)
    connect.close()
try:
    if cursor:
        for i in range(10):
            result = cursor.execute("insert into students (name, age) values ('Angle', {})".format(i))  # 插入操作
        connect.commit()   # 提交
except Exception as e:
    print(e)
    connect.rollback()   # 回滾
finally:
    if cursor:
        cursor.close()
    if connect:
        connect.close()

插入多條資料

  • 查詢資料 ,查詢結果的id會隨著遊標往下走

import MySQLdb
from pprint import pprint   # 換行
connect = None   # 連線物件
cursor = None    # 遊標物件
try:
    # 連線物件
    connect = MySQLdb.connect(host='localhost',   # 主機地址
                                  user='zengzeng',    # 賬號
                                  password='123456',   # 密碼
                                  database='XKD_Python_Course',  # 資料庫名
                                  use_unicode=True,
                                  charset='utf8')   # 指定字符集
    # 遊標物件
    cursor = connect.cursor()   # 通過連線物件呼叫cursor()
except Exception as e:
    print(e)
    connect.close()
try:
    if cursor:
        cursor.execute('select * from students')  # 不會返回任何物件,想要拿到資料可以通過cursor.方法名
        one_result = cursor.fetchone()  # 查詢結果集的下一條資料
        many_result = cursor.fetchmany(5)  # 查詢結果集的下五條資料
        all_result = cursor.fetchall()  # 查詢結果集的剩餘所有資料
        # 換行列印
        pprint(one_result)
        print('*' * 100)
        pprint(many_result)
        print('*' * 100)
        pprint(all_result)
        connect.commit()  # 提交
except Exception as e:
    print(e)
    connect.rollback()   # 回滾
finally:
    if cursor:
        cursor.close()
    if connect:
        connect.close()

查詢結果

cursor

  • cursor是遊標物件,用於執行查詢和獲取結果;

cursor遊標支援的方法

  • execute(op[,args]) :執行一個資料庫的查詢和命令;

  • fetchmany(size) :獲取結果集的下幾行務;

  • fetchone() :獲取結果集的下一行;

  • fetchall() :獲取結果集中剩下的所有行;

  • rowcount() :最近一次execute返回資料的行數或影響的行數;

  • close() :關閉遊標物件;

查詢引數化

在使用子查詢的時候,我們就可以使用查詢引數


# 位置引數
cursor.execute('select * from students where id = %s', args=(10, ))
# 關鍵字引數
cursor.execute('select * from students where id = %(id)s', args={'id': 10})

使用上下文管理

會自動關閉遊標


import MySQLdb
connect = MySQLdb.connect(host='localhost',
                          user='zengzeng',
                          password='123456',
                          database='XKD_Python_Course',
                          use_unicode=True,
                          charset='utf8')
with connect as cursor:
    # 會自動關閉cursor物件
    cursor.execute("insert into students (name, age) values ('zengzeng', 22)")
# 此時連線還沒有關閉
cursor.execute("insert into students (name, age) values ('Mark', 23)")
connect.close()

Queue模組

Queue模組實現了多生產者多消費者佇列,尤其適合多執行緒程式設計,Queue類中實現了所有需要的鎖原語,Queue模組實現了三種型別佇列:

  • 第一種,FIFO(先進先出)佇列,第一加入佇列的任務,被第一個取出;

  • 第二種,LIFO(後進先出)佇列,最後加入佇列的任務,被第一個取出(操作類似與棧,總是從棧頂取出,這個佇列還不清楚內部的實現);

  • 第三種,PriorityQueue(優先順序)佇列,保持佇列資料有序,最小值被先取出;

queue模組中的Queue與multiprocessing模組的Queue的區別

  • queue模組中的Queue:是普通的佇列模式,先進先出模式,get方法會阻塞請求,直到有資料get出來為止,適用於多執行緒的場景

from threading import Thread, Event
from queue import Queue
import time
def write(q: Queue, e: Event):
    for value in range(100):
        print('put {} to queue'.format(value))
        q.put(value)
        time.sleep(0.5)
    else:
        e.set()
def read(q: Queue, e: Event):
    while True :
        if not q.empty() or not e.is_set():
            value = q.get()
            print('get {} from queue'.format(value))
            time.sleep(1)
        else:
            break
if __name__ == '__main__':
    q = Queue()
    e = Event()
    tw = Thread(target=write, args=(q,e))
    tr = Thread(target=read, args=(q,e))
    tw.start()
    tr.start()
    tw.join()
    tr.join()
    print('finished ')

  • multiprocessing模組的Queue:是多程式併發的Queue佇列,用於解決多程式間的通訊問題。

from multiprocessing import Process,Queue, Event
import time
def write(q: Queue, e: Event):
    for value in range(100):
        print('put {} to queue'.format(value))
        q.put(value)
        time.sleep(0.5)
    else:
        e.set()
def read(q: Queue, e: Event):
    while True :
        if not q.empty() or not e.is_set():
            value = q.get()
            print('get {} from queue'.format(value))
            time.sleep(1)
        else:
            break
if __name__ == '__main__':
    q = Queue()
    e = Event()
    pw = Process(target=write, args=(q,e))
    pr = Process(target=read, args=(q,e))
    pw.start()
    pr.start()
    pw.join()
    pr.join()
    print('finished ')

Queue佇列物件的方法

  • qsize() :返回佇列的大致大小;

  • empty() :判斷佇列是否為空,如果佇列為空,返回True,反之False;

  • full() :判斷是否滿了;

  • put() :將專案放入佇列;

  • put_nowait :相當於put(item, False);

  • get() :從佇列中刪除並返回一個專案;

  • get_nowait() :提供了兩種方法來支援跟蹤守護程式消費者執行緒是否已完全處理入隊任務;

  • task_done() :表示以前排隊的任務已完成;

  • join() :阻止直到佇列中的所有專案都已獲取並處理完畢;

使用Queue構建連線池


from queue import Queue
import MySQLdb
class ConnectPool:
    def __init__(self, size=5, *args, **kwargs):
        if not isinstance(size, int) or size < 1:
            size = 10
        self.__pool = Queue(size)
        for i in range(size):
            self.__pool.put(MySQLdb.connect(*args, **kwargs))
    @property
    def connect(self):
        return self.__pool.get()
    @connect.setter
    def connect(self, conn):
        self.__pool.put(conn)
if __name__ == '__main__':
    # 構建連線池
    pool = ConnectPool(host='localhost',
                       user='zengzeng',
                       password='123456',
                       database='XKD_Python_Course',
                       use_unicode=True,
                       charset='utf8')
    # 獲取一個連線
    connect = pool.connect
    #
    with connect as cursor:
        with cursor:
            sql = 'select * from students'
            cursor.execute(sql)
            print(cursor.fetchall())

執行緒連線池實現


from queue import Queue
import MySQLdb
import threading
class ConnectPool:
    def __init__(self, size=5, *args, **kwargs):
        if not isinstance(size, int) or size < 1:
            size = 10
        self.__pool = Queue(size)
        for i in range(size):
            self.__pool.put(MySQLdb.connect(*args, **kwargs))
        # 建立一個local物件
        self.local = threading.local()
    @property
    def connect(self):
        return self.__pool.get()
    @connect.setter
    def connect(self, conn):
        self.__pool.put(conn)
    def __enter__(self):
        if getattr(self.local, 'conn', None) is None:
            self.local.conn = self.connect
        return self.local.conn.cursor()
    def __exit__(self, *exc_info):
        if exc_info:
            self.local.conn.rollback()
        else:
            self.local.conn.commit()
        # 將連線物件歸還到連線池
        self.connect = self.local.conn
        # 執行緒級別的連線物件引用計算器減一
        self.local.conn = None
if __name__ == '__main__':
    pool = ConnectPool(host='localhost',
                       user='zengzeng',
                       password='123456',
                       database='XKD_Python_Course',
                       use_unicode=True,
                       charset='utf8')
    def foo(pool):
        with pool as cursor:
            with cursor:  # 對cursor做上下文管理
                sql = 'select * from students'
                cursor.execute(sql)
                print(cursor.fetchall())
    for i in range(5):
        t = threading.Thread(target=foo, args=(pool, ))
        t.start()

參考: https://www.9xkd.com/user/plan-view.html?id=2546175346

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69908432/viewspace-2643371/,如需轉載,請註明出處,否則將追究法律責任。

相關文章