1. 程式人生 > >Navicat工具、pymysql模塊

Navicat工具、pymysql模塊

不能 組成 title exc 的區別 移動 獲取 生產 tps

閱讀目錄

  • 一 IDE工具介紹
  • 二 pymysql模塊

一 IDE工具介紹(Navicat)

  生產環境還是推薦使用mysql命令行,但為了方便我們測試,可以使用IDE工具,我們使用Navicat工具,這個工具本質上就是一個socket客戶端,可視化的連接mysql服務端的一個工具,並且他是圖形界面版的。我們使用它和直接使用命令行的區別就類似linux和windows系統操作起來的一個區別。

下載鏈接:https://pan.baidu.com/s/1bpo5mqj

  Navicat的安裝教程看這篇博客:https://www.cnblogs.com/clschao/articles/10022040.html

  

技術分享圖片
掌握:
#1. 測試+鏈接數據庫
#2. 新建庫
#3. 新建表,新增字段+類型+約束
#4. 設計表:外鍵
#5. 新建查詢
#6. 備份庫/表

#註意:
批量加註釋:ctrl+?鍵
批量去註釋:ctrl+shift+?鍵
技術分享圖片

二 pymysql模塊

  我們要學的pymysql就是用來在python程序中如何操作mysql,它和mysql自帶的那個客戶端還有navicat是一樣的,本質上就是一個套接字客戶端,只不過這個套接字客戶端是在python程序中用的,既然是客戶端套接字,應該怎麽用,是不是要連接服務端,並且和服務端進行通信啊,讓我們來學習一下pymysql這個模塊

#安裝
pip3 install pymysql

  一 鏈接、執行sql、關閉(遊標)

    技術分享圖片

技術分享圖片
import pymysql
user=input(‘用戶名: ‘).strip()
pwd=input(‘密碼: ‘).strip()

#鏈接,指定ip地址和端口,本機上測試時ip地址可以寫localhost或者自己的ip地址或者127.0.0.1,然後你操作數據庫的時候的用戶名,密碼,要指定你操作的是哪個數據庫,指定庫名,還要指定字符集。不然會出現亂碼
conn=pymysql.connect(host=‘localhost‘,port=3306,user=‘root‘,password=‘123‘,database=‘student‘,charset=‘utf8‘) #指定編碼為utf8的時候,註意沒有-,別寫utf-8,數據庫為
#得到conn這個連接對象 #遊標 cursor=conn.cursor() #這就想到於mysql自帶的那個客戶端的遊標mysql> 在這後面輸入指令,回車執行 #cursor=conn.cursor(cursor=pymysql.cursors.DictCursor) #獲取字典數據類型表示的結果:{‘sid‘: 1, ‘gender‘: ‘男‘, ‘class_id‘: 1, ‘sname‘: ‘理解‘} {‘字段名‘:值} #然後給遊標輸入sql語句並執行sql語句execute sql=‘select * from userinfo where name="%s" and password="%s"‘ %(user,pwd) #註意%s需要加引號,執行這句sql的前提是醫藥有個userinfo表,裏面有name和password兩個字段,還有一些數據,自己添加數據昂 print(sql) res=cursor.execute(sql) #執行sql語句,返回sql查詢成功的記錄數目,是個數字,是受sql語句影響到的記錄行數,其實除了受影響的記錄的條數之外,這些記錄的數據也都返回了給遊標,這個就相當於我們subprocess模塊裏面的管道PIPE,乘放著返回的數據
#all_data=cursor.fetchall() #獲取返回的所有數據,註意凡是取數據,取過的數據就沒有了,結果都是元祖格式的
#many_data=cursor.fetchmany(3) #一下取出3條數據,
#one_data=cursor.fetchone() #按照數據的順序,一次只拿一個數據,下次再去就從第二個取了,因為第一個被取出去了,取一次就沒有了,結果也都是元祖格式的

fetchone:(1, ‘男‘, 1, ‘理解‘)
fetchone:(2, ‘女‘, 1, ‘鋼蛋‘)
fetchall:((3, ‘男‘, 1, ‘張三‘), (4, ‘男‘, 1, ‘張一‘))

#上面fetch的結果都是元祖格式的,沒法看出哪個數據是對應的哪個字段,這樣是不是不太好看,想一想,我們可以通過python的哪一種數據類型,能把字段和對應的數據表示出來最清晰,當然是字典{‘字段名‘:值}
#我們可以再創建遊標的時候,在cursor裏面加上一個參數:cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)獲取的結果就是字典格式的,fetchall或者fetchmany取出的結果是列表套字典的數據形式

上面我們說,我們的數據取一次是不是就沒有了啊,實際上不是的,這個取數據的操作就像讀取文件內容一樣,每次read之後,光標就移動到了對應的位置,我們可以通過seek來移動光標
同樣,我們可以移動遊標的位置,繼續取我們前面的數據,通過cursor.scroll(數字,模式),第一個參數就是一個int類型的數字,表示往後移動的記錄條數,第二個參數為移動的模式,有兩個值:absolute:絕對移動,relative:相對移動
#絕對移動:它是相對於所有數據的起始位置開始往後面移動的
#相對移動:他是相對於遊標的當前位置開始往後移動的

#絕對移動的演示
#print(cursor.fetchall())
#cursor.scroll(3,‘absolute‘) #從初始位置往後移動三條,那麽下次取出的數據為第四條數據
#print(cursor.fetchone())

#相對移動的演示
#print(cursor.fetchone())
#cursor.scroll(1,‘relative‘) #通過上面取了一次數據,遊標的位置在第二條的開頭,我現在相對移動了1個記錄,那麽下次再取,取出的是第三條,我相對於上一條,往下移動了一條
#print(cursor.fetchone())
print(res) #一個數字 cursor.close() #關閉遊標 conn.close() #關閉連接 if res: print(‘登錄成功‘) else: print(‘登錄失敗‘)
技術分享圖片

  技術分享圖片

  二 execute()之sql註入

    之前我們進行用戶名密碼認證是先將用戶名和密碼保存到一個文件中,然後通過讀文件裏面的內容,來和客戶端發送過來的用戶名密碼進行匹配,現在我們學了數據庫,我們可以將這些用戶數據保存到數據庫中,然後通過數據庫裏面的數據來對客戶端進行用戶名和密碼的認證。

    自行創建一個用戶信息表userinfo,裏面包含兩個字段,username和password,然後裏面寫兩條記錄

    技術分享圖片

    

技術分享圖片
#我們來使用數據來進行一下用戶名和密碼的認證操作
import pymysql conn = pymysql.connect( host=‘127.0.0.1‘, port=3306, user=‘root‘, password=‘666‘, database=‘crm‘, charset=‘utf8‘ ) cursor = conn.cursor(pymysql.cursors.DictCursor) uname = input(‘請輸入用戶名:‘) pword = input(‘請輸入密碼:‘) sql = "select * from userinfo where username=‘%s‘ and password=‘%s‘;"%(uname,pword) res = cursor.execute(sql) #res我們說是得到的行數,如果這個行數不為零,說明用戶輸入的用戶名和密碼存在,如果為0說名存在,你想想對不 print(res) #如果輸入的用戶名和密碼錯誤,這個結果為0,如果正確,這個結果為1 if res: print(‘登陸成功‘) else: print(‘用戶名和密碼錯誤!‘) #通過上面的驗證方式,比我們使用文件來保存用戶名和密碼信息的來進行驗證操作要方便很多。
技術分享圖片

    

    但是我們來看下面的操作,如果將在輸入用戶名的地方輸入一個 chao‘空格然後--空格然後加上任意的字符串,就能夠登陸成功,也就是只知道用戶名的情況下,他就能登陸成功的情況:

技術分享圖片
uname = input(‘請輸入用戶名:‘)
pword = input(‘請輸入密碼:‘)

sql = "select * from userinfo where username=‘%s‘ and password=‘%s‘;"%(uname,pword)
print(sql)
res = cursor.execute(sql) #res我們說是得到的行數,如果這個行數不為零,說明用戶輸入的用戶名和密碼存在,如果為0說名存在,你想想對不

print(res) #如果輸入的用戶名和密碼錯誤,這個結果為0,如果正確,這個結果為1
if res:
    print(‘登陸成功‘)
else:
    print(‘用戶名和密碼錯誤!‘)
#運行看結果:居然登陸成功
請輸入用戶名:chao‘ -- xxx
請輸入密碼:
select * from userinfo where username=‘chao‘ -- xxx‘ and password=‘‘;
1
登陸成功

我們來分析一下:
此時uname這個變量等於什麽,等於chao‘ -- xxx,然後我們來看我們的sql語句被這個字符串替換之後是個什麽樣子:
select * from userinfo where username=‘chao‘ -- xxx‘ and password=‘‘; 其中chao後面的這個‘,在進行字符串替換的時候,我們輸入的是chao‘,這個引號和前面的引號組成了一對,然後後面--在sql語句裏面是註釋的意思,也就是說--後面的sql語句被註釋掉了。也就是說,拿到的sql語句是select * from userinfo where username=‘chao‘;然後就去自己的數據庫裏面去執行了,發現能夠找到對應的記錄,因為有用戶名為chao的記錄,然後他就登陸成功了,但是其實他連密碼都不知道,只知道個用戶名。。。,他完美的跳過了你的認證環節。
技術分享圖片

    然後我們再來看一個例子,直接連用戶名和密碼都不知道,但是依然能夠登陸成功的情況:

技術分享圖片
請輸入用戶名:xxx‘ or 1=1 -- xxxxxx
請輸入密碼:
select * from userinfo where username=‘xxx‘ or 1=1 -- xxxxxx‘ and password=‘‘;
3
登陸成功

我們只輸入了一個xxx‘ 加or 加 1=1 加 -- 加任意字符串
看上面被執行的sql語句你就發現了,or 後面跟了一個永遠為真的條件,那麽即便是username對不上,但是or後面的條件是成立的,也能夠登陸成功。
技術分享圖片

    上面兩個例子就是兩個sql註入的問題,看完上面這兩個例子,有沒有感覺後背發涼啊同誌們,別急,我們來解決一下這個問題,怎麽解決呢?

      有些網站直接在你輸入內容的時候,是不是就給你限定了,你不能輸入一些特殊的符號,因為有些特殊符號可以改變sql的執行邏輯,其實不光是--,還有一些其他的符號也能改變sql語句的執行邏輯,這個方案我們是在客戶端給用戶輸入的地方進行限制,但是別人可不可以模擬你的客戶端來發送請求,是可以的,他模擬一個客戶端,不按照你的客戶端的要求來,就發一些特殊字符,你的客戶端是限制不了的。所以單純的在客戶端進行這個特殊字符的過濾是不能解決根本問題的,那怎麽辦?我們服務端也需要進行驗證,可以通過正則來將客戶端發送過來的內容進行特殊字符的匹配,如果有這些特殊字符,我們就讓它登陸失敗。

    在服務端來解決sql註入的問題:不要自己來進行sql字符串的拼接了,pymysql能幫我們拼接,他能夠防止sql註入,所以以後我們再寫sql語句的時候按下面的方式寫:

技術分享圖片
之前我們的sql語句是這樣寫的:
sql = "select * from userinfo where username=‘%s‘ and password=‘%s‘;"%(uname,pword)

以後再寫的時候,sql語句裏面的%s左右的引號去掉,並且語句後面的%(uname,pword)這些內容也不要自己寫了,按照下面的方式寫
sql = "select * from userinfo where username=%s and password=%s;"
難道我們不傳值了嗎,不是的,我們通過下面的形式,在excute裏面寫參數:
#cursor.execute(sql,[uname,pword]) ,其實它本質也是幫你進行了字符串的替換,只不過它會將uname和pword裏面的特殊字符給過濾掉。

看下面的例子:
uname = input(‘請輸入用戶名:‘) #輸入的內容是:chao‘ -- xxx或者xxx‘ or 1=1 -- xxxxx
pword = input(‘請輸入密碼:‘)

sql = "select * from userinfo where username=%s and password=%s;"
print(sql)
res = cursor.execute(sql,[uname,pword]) #res我們說是得到的行數,如果這個行數不為零,說明用戶輸入的用戶名和密碼存在,如果為0說名存在,你想想對不

print(res) #如果輸入的用戶名和密碼錯誤,這個結果為0,如果正確,這個結果為1
if res:
    print(‘登陸成功‘)
else:
    print(‘用戶名和密碼錯誤!‘)
#看結果:
請輸入用戶名:xxx‘ or 1=1 -- xxxxx
請輸入密碼:
select * from userinfo where username=%s and password=%s;
0
用戶名和密碼錯誤!
技術分享圖片

  通過pymysql提供的excute完美的解決了問題。

總結咱們剛才說的兩種sql註入的語句
#1、sql註入之:用戶存在,繞過密碼 chao‘ -- 任意字符 #2、sql註入之:用戶不存在,繞過用戶與密碼 xxx‘ or 1=1 -- 任意字符

    解決方法總結:

