Navicat工具、pymysql模块
Navicat工具、pymysql模塊
閱讀目錄
- 一 IDE工具介紹
- 二 pymysql模塊
一 IDE工具介紹(Navicat)
生產(chǎn)環(huán)境還是推薦使用mysql命令行,但為了方便我們測(cè)試,可以使用IDE工具,我們使用Navicat工具,這個(gè)工具本質(zhì)上就是一個(gè)socket客戶端,可視化的連接mysql服務(wù)端的一個(gè)工具,并且他是圖形界面版的。我們使用它和直接使用命令行的區(qū)別就類似linux和windows系統(tǒng)操作起來(lái)的一個(gè)區(qū)別。
? ? ? ?下載鏈接:https://pan.baidu.com/s/1bpo5mqj
Navicat的安裝教程看這篇博客:https://www.cnblogs.com/clschao/articles/10022040.html
掌握: #1. 測(cè)試+鏈接數(shù)據(jù)庫(kù) #2. 新建庫(kù) #3. 新建表,新增字段+類型+約束 #4. 設(shè)計(jì)表:外鍵 #5. 新建查詢 #6. 備份庫(kù)/表#注意: 批量加注釋:ctrl+?鍵 批量去注釋:ctrl+shift+?鍵
?
二 pymysql模塊
我們要學(xué)的pymysql就是用來(lái)在python程序中如何操作mysql,它和mysql自帶的那個(gè)客戶端還有navicat是一樣的,本質(zhì)上就是一個(gè)套接字客戶端,只不過這個(gè)套接字客戶端是在python程序中用的,既然是客戶端套接字,應(yīng)該怎么用,是不是要連接服務(wù)端,并且和服務(wù)端進(jìn)行通信啊,讓我們來(lái)學(xué)習(xí)一下pymysql這個(gè)模塊
?
#安裝 pip3 install pymysql?
一 鏈接、執(zhí)行sql、關(guān)閉(游標(biāo))
import pymysql user=input('用戶名: ').strip() pwd=input('密碼: ').strip()#鏈接,指定ip地址和端口,本機(jī)上測(cè)試時(shí)ip地址可以寫localhost或者自己的ip地址或者127.0.0.1,然后你操作數(shù)據(jù)庫(kù)的時(shí)候的用戶名,密碼,要指定你操作的是哪個(gè)數(shù)據(jù)庫(kù),指定庫(kù)名,還要指定字符集。不然會(huì)出現(xiàn)亂碼 conn=pymysql.connect(host='localhost',port=3306,user='root',password='123',database='student',charset='utf8') #指定編碼為utf8的時(shí)候,注意沒有-,別寫utf-8,數(shù)據(jù)庫(kù)為
#得到conn這個(gè)連接對(duì)象 #游標(biāo) cursor=conn.cursor() #這就想到于mysql自帶的那個(gè)客戶端的游標(biāo)mysql> 在這后面輸入指令,回車執(zhí)行 #cursor=conn.cursor(cursor=pymysql.cursors.DictCursor) #獲取字典數(shù)據(jù)類型表示的結(jié)果:{'sid': 1, 'gender': '男', 'class_id': 1, 'sname': '理解'} {'字段名':值}#然后給游標(biāo)輸入sql語(yǔ)句并執(zhí)行sql語(yǔ)句execute sql='select * from userinfo where name="%s" and password="%s"' %(user,pwd) #注意%s需要加引號(hào),執(zhí)行這句sql的前提是醫(yī)藥有個(gè)userinfo表,里面有name和password兩個(gè)字段,還有一些數(shù)據(jù),自己添加數(shù)據(jù)昂 print(sql) res=cursor.execute(sql) #執(zhí)行sql語(yǔ)句,返回sql查詢成功的記錄數(shù)目,是個(gè)數(shù)字,是受sql語(yǔ)句影響到的記錄行數(shù),其實(shí)除了受影響的記錄的條數(shù)之外,這些記錄的數(shù)據(jù)也都返回了給游標(biāo),這個(gè)就相當(dāng)于我們subprocess模塊里面的管道PIPE,乘放著返回的數(shù)據(jù)
#all_data=cursor.fetchall() #獲取返回的所有數(shù)據(jù),注意凡是取數(shù)據(jù),取過的數(shù)據(jù)就沒有了,結(jié)果都是元祖格式的
#many_data=cursor.fetchmany(3) #一下取出3條數(shù)據(jù),
#one_data=cursor.fetchone() #按照數(shù)據(jù)的順序,一次只拿一個(gè)數(shù)據(jù),下次再去就從第二個(gè)取了,因?yàn)榈谝粋€(gè)被取出去了,取一次就沒有了,結(jié)果也都是元祖格式的
? fetchone:(1, '男', 1, '理解')
? fetchone:(2, '女', 1, '鋼蛋')
? fetchall:((3, '男', 1, '張三'), (4, '男', 1, '張一'))
上面我們說(shuō),我們的數(shù)據(jù)取一次是不是就沒有了啊,實(shí)際上不是的,這個(gè)取數(shù)據(jù)的操作就像讀取文件內(nèi)容一樣,每次read之后,光標(biāo)就移動(dòng)到了對(duì)應(yīng)的位置,我們可以通過seek來(lái)移動(dòng)光標(biāo)
同樣,我們可以移動(dòng)游標(biāo)的位置,繼續(xù)取我們前面的數(shù)據(jù),通過cursor.scroll(數(shù)字,模式),第一個(gè)參數(shù)就是一個(gè)int類型的數(shù)字,表示往后移動(dòng)的記錄條數(shù),第二個(gè)參數(shù)為移動(dòng)的模式,有兩個(gè)值:absolute:絕對(duì)移動(dòng),relative:相對(duì)移動(dòng)
#絕對(duì)移動(dòng):它是相對(duì)于所有數(shù)據(jù)的起始位置開始往后面移動(dòng)的
#相對(duì)移動(dòng):他是相對(duì)于游標(biāo)的當(dāng)前位置開始往后移動(dòng)的
#絕對(duì)移動(dòng)的演示
#print(cursor.fetchall())
#cursor.scroll(3,'absolute') #從初始位置往后移動(dòng)三條,那么下次取出的數(shù)據(jù)為第四條數(shù)據(jù)
#print(cursor.fetchone())
#相對(duì)移動(dòng)的演示
#print(cursor.fetchone())
#cursor.scroll(1,'relative') #通過上面取了一次數(shù)據(jù),游標(biāo)的位置在第二條的開頭,我現(xiàn)在相對(duì)移動(dòng)了1個(gè)記錄,那么下次再取,取出的是第三條,我相對(duì)于上一條,往下移動(dòng)了一條
#print(cursor.fetchone())
print(res) #一個(gè)數(shù)字cursor.close() #關(guān)閉游標(biāo) conn.close() #關(guān)閉連接if res:print('登錄成功') else:print('登錄失敗')
?
?
?
二 execute()之sql注入
之前我們進(jìn)行用戶名密碼認(rèn)證是先將用戶名和密碼保存到一個(gè)文件中,然后通過讀文件里面的內(nèi)容,來(lái)和客戶端發(fā)送過來(lái)的用戶名密碼進(jìn)行匹配,現(xiàn)在我們學(xué)了數(shù)據(jù)庫(kù),我們可以將這些用戶數(shù)據(jù)保存到數(shù)據(jù)庫(kù)中,然后通過數(shù)據(jù)庫(kù)里面的數(shù)據(jù)來(lái)對(duì)客戶端進(jìn)行用戶名和密碼的認(rèn)證。
自行創(chuàng)建一個(gè)用戶信息表userinfo,里面包含兩個(gè)字段,username和password,然后里面寫兩條記錄
#我們來(lái)使用數(shù)據(jù)來(lái)進(jìn)行一下用戶名和密碼的認(rèn)證操作
import pymysqlconn = 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('請(qǐng)輸入用戶名:') pword = input('請(qǐng)輸入密碼:')sql = "select * from userinfo where username='%s' and password='%s';"%(uname,pword)res = cursor.execute(sql) #res我們說(shuō)是得到的行數(shù),如果這個(gè)行數(shù)不為零,說(shuō)明用戶輸入的用戶名和密碼存在,如果為0說(shuō)名存在,你想想對(duì)不print(res) #如果輸入的用戶名和密碼錯(cuò)誤,這個(gè)結(jié)果為0,如果正確,這個(gè)結(jié)果為1 if res:print('登陸成功') else:print('用戶名和密碼錯(cuò)誤!')#通過上面的驗(yàn)證方式,比我們使用文件來(lái)保存用戶名和密碼信息的來(lái)進(jìn)行驗(yàn)證操作要方便很多。
?
但是我們來(lái)看下面的操作,如果將在輸入用戶名的地方輸入一個(gè) chao'空格然后--空格然后加上任意的字符串,就能夠登陸成功,也就是只知道用戶名的情況下,他就能登陸成功的情況:
uname = input('請(qǐng)輸入用戶名:') pword = input('請(qǐng)輸入密碼:')sql = "select * from userinfo where username='%s' and password='%s';"%(uname,pword) print(sql) res = cursor.execute(sql) #res我們說(shuō)是得到的行數(shù),如果這個(gè)行數(shù)不為零,說(shuō)明用戶輸入的用戶名和密碼存在,如果為0說(shuō)名存在,你想想對(duì)不print(res) #如果輸入的用戶名和密碼錯(cuò)誤,這個(gè)結(jié)果為0,如果正確,這個(gè)結(jié)果為1 if res:print('登陸成功') else:print('用戶名和密碼錯(cuò)誤!') #運(yùn)行看結(jié)果:居然登陸成功 請(qǐng)輸入用戶名:chao' -- xxx 請(qǐng)輸入密碼: select * from userinfo where username='chao' -- xxx' and password=''; 1 登陸成功我們來(lái)分析一下: 此時(shí)uname這個(gè)變量等于什么,等于chao' -- xxx,然后我們來(lái)看我們的sql語(yǔ)句被這個(gè)字符串替換之后是個(gè)什么樣子: select * from userinfo where username='chao' -- xxx' and password=''; 其中chao后面的這個(gè)',在進(jìn)行字符串替換的時(shí)候,我們輸入的是chao',這個(gè)引號(hào)和前面的引號(hào)組成了一對(duì),然后后面--在sql語(yǔ)句里面是注釋的意思,也就是說(shuō)--后面的sql語(yǔ)句被注釋掉了。也就是說(shuō),拿到的sql語(yǔ)句是select * from userinfo where username='chao';然后就去自己的數(shù)據(jù)庫(kù)里面去執(zhí)行了,發(fā)現(xiàn)能夠找到對(duì)應(yīng)的記錄,因?yàn)橛杏脩裘麨閏hao的記錄,然后他就登陸成功了,但是其實(shí)他連密碼都不知道,只知道個(gè)用戶名。。。,他完美的跳過了你的認(rèn)證環(huán)節(jié)。?
然后我們?cè)賮?lái)看一個(gè)例子,直接連用戶名和密碼都不知道,但是依然能夠登陸成功的情況:
請(qǐng)輸入用戶名:xxx' or 1=1 -- xxxxxx 請(qǐng)輸入密碼: select * from userinfo where username='xxx' or 1=1 -- xxxxxx' and password=''; 3 登陸成功我們只輸入了一個(gè)xxx' 加or 加 1=1 加 -- 加任意字符串 看上面被執(zhí)行的sql語(yǔ)句你就發(fā)現(xiàn)了,or 后面跟了一個(gè)永遠(yuǎn)為真的條件,那么即便是username對(duì)不上,但是or后面的條件是成立的,也能夠登陸成功。上面兩個(gè)例子就是兩個(gè)sql注入的問題,看完上面這兩個(gè)例子,有沒有感覺后背發(fā)涼啊同志們,別急,我們來(lái)解決一下這個(gè)問題,怎么解決呢?
有些網(wǎng)站直接在你輸入內(nèi)容的時(shí)候,是不是就給你限定了,你不能輸入一些特殊的符號(hào),因?yàn)橛行┨厥夥?hào)可以改變sql的執(zhí)行邏輯,其實(shí)不光是--,還有一些其他的符號(hào)也能改變sql語(yǔ)句的執(zhí)行邏輯,這個(gè)方案我們是在客戶端給用戶輸入的地方進(jìn)行限制,但是別人可不可以模擬你的客戶端來(lái)發(fā)送請(qǐng)求,是可以的,他模擬一個(gè)客戶端,不按照你的客戶端的要求來(lái),就發(fā)一些特殊字符,你的客戶端是限制不了的。所以單純的在客戶端進(jìn)行這個(gè)特殊字符的過濾是不能解決根本問題的,那怎么辦?我們服務(wù)端也需要進(jìn)行驗(yàn)證,可以通過正則來(lái)將客戶端發(fā)送過來(lái)的內(nèi)容進(jìn)行特殊字符的匹配,如果有這些特殊字符,我們就讓它登陸失敗。
在服務(wù)端來(lái)解決sql注入的問題:不要自己來(lái)進(jìn)行sql字符串的拼接了,pymysql能幫我們拼接,他能夠防止sql注入,所以以后我們?cè)賹憇ql語(yǔ)句的時(shí)候按下面的方式寫:
之前我們的sql語(yǔ)句是這樣寫的: sql = "select * from userinfo where username='%s' and password='%s';"%(uname,pword)以后再寫的時(shí)候,sql語(yǔ)句里面的%s左右的引號(hào)去掉,并且語(yǔ)句后面的%(uname,pword)這些內(nèi)容也不要自己寫了,按照下面的方式寫 sql = "select * from userinfo where username=%s and password=%s;" 難道我們不傳值了嗎,不是的,我們通過下面的形式,在excute里面寫參數(shù): #cursor.execute(sql,[uname,pword]) ,其實(shí)它本質(zhì)也是幫你進(jìn)行了字符串的替換,只不過它會(huì)將uname和pword里面的特殊字符給過濾掉。看下面的例子: uname = input('請(qǐng)輸入用戶名:') #輸入的內(nèi)容是:chao' -- xxx或者xxx' or 1=1 -- xxxxx pword = input('請(qǐng)輸入密碼:')sql = "select * from userinfo where username=%s and password=%s;" print(sql) res = cursor.execute(sql,[uname,pword]) #res我們說(shuō)是得到的行數(shù),如果這個(gè)行數(shù)不為零,說(shuō)明用戶輸入的用戶名和密碼存在,如果為0說(shuō)名存在,你想想對(duì)不print(res) #如果輸入的用戶名和密碼錯(cuò)誤,這個(gè)結(jié)果為0,如果正確,這個(gè)結(jié)果為1 if res:print('登陸成功') else:print('用戶名和密碼錯(cuò)誤!') #看結(jié)果: 請(qǐng)輸入用戶名:xxx' or 1=1 -- xxxxx 請(qǐng)輸入密碼: select * from userinfo where username=%s and password=%s; 0 用戶名和密碼錯(cuò)誤!?
通過pymysql提供的excute完美的解決了問題。
總結(jié)咱們剛才說(shuō)的兩種sql注入的語(yǔ)句#1、sql注入之:用戶存在,繞過密碼 chao' -- 任意字符#2、sql注入之:用戶不存在,繞過用戶與密碼 xxx' or 1=1 -- 任意字符
解決方法總結(jié):
# 原來(lái)是我們對(duì)sql進(jìn)行字符串拼接 # sql="select * from userinfo where name='%s' and password='%s'" %(user,pwd) # print(sql) # res=cursor.execute(sql)#改寫為(execute幫我們做字符串拼接,我們無(wú)需且一定不能再為%s加引號(hào)了) sql="select * from userinfo where name=%s and password=%s" #!!!注意%s需要去掉引號(hào),因?yàn)閜ymysql會(huì)自動(dòng)為我們加上 res=cursor.execute(sql,[user,pwd]) #pymysql模塊自動(dòng)幫我們解決sql注入的問題,只要我們按照pymysql的規(guī)矩來(lái)。三 增、刪、改:conn.commit()
查操作在上面已經(jīng)說(shuō)完了,我們來(lái)看一下增刪改,也要注意,sql語(yǔ)句不要自己拼接,交給excute來(lái)拼接
import pymysql #鏈接 conn=pymysql.connect(host='localhost',port='3306',user='root',password='123',database='crm',charset='utf8') #游標(biāo) cursor=conn.cursor()#執(zhí)行sql語(yǔ)句 #part1 # sql='insert into userinfo(name,password) values("root","123456");' # res=cursor.execute(sql) #執(zhí)行sql語(yǔ)句,返回sql影響成功的行數(shù) # print(res)# print(cursor.lastrowid) #返回的是你插入的這條記錄是到了第幾條了#part2 # sql='insert into userinfo(name,password) values(%s,%s);' # res=cursor.execute(sql,("root","123456")) #執(zhí)行sql語(yǔ)句,返回sql影響成功的行數(shù) # print(res) #還可以進(jìn)行更改操作:
#res=cursor.excute("update userinfo set username='taibaisb' where id=2")
#print(res) #結(jié)果為1 #part3 sql='insert into userinfo(name,password) values(%s,%s);' res=cursor.executemany(sql,[("root","123456"),("lhf","12356"),("eee","156")]) #執(zhí)行sql語(yǔ)句,返回sql影響成功的行數(shù),一次插多條記錄 print(res) #上面的幾步,雖然都有返回結(jié)果,也就是那個(gè)受影響的函數(shù)res,但是你去數(shù)據(jù)庫(kù)里面一看,并沒有保存到數(shù)據(jù)庫(kù)里面, conn.commit() #必須執(zhí)行conn.commit,注意是conn,不是cursor,執(zhí)行這句提交后才發(fā)現(xiàn)表中插入記錄成功,沒有這句,上面的這幾步操作其實(shí)都沒有成功保存。 cursor.close() conn.close()
四 查:fetchone,fetchmany,fetchall
import pymysql #鏈接 conn=pymysql.connect(host='localhost',user='root',password='123',database='egon') #游標(biāo) cursor=conn.cursor()#執(zhí)行sql語(yǔ)句 sql='select * from userinfo;' rows=cursor.execute(sql) #執(zhí)行sql語(yǔ)句,返回sql影響成功的行數(shù)rows,將結(jié)果放入一個(gè)集合,等待被查詢# cursor.scroll(3,mode='absolute') # 相對(duì)絕對(duì)位置移動(dòng) # cursor.scroll(3,mode='relative') # 相對(duì)當(dāng)前位置移動(dòng) 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() #提交后才發(fā)現(xiàn)表中插入記錄成功 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) '''
五 獲取插入的最后一條數(shù)據(jù)的自增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) #在插入語(yǔ)句后查看conn.commit()cursor.close() conn.close()轉(zhuǎn)載于:https://www.cnblogs.com/bpbl/p/10296474.html
總結(jié)
以上是生活随笔為你收集整理的Navicat工具、pymysql模块的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: webpack.config.js===
- 下一篇: 全北现代宣布江苏苏宁中后卫洪正好租借延长