python中MySQL數據庫相關操做

一 安裝基本環境

1 簡介

MySQL 基於TCP 協議之上的開發,可是網絡鏈接後,傳輸的數據必須遵循MySQL的協議,封裝好MySQL協議的包,就是驅動程序 python


MySQL 的驅動
MySQLDB 最有名的庫,對MySQL 的C Client 封裝實現,支持python2,不更新了,不支持python3
MySQL 官方的connector
pymysql 語法兼容MySQLdb,使用python寫的庫,支持python3mysql

2 安裝MySQL數據庫

本文使用的是mariadb數據庫,與MySQL類似sql

1 掛載鏡像文件(本次使用的是本地鏡像文件)

python中MySQL數據庫相關操做

2 啓動MySQL數據庫

python中MySQL數據庫相關操做

3 建立用戶名和密碼並刷新

grant all(表示全部操做) on .(庫.表(全部的,也能夠指定)) to root@localhost(設置用戶名爲root,連接爲本地連接) identified by 'roiot123';(設置密碼)數據庫

flush privileges;(刷新權限)緩存

4 修改默認字符集:

python中MySQL數據庫相關操做

server.cnf 中的操做(前面必須有空格,不然不生效,不能寫入漢字)服務器

python中MySQL數據庫相關操做

client.cnf 操做同上網絡

python中MySQL數據庫相關操做

重啓加載字符集多線程

python中MySQL數據庫相關操做

5 查看字符集是否加載完畢

python中MySQL數據庫相關操做

如上,則表示加載完畢!!!socket

6 建立數據庫

python中MySQL數據庫相關操做

二 MySQL-python

1 安裝

1 安裝

python中MySQL數據庫相關操做

2 查看安裝是否完成,若完成,則不會報錯ide

python中MySQL數據庫相關操做

2 鏈接通常流程

創建鏈接
獲取遊標
執行SQL
提交事務
釋放資源

2 MySQL連接基本操做及說明

1 導入MySQLdb 模塊

導入名重命名重命名

python中MySQL數據庫相關操做

2 建立鏈接

參數含義以下

connection 初始化經常使用參數 說明
host 主機
user 用戶名
password 密碼
database 數據庫
port 端口

其中必選參數是user和passwd 其餘可選
其中user 表示數據庫的用戶名,就是上面初始化的用戶名和密碼,db 是上面初始化的數據庫,host 表示本地連接,可使用IP地址或域名進行遠程連接,charset 表示連接使用的字符集,若是和上面的utf8不對應,則可能出現亂碼現象

python中MySQL數據庫相關操做

3 初始化遊標

python中MySQL數據庫相關操做

4 使用遊標.execute('sql')語句負責向MySQL數據庫傳遞消息。

對於數據庫的操做有 增insert 刪 delete 改 update 等 查 select show 等

python中MySQL數據庫相關操做

5 提交

建立完成後須要提交,若是不提交則不生效,提交使用的是建立的連接的關鍵字。

python中MySQL數據庫相關操做

6 關閉連接

須要關閉連接,首先須要關閉的是遊標,其次是連接。

python中MySQL數據庫相關操做

7 查看

在MySQL數據庫中進行查看:

python中MySQL數據庫相關操做

3 數據庫進階

1 顯示設置

顯示與數據庫查詢類似的結果show 和 select
數據庫中的顯示

python中MySQL數據庫相關操做

再次建立一個數據表以備查詢所用

python中MySQL數據庫相關操做

1 進行查看顯示

python中MySQL數據庫相關操做

使用遊標.fetchone()表示每次查看一行操做,兩個表示兩個操做一塊兒輸出

2 顯示全部查看的結果

python中MySQL數據庫相關操做

3 顯示指定的數量

python中MySQL數據庫相關操做

4 進行查看使用cur.scroll(0,'absolute')

將其恢復遊標到起始位置,能夠進行屢次查看,若是沒有此配置,默認重上一次查詢的下一行開始查詢

python中MySQL數據庫相關操做

2 多行插入

1 使用for 循環遍歷的方式插入:

python中MySQL數據庫相關操做

查看

python中MySQL數據庫相關操做

2 將sql 語句與cur.execute 分離的方式插入

python中MySQL數據庫相關操做

查看

python中MySQL數據庫相關操做

3 進行多行插入

python中MySQL數據庫相關操做

查看

python中MySQL數據庫相關操做

