Navicat工具、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()
復制代碼

 

回到頂部


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM