進擊のpython
數據庫——pymysql
數據庫就算是學習完畢了,但是我們學習數據庫的本質是什么?
是想讓數據庫像文件存儲一樣將信息存儲起來供我們調用
那回歸本行,我就應該是用python來處理數據庫的相關操作
所以從這節開始就開始python跟數據庫建立聯系了
pymysql是一個第三方庫,是用來使用Python語句來操作mysql的庫
本質上就是個套接字連接
因為是第三方庫,所以要安裝~
我們用一個實例來帶領你學習如何使用這個數據庫
驗證賬號密碼
驗證之前得有一個數據庫存放賬號密碼,所以先用上一節的可視化工具建立一個
創建完之后打開編譯工具,調用pymysql:
import pymysql
因為他也相當於是套接字連接,所以首先應該建立聯系,那都應該寫什么呢?
pymysql.connect(
host='localhost', # ip
port=3306, # 端口
user='root', # 用戶名
passwd='', # 密碼
db='db10', # 連接的數據庫
charset='utf8' # 編碼方式
)
然后我們就要拿到游標,游標是什么呢?你注意到每次輸入mysql語句的時候,都是 mysql>_
那這個_就是游標,我們輸入SQL語句的手也是在這上面輸入的,所以要先拿到游標:
cursor = conn.cursor()
我們是要驗證賬號密碼,所以應該先輸入再對比:
user = input('請輸入用戶名:').strip()
pwd = input('請輸入密碼:').strip()
sql='select * from user_info where name="%s" and pwd="%s"' %(user,pwd)
那執行給誰執行?游標!
rows = cursor.execute(sql)
這個拿到的結果是受影響的行數~也就是前幾節命令執行完的最后一句話:3 rows in set (0.01 sec)
其實你想想,如果有行數改變,是不是就說明查找到了呢!
那執行完之后要把數據庫關掉
cursor.close()
conn.close()
接下來就開始判斷了:
if rows:
print('登陸成功!')
else:
print('登陸失敗!')
完整代碼:
import pymysql
user = input('請輸入用戶名:').strip()
pwd = input('請輸入密碼:').strip()
conn = pymysql.connect(
host='localhost', # ip
port=3306, # 端口
user='root', # 用戶名
password='', # 密碼
db='db10', # 連接的數據庫
charset='utf8' # 編碼方式
)
cursor = conn.cursor()
sql = 'select * from user_info where name="%s" and pwd="%s"' % (user, pwd)
rows = cursor.execute(sql)
cursor.close()
conn.close()
if rows:
print('登陸成功!')
else:
print('登陸失敗!')
SQL注入
來,先不用管這個SQL注入是什么,我來讓你看一個現象
其實剛才咱們的代碼有致命的漏洞,不信你看
很明顯,這也登陸成功了!為什么呢???
那我是不是把賬號密碼都輸入到sql里面了,我現在打印一下,看看是什么:
select * from user_info where name="apple" -- dawdwa" and pwd=""
注意!!!在sql語句中,杠杠空格后面的語句就是注釋掉了!
所以實際上你只執行到了這句話
select * from user_info where name="apple"
當然就成功登錄了!
好!那又有疑問了!那我這么寫的前提是我得知道用戶名,不知道也是登不上去的啊,所以不算致命漏洞
那你看這個!
卧槽!也成功了!這是不是就瞬間慌了!
是不是實際上執行的是
select * from user_info where name="xxx " or 1=1
問題是不是就嚴重起來了????其實這種情況就是sql注入!!!!
如何解決呢??其實很好解決,只要不讓它輸入這種非法字符就行了!
其實你也就知道了為什么有的網站在創建用戶名的時候不讓用特殊符號了
那如何才能檢測用戶輸入的特殊字符呢??
pymysql的模塊作者想到了這一點,然后就給你提供了execute來過濾掉這些非法字符
所以部分代碼應該這樣修改:
sql = 'select * from user_info where name=%s and pwd=%s'
rows = cursor.execute(sql, (user, pwd))
pymysql的增刪改查
增 刪 改
之所以把這三個放在一起,本質上都是對庫進行了修改,所以放在一起,講一個就能舉一反三
sql = 'insert into user_info(name,pwd) values (%s,%s)'
rows = cursor.execute(sql, ("orange", "147258"))
到這就出現問題了,實際上,這么寫不會真的修改數據庫,如果你真的想改,就要在
conn.close()前面加上conn.commit(),加個提交才可以!
執行完之后用可視化工具看一眼吧~
但是我這樣只能添加一個,我想一次添加多個怎么辦呢??
那就要用到executemany方法了,列表里包裹的一個元祖就是一組數據
rows = cursor.executemany(sql, [("pear", "147258"), ('peach', '789456')])
最后再用可視化工具看一下,看看添沒添加成功
查
這兩面來回很麻煩,有沒有能讓結果在編譯器里打印的呢?
有!一共有三個方法:
cursor.fetchall() # 拿出所有
cursor.fetchone() # 拿到一條數據,相當於把結果放進管道一個一個拿出來
cursor.fetchmany() # 指定取多少條
但是我拿到的只有數據,要是能加上字段就好了~
所以!字典就變成首選,那如何能讓返回的數據變成字典呢?
我們可以在設置游標的時候設置:
cursor = conn.cursor(pymysql.cursors.DictCursor)
這是啥意思啊,是不是基於字典的游標啊,這回你再查:
print(cursor.fetchone())
print(cursor.fetchone())
print(cursor.fetchone())
{'id': 1, 'name': 'apple', 'pwd': '123456'}
{'id': 2, 'name': 'banana', 'pwd': '654321'}
{'id': 3, 'name': 'orange', 'pwd': '147258'}
是不是就是帶有字段的了~
print(cursor.fetchmany(3))
[{'id': 1, 'name': 'apple', 'pwd': '123456'}, {'id': 2, 'name': 'banana', 'pwd': '654321'}, {'id': 3, 'name': 'orange', 'pwd': '147258'}]
print(cursor.fetchall())
[{'id': 1, 'name': 'apple', 'pwd': '123456'}, {'id': 2, 'name': 'banana', 'pwd': '654321'}, {'id': 3, 'name': 'orange', 'pwd': '147258'}, {'id': 4, 'name': 'pear', 'pwd': '147258'}, {'id': 5, 'name': 'peach', 'pwd': '789456'}]
那有的同學發現我featchall()了之后,再featchall()就會返回一個空列表
那我不想這樣,我就想每一次featchall,都是完整打印,怎么辦呢?
其實這就有點像文件操作的時候通過光標的移動來決定打印內容
在數據庫這里就是通過游標位置來決定打印內容,對於游標的移動有兩種方式
絕對移動:cursor.scroll(3,mode='absolute')
相對移動:cursor.scroll(3,mode='relative')
絕對移動就是從頭開始移動幾個:
cursor.scroll(3,mode='absolute')
print(cursor.fetchone())
{'id': 4, 'name': 'pear', 'pwd': '147258'}
相對移動就是根據當前的游標位置進行移動
print(cursor.fetchone())
cursor.scroll(2, mode='relative')
print(cursor.fetchone())
{'id': 1, 'name': 'apple', 'pwd': '123456'}
{'id': 4, 'name': 'pear', 'pwd': '147258'}
最后說一點,pymysql提供了一種方法,能夠讓你知道現在id走到哪了,在插入數據的時候可以使用
sql = 'insert into user_info(name,pwd) values (%s,%s)'
rows = cursor.execute(sql,('plum',888888))
print(cursor.lastrowid)
代表着id要從6開始,也代表着,plum這個數據的id是6!