當%s 沒有雙引號時:

python中MySQL數據庫相關操做

查看

python中MySQL數據庫相關操做

4 :數據庫應用:

1 生成姓名

python中MySQL數據庫相關操做

python中MySQL數據庫相關操做

查看生成結果:

python中MySQL數據庫相關操做

2 判斷數據庫的某個表是否存在

python中MySQL數據庫相關操做

3 應用封裝mysql數據庫的類

python中MySQL數據庫相關操做
python中MySQL數據庫相關操做python中MySQL數據庫相關操做python中MySQL數據庫相關操做

查看是否生成:

python中MySQL數據庫相關操做
python中MySQL數據庫相關操做

三 pymysql

1 安裝pymysql

1 安裝

pymysql 是第三方模塊庫,須要安裝

pip  install  pymysql

2 參數簡介和基本連接

1 基本參數詳解

pymysql.connect() 方法返回的是connections模塊下的connection類實例,connect方法傳遞就是給connection類的__init__提供參數


源碼以下

def __init__(self, host=None, user=None, password="",
                 database=None, port=0, unix_socket=None,
                 charset='', sql_mode=None,
                 read_default_file=None, conv=None, use_unicode=None,
                 client_flag=0, cursorclass=Cursor, init_command=None,
                 connect_timeout=10, ssl=None, read_default_group=None,
                 compress=None, named_pipe=None,
                 autocommit=False, db=None, passwd=None, local_infile=False,
                 max_allowed_packet=16*1024*1024, defer_connect=False,
                 auth_plugin_map=None, read_timeout=None, write_timeout=None,
                 bind_address=None, binary_prefix=False, program_name=None,
                 server_public_key=None):

上述初始化參數中autocommit=False,則指的是默認的事務提交是關閉的,及須要手動提交事務

Connection.ping() 方法,測試數據庫服務器是否活着,有一個參數熱connection表示斷開與服務器鏈接是否重連

def ping(self, reconnect=True):
        """
        Check if the server is alive.

        :param reconnect: If the connection is closed, reconnect.
        :raise Error: If the connection is closed and reconnect=False.
        """
        if self._sock is None:
            if reconnect:
                self.connect()
                reconnect = False
            else:
                raise err.Error("Already closed")
        try:
            self._execute_command(COMMAND.COM_PING, "")
            self._read_ok_packet()
        except Exception:
            if reconnect:
                self.connect()
                self.ping(False)
            else:
                raise

2 conn.ping 相關測試

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection

conn=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    print (conn.ping(False))
finally:
    if conn:
        print('關閉連接:',conn.ping(False))
        conn.close()

結果以下

python中MySQL數據庫相關操做

3 遊標 Cursor

操做數據庫,必須使用遊標,須要先獲取一個遊標對象

Connection.cursor(cursor=None) 方法返回一個新的遊標對象

鏈接沒有關閉以前,遊標對象能夠反覆使用

cursor參數,能夠指定一個Cursor類,若是爲None,則使用默認Cursor類

數據庫操做須要使用Cursor 類的實例,提供的execute()方法,執行SQL語句,成功返回影響行數。


基本代碼以下

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
conn=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    print (conn.ping(False))
    # 獲取遊標
    cursor=conn.cursor()
    sql="insert into  t(id,username,password)  values(3,'mysql','mysql')"
    line=cursor.execute(sql)
    # 此處未提交事務。若關閉,則直接致使事務回滾
    print (line)
    cursor.close()
finally:
    if conn:
        print('關閉連接:',conn.ping(False))
        conn.close()

結果以下

python中MySQL數據庫相關操做

數據庫結果以下

python中MySQL數據庫相關操做

4 添加事務管理

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
conn=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    print (conn.ping(False))
    # 獲取遊標
    cursor=conn.cursor()
    sql="insert into  t(id,username,password)  values(3,'mysql','mysql')"
    line=cursor.execute(sql)
    # 此處未提交事務。若關閉,則直接致使事務回滾
    print (line)
    cursor.close()
    # 若沒有異常,則提交事務
    conn.commit()
except:  # 若存在異常,則回滾事務
    conn.rollback()
finally:
    if conn:
        print('關閉連接:',conn.ping(False))
        conn.close()

結果以下

python中MySQL數據庫相關操做

數據庫結果以下

python中MySQL數據庫相關操做