技術分享圖片 技術分享圖片
# 原來是我們對sql進行字符串拼接
# sql="select * from userinfo where name=‘%s‘ and password=‘%s‘" %(user,pwd)
# print(sql)
# res=cursor.execute(sql)

#改寫為(execute幫我們做字符串拼接,我們無需且一定不能再為%s加引號了)
sql="select * from userinfo where name=%s and password=%s" #!!!註意%s需要去掉引號,因為pymysql會自動為我們加上
res=cursor.execute(sql,[user,pwd]) #pymysql模塊自動幫我們解決sql註入的問題,只要我們按照pymysql的規矩來。
技術分享圖片 技術分享圖片

  三 增、刪、改:conn.commit()

    查操作在上面已經說完了,我們來看一下增刪改,也要註意,sql語句不要自己拼接,交給excute來拼接

技術分享圖片 技術分享圖片 技術分享圖片
import pymysql
#鏈接
conn=pymysql.connect(host=‘localhost‘,port=‘3306‘,user=‘root‘,password=‘123‘,database=‘crm‘,charset=‘utf8‘)
#遊標
cursor=conn.cursor()

#執行sql語句
#part1
# sql=‘insert into userinfo(name,password) values("root","123456");‘
# res=cursor.execute(sql) #執行sql語句,返回sql影響成功的行數
# print(res)
# print(cursor.lastrowid) #返回的是你插入的這條記錄是到了第幾條了 #part2 # sql=‘insert into userinfo(name,password) values(%s,%s);‘ # res=cursor.execute(sql,("root","123456")) #執行sql語句,返回sql影響成功的行數 # print(res) #還可以進行更改操作:
#res=cursor.excute("update userinfo set username=‘taibaisb‘ where id=2")
#print(res) #結果為1 #part3 sql=‘insert into userinfo(name,password) values(%s,%s);‘ res=cursor.executemany(sql,[("root","123456"),("lhf","12356"),("eee","156")]) #執行sql語句,返回sql影響成功的行數,一次插多條記錄 print(res) #上面的幾步,雖然都有返回結果,也就是那個受影響的函數res,但是你去數據庫裏面一看,並沒有保存到數據庫裏面, conn.commit() #必須執行conn.commit,註意是conn,不是cursor,執行這句提交後才發現表中插入記錄成功,沒有這句,上面的這幾步操作其實都沒有成功保存。 cursor.close() conn.close()
技術分享圖片 技術分享圖片

  四 查:fetchone,fetchmany,fetchall

    技術分享圖片

技術分享圖片 技術分享圖片 技術分享圖片
import pymysql
#鏈接
conn=pymysql.connect(host=‘localhost‘,user=‘root‘,password=‘123‘,database=‘egon‘)
#遊標
cursor=conn.cursor()

#執行sql語句
sql=‘select * from userinfo;‘
rows=cursor.execute(sql) #執行sql語句,返回sql影響成功的行數rows,將結果放入一個集合,等待被查詢

# cursor.scroll(3,mode=‘absolute‘) # 相對絕對位置移動
# cursor.scroll(3,mode=‘relative‘) # 相對當前位置移動
res1=cursor.fetchone()
res2=cursor.fetchone()
res3=cursor.fetchone()
res4=cursor.fetchmany(2)
res5=cursor.fetchall()
print(res1)
print(res2)
print(res3)
print(res4)
print(res5)
print(‘%s rows in set (0.00 sec)‘ %rows)



conn.commit() #提交後才發現表中插入記錄成功
cursor.close()
conn.close()

‘‘‘
(1, ‘root‘, ‘123456‘)
(2, ‘root‘, ‘123456‘)
(3, ‘root‘, ‘123456‘)
((4, ‘root‘, ‘123456‘), (5, ‘root‘, ‘123456‘))
((6, ‘root‘, ‘123456‘), (7, ‘lhf‘, ‘12356‘), (8, ‘eee‘, ‘156‘))
rows in set (0.00 sec)
‘‘‘
技術分享圖片 技術分享圖片

  五 獲取插入的最後一條數據的自增ID

技術分享圖片 技術分享圖片 技術分享圖片
import pymysql
conn=pymysql.connect(host=‘localhost‘,user=‘root‘,password=‘123‘,database=‘egon‘)
cursor=conn.cursor()

sql=‘insert into userinfo(name,password) values("xxx","123");‘
rows=cursor.execute(sql)
print(cursor.lastrowid) #在插入語句後查看

conn.commit()

cursor.close()
conn.close()
技術分享圖片 技術分享圖片

Navicat工具、pymysql模塊