5 批量增長數據

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
conn=None
cursor=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    print (conn.ping(False))
    # 獲取遊標
    cursor=conn.cursor()
    for  i in  range(5):
        sql="insert into  t(id,username,password)  values(3,'mysql','mysql')"
        line=cursor.execute(sql)
        print (line)
    # 此處未提交事務。若關閉,則直接致使事務回滾
    # 若沒有異常,則提交事務
    conn.commit()
except:  # 若存在異常,則回滾事務
    conn.rollback()
finally:
    if cursor:
        cursor.close()
    if conn:
        conn.close()

數據庫結果以下

python中MySQL數據庫相關操做

變量的方式插入多行數據

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
conn=None
cursor=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    print (conn.ping(False))
    # 獲取遊標
    cursor=conn.cursor()
    for  i in  range(10,15):
        sql="insert into  t(id,username,password)  values({},'mysql','mysql')".format(i)
        line=cursor.execute(sql)
    # 此處未提交事務。若關閉,則直接致使事務回滾
    # 若沒有異常,則提交事務
    conn.commit()
except:  # 若存在異常,則回滾事務
    conn.rollback()
finally:
    if cursor:
        cursor.close()
    if conn:
        conn.close()

結果以下

python中MySQL數據庫相關操做

6 查詢返回結果

1 概念

cursor類的獲取查詢結果集的方法有fetchone(),fetchmany(size=None),fetchall() 三種


fetchone()方法,獲取結果集的下一行
fetchmany(size=None) 方法,size指定返回的行數的行,None則返回用組
fetchall() 方法,獲取全部行


返回多行,若是走到末尾,就返回空元組,不然返回一個元組,其元素就是每一行的記錄,每一行的記錄都裝載在一個元組中。


注意:fetch操做的是結果集,結果集是保存在客戶端的,也就是說fetch的時候,查詢已經結束了。

2 普通元祖返回

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
conn=None
cursor=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    print (conn.ping(False))
    # 獲取遊標
    cursor=conn.cursor()
    sql="select  * from  t"
    line=cursor.execute(sql)
    print ('獲取一個',cursor.fetchone())  # 獲取一個
    print ('獲取下面兩個',cursor.fetchmany(2)) # 獲取下面兩個
    print ('獲取全部',cursor.fetchall()) # 獲取全部
    cursor.rownumber=0 # 遊標初始化,支持負索引,當大於len的索引,則會不存在
    # 此處未提交事務。若關閉,則直接致使事務回滾
    # 若沒有異常,則提交事務
    print ('獲取全部',cursor.fetchall()) # 獲取全部
    print ('獲取一個',cursor.fetchone())  #此處沒法獲取到了
    conn.commit()

finally:
    if cursor:
        cursor.close()
    if conn:
        conn.close()

結果以下

python中MySQL數據庫相關操做

3 字典返回(字典遊標)

Cursor類有一個Mixin的子類DictCursor
只須要cursor=conn.cursor(DictCursor)就好了
返回多行,放在列表中,元素是字典,表明行,返回是列表

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
from  pymysql.cursors import  DictCursor
conn=None
cursor=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    print (conn.ping(False))
    # 獲取遊標
    cursor=conn.cursor(DictCursor)
    sql="select  * from  t"
    line=cursor.execute(sql)
    print (cursor.fetchall())  # 獲取一個

finally:
    if cursor:
        cursor.close()
    if conn:
        conn.close()

結果以下

python中MySQL數據庫相關操做

7 SQL 注入

1 概念

猜想後臺數據的查詢語句使用拼接字符串的方式,從而通過設計爲服務端傳遞參數,令其拼接處特殊的字符串,返回用戶想要的結果

2 經常使用的SQL注入方式

1 數字拼接

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
from  pymysql.cursors import  DictCursor
conn=None
cursor=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    print (conn.ping(False))
    # 獲取遊標
    cursor=conn.cursor()
    sql="select  * from  t where  id={}".format('5  or 1=1')
    print (sql)
    line=cursor.execute(sql)
    print (cursor.fetchall())  # 獲取一個

finally:
    if cursor:
        cursor.close()
    if conn:
        conn.close()

結果以下

python中MySQL數據庫相關操做

2 字符串拼接

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
from  pymysql.cursors import  DictCursor
conn=None
cursor=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    print (conn.ping(False))
    # 獲取遊標
    name="'test'"
    passwd="'test' or 1=1"
    cursor=conn.cursor()
    sql="select  * from  t where  username={}  and   password ={}".format(name,passwd)
    print (sql)
    line=cursor.execute(sql)
    print (cursor.fetchall())  # 獲取一個

finally:
    if cursor:
        cursor.close()
    if conn:
        conn.close()

結果以下

python中MySQL數據庫相關操做

3 解決SQL 注入方式

1 概念

參數化查詢,能夠有效防止SQL注入,並提升查詢效率

cursor.execute(query,args=None)
args, 必須是元祖,列表或者字典,若是查詢字符串使用%(name)s,就必須使用字典

2 查詢效率高緣由

參數化查詢爲何能提升效率

緣由就是SQL語句緩存

數據庫服務器通常都會對SQL語句編譯和緩存,編譯只是對SQL部分,因此參數化就算有SQL指令也不會被執行


編譯過程,須要詞法分析,語法分析,生成AST,優化,生成執行計劃等過程,比較耗資源,服務端會先查詢是否對同一條語句進行緩存,若是緩存未失效,則不須要再次編譯,從而下降了編譯的成本,減低了內存消耗。


能夠認爲SQL語句字符串就是一個key,若是使用拼接方案,每次發過去的SQL語句都不同,都須要從新編譯並緩存。
大量查詢的時候,首選使用參數化查詢,以節省資源。
開發時,應該使用參數化查詢


注意:這裏說的是查詢字符串的緩存,不是查詢結果的緩存
>
慢查詢通常用不上緩存。

3 具體代碼

字典參數化查詢

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
from  pymysql.cursors import  DictCursor
conn=None
cursor=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    d={'name':"'test'",'passwd':"'test' or 1=1"}
    cursor=conn.cursor()
    sql="select  * from  t where  username=%(name)s  and  password=%(passwd)s"
    line=cursor.execute(sql,d)
    print (cursor.fetchall())  # 獲取一個
finally:
    if cursor:
        cursor.close()
    if conn:
        conn.close()

結果以下

python中MySQL數據庫相關操做

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
from  pymysql.cursors import  DictCursor
conn=None
cursor=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    d={'id': '1 or 1=1'}
    cursor=conn.cursor()
    sql="select  * from  t where  id=%(id)s"
    line=cursor.execute(sql,d)
    print (cursor.fetchall())  # 獲取一個
finally:
    if cursor:
        cursor.close()
    if conn:
        conn.close()

python中MySQL數據庫相關操做

元祖處理

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
from  pymysql.cursors import  DictCursor
conn=None
cursor=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    cursor=conn.cursor()
    L1=[ (i,'admin','admin')  for  i in  range(20,23)]
    for  x  in L1:
        sql="insert  into  t(id,username,password)  values(%s,%s,%s)"
        line=cursor.execute(sql,x)
        print (line)
    conn.commit()
finally:
    if cursor:
        cursor.close()
    if conn:
        conn.close()

結果以下

python中MySQL數據庫相關操做

列表以下

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
from  pymysql.cursors import  DictCursor
conn=None
cursor=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    cursor=conn.cursor()
    L1=[ [i,'admin','admin']  for  i in  range(24,26)]
    for  x  in L1:
        sql="insert  into  t(id,username,password)  values(%s,%s,%s)"
        line=cursor.execute(sql,x)
    conn.commit()
finally:
    if cursor:
        cursor.close()
    if conn:
        conn.close()

結果以下

python中MySQL數據庫相關操做

8 上下文支持

1 查看鏈接和遊標部分源碼

1 鏈接上下文相關源碼以下:

def __enter__(self):
        """Context manager that returns a Cursor"""
        warnings.warn(
            "Context manager API of Connection object is deprecated; Use conn.begin()",
            DeprecationWarning)
        return self.cursor()

    def __exit__(self, exc, value, traceback):
        """On successful exit, commit. On exception, rollback"""
        if exc:
            self.rollback()
        else:
            self.commit()

有上述代碼可得,連接在使用上下文時會自動返回cursor遊標,並在連接關閉時會自動判斷執行語句是否出錯,若出錯,則直接回滾,不然提交,但未定義相關的關閉連接的操做

2 遊標相關源碼

def __enter__(self):
        return self

    def __exit__(self, *exc_info):
        del exc_info
        self.close()

有上述可知,遊標的上下文返回的是本身,關閉連接時遊標會自動關閉連接

2 鏈接相關上下文代碼以下

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
from  pymysql.cursors import  DictCursor
conn=None
cursor=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    with conn as cursor:  #此處返回一個cursor連接
        sql="select * from  t"  
        cursor.execute(sql)  
        print (cursor.fetchmany(5))

finally:
      if  cursor:  #上述的代碼中未使用cursor的上下文,所以此處仍是須要的
              cursor.close()
    if conn:
        conn.close()

結果以下

python中MySQL數據庫相關操做

3 遊標相關代碼以下

#!/usr/bin/poython3.6
#conding:utf-8

from   pymysql.connections import  Connection
from  pymysql.cursors import  DictCursor
conn=None
cursor=None
try:
    conn=Connection('192.168.1.200','test','Admin@Root123','test')
    with conn as cursor:  #此處返回一個cursor連接
        with  cursor:  #此處使用cursor的上下文,默認會關閉其遊標
            sql="select * from  t"
            cursor.execute(sql)
            print (cursor.fetchmany(5))
finally:
    if conn:
        conn.close()

結果以下

python中MySQL數據庫相關操做

鏈接不該該隨隨便便銷燬,應該造成重複使用的習慣,應該是多個cursor共享一個鏈接 。

四 簡單鏈接池的實現

1 概念

這裏的鏈接池,指的是數據庫的鏈接池
鏈接池,是一個容器,裏面存放着已經鏈接到數據庫的鏈接,若是須要鏈接,使用者能夠直接從池中獲取一個鏈接,使用完後歸還便可
從而減小頻繁的建立,銷燬數據庫鏈接的過程,提升了性能。

2 分析

一個鏈接池,應該是一個能夠設置大小的容器,裏面存放着數據庫的鏈接。
使用者須要鏈接,從池中獲取一個鏈接,用完則須要歸還。

3 設計

面向對象的設計思路,構建一個鏈接池
構建時,傳入鏈接的服務器相關參數(主機,端口,用戶名,密碼,庫名稱),還有提供一個池的容量
考慮多線程的使用,使用者從池中get一個鏈接,用完後歸還該鏈接便可。

4 基本代碼實現

#!/usr/local/bin/python3.6
#coding:utf-8
from  pymysql.connections import  Connection
from threading import  local
import queue
class ConnPool:
    def __init__(self,size,*args,**kwargs):
        self.__size=size
        self.__pool=queue.Queue(size)  # 此處用於保存鏈接
        self.local=local()  # 此處用於隔離線程間數據,用於對不一樣的conn進行區分,具體在線程基礎一章全部介紹
        for   i  in  range(size):  # 此處用於生成鏈接池,此處是建立鏈接
            conn=Connection(*args,**kwargs)  # 初始化鏈接
            self.__pool.put(conn)

    @property
    def  maxsize(self):
        return   self.__size
    @property
    def size(self):
        return   self.__pool.qsize()
    def  __getconn(self):  # 此處用於返回conn鏈接
        return  self.__pool.get()
    def  __returnconn(self,conn:Connection):  # 此處用於歸還鏈接
        if  isinstance(conn,Connection):  # 此處如果一個鏈接,則可用於返回
            self.__pool.put(conn)
    def __enter__(self):  # 此處用於返回一個遊標,固然能夠返回一個鏈接
        if  getattr(self.local,'conn',None)  is  None:  # 若不存在,則進行添加,若存在,則返回
            self.local.conn=self.__getconn()
        return   self.local.conn.cursor()
    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            self.local.conn.rollback()
        else:
            self.local.conn.commit()
        self.__returnconn(self.local.conn)
        self.local.conn=None  # 此處若重置此連接,則不會致使cursor的不可用,由於cursor中保存着conn的相關信息,但若被刪除,則會致使所有出錯,del
        # 語句不可輕易執行

pool=ConnPool(3,'192.168.1.120','root','666666','test')
with  pool  as  cursor:
    with cursor:
        sql="select  * from  login"
        cursor.execute(sql)
        print (cursor.fetchall())

        sql="SHOW  PROCESSLIST;"  #此處是SQL 自己自帶的用於查看進程的命令
        cursor.execute(sql)
        for  x  in  cursor:
            print (x)

上述的cursor可以被遍歷的緣由是其中有iter方法,具體源碼以下

def __iter__(self):
        return iter(self.fetchone, None)

結果以下

python中MySQL數據庫相關操做

相關文章
相關標籤/搜索