Python 數據庫的Connection、Cursor兩大對象

Python 數據庫的Connection、Cursor兩大對象

pymysql是Python中操做MySQL的模塊,其使用方法和py2的MySQLdb幾乎相同。html

Python 數據庫圖解流程python

   Connection、Cursor比喻mysql

 

 

 

Connection()的參數列表web

host,鏈接的數據庫服務器主機名,默認爲本地主機(localhost)。
user,鏈接數據庫的用戶名,默認爲當前用戶。
passwd,鏈接密碼,沒有默認值。
db,鏈接的數據庫名,沒有默認值。
conv,將文字映射到Python類型的字典。
MySQLdb.converters.conversions
cursorclass,cursor()使用的種類,默認值爲MySQLdb.cursors.Cursor。
compress,啓用協議壓縮功能。
named_pipe,在windows中,與一個命名管道相鏈接。
init_command,一旦鏈接創建,就爲數據庫服務器指定一條語句來運行。
read_default_file,使用指定的MySQL配置文件。
read_default_group,讀取的默認組。
unix_socket,在unix中,鏈接使用的套接字,默認使用TCP。
port,指定數據庫服務器的鏈接端口,默認是3306。sql

 

 

 

鏈接對象的db.close()方法可關閉數據庫鏈接,並釋放相關資源。數據庫

鏈接對象的db.cursor([cursorClass])方法返回一個指針對象,用於訪問和操做數據庫中的數據。
鏈接對象的db.begin()方法用於開始一個事務,若是數據庫的AUTOCOMMIT已經開啓就關閉它,直到事務調用commit()和rollback()結束。
鏈接對象的db.commit()和db.rollback()方法分別表示事務提交和回退。
指針對象的cursor.close()方法關閉指針並釋放相關資源。
指針對象的cursor.execute(query[,parameters])方法執行數據庫查詢。
指針對象的cursor.fetchall()可取出指針結果集中的全部行,返回的結果集一個元組(tuples)。
指針對象的cursor.fetchmany([size=cursor.arraysize])從查詢結果集中取出多行,咱們可利用可選的參數指定取出的行數。
指針對象的cursor.fetchone()從查詢結果集中返回下一行。
指針對象的cursor.arraysize屬性指定由cursor.fetchmany()方法返回行的數目,影響fetchall()的性能,默認值爲1。
指針對象的cursor.rowcount屬性指出上次查詢或更新所發生行數。-1表示還沒開始查詢或沒有查詢到數據。segmentfault

 

 

 

Cursorwindows

經常使用方法:安全

close():關閉此遊標對象
fetchone():獲得結果集的下一行
fetchmany([size = cursor.arraysize]):獲得結果集的下幾行
fetchall():獲得結果集中剩下的全部行
excute(sql[, args]):執行一個數據庫查詢或命令
excutemany(sql, args):執行多個數據庫查詢或命令ruby

 

 

 

 

 

 

 

 

 經常使用屬性:

connection:建立此遊標對象的數據庫鏈接
arraysize:使用fetchmany()方法一次取出多少條記錄,默認爲1

事務

事務命令

事務指邏輯上的一組操做,組成這組操做的各個單元,要不所有成功,要不所有不成功。

數據庫開啓事務命令 

start transaction 開啓事務
Rollback 回滾事務,即撤銷指定的sql語句(只能回退insert delete update語句),回滾到上一次commit的位置
Commit 提交事務,提交未存儲的事務
savepoint 保留點 ,事務處理中設置的臨時佔位符 你能夠對它發佈回退(與整個事務回退不一樣)   

 轉帳實例:

UPDATE account set balance=balance-5000 WHERE name=」yuan」;
UPDATE account set balance=balance+5000 WHERE name=」xialv」;
 
-- 建立表
create table test2(id int PRIMARY KEY auto_increment,name VARCHAR(20)) engine=innodb;

-- 插入數據
INSERT INTO test2(name) VALUE ("alvin"),
                              ("yuan"),
                              ("xialv");



start transaction; -- 開啓事務
insert into test2 (name)values('silv');
select * from test2;
commit;   -- 提交事務


-- 保留點

start transaction;
insert into test2 (name)values('wu');
savepoint insert_wu; -- 給上面剛纔insert的命令起了個名字叫insert_wu,並設置一個保留點,對重要的sql,要緊挨着設置保留點
select * from test2;



delete from test2 where id=4;
savepoint delete1;
select * from test2;


delete from test2 where id=1;
savepoint delete2;
select * from test2;

rollback to delete1;  -- 回滾到某個設置的節點


select * from test2;

savepoint
 

事務特性

<1> 原子性(Atomicity):原子性是指事務是一個不可分割的工做單位,事務中的操做要麼都發生,要麼都不發生。

<2> 一致性(Consistency):事務先後數據的完整性必須保持一致。在事務執行以前數據庫是符合數據完整性約束的,不管事務是否執行成功,事務結束後的數據庫中的數據也應該是符合完整性約束的。在某一時間點,若是數據庫中的全部記錄都能保證知足當前數據庫中的全部約束,則能夠說當前的數據庫是符合數據完整性約束的。
好比刪部門表前應該刪掉關聯員工(已經創建外鍵),若是數據庫服務器發生錯誤,有一個員工沒刪掉,那麼此時員工的部門表已經刪除,那麼就不符合完整性約束了,因此這樣的數據庫也就性能太差啦!

<3>隔離性(Isolation):事務的隔離性是指多個用戶併發訪問數據庫時,一個用戶的事務不能被其它用戶的事務所幹擾,多個併發事務之間數據要相互隔離。

<4>持久性(Durability):持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即便數據庫發生故障也不該該對其有任何影響。

3、隔離性:
將數據庫設計爲串行化程的數據庫,讓一張表在同一時間內只能有一個線程來操做。若是將數據庫設計爲這樣,那數據庫的效率過低了。因此數據庫的設計這沒有直接將數據庫設計爲串行化,而是爲數據庫提供多個隔離級別選項,使數據庫的使用者能夠根據使用狀況本身定義到底須要什麼樣的隔離級別。

不考慮隔離性可能出現的問題:

髒讀

 
--一個事務讀取到了另外一個事務未提交的數據,這是特別危險的,要盡力防止。
        a 1000
        b 1000
        a:
            start transaction;
            update set money=money+100 where name=b;
        b:
            start transaction;
            select * from account where name=b;--1100
            commit;
        a:
            rollback;
        b:  start transaction;
            select * from account where name=b;--1000
 

不可重複讀

 
--在一個事務內讀取表中的某一行數據,屢次讀取結果不一樣。(一個事務讀取到了另外一個事務已經提交
-- 的數據--增長記錄、刪除記錄、修改記錄),在某寫狀況下並非問題,在另外一些狀況下就是問題。

a:
start transaction;
select 活期帳戶 from account where name=b;--1000    活期帳戶:1000
select 按期帳戶 from account where name=b;--1000   按期帳戶:1000
select 固定資產 from account where name=b;--1000   固定資產:1000
------------------------------
b:
start transaction;
update set money=0 where name=b;(把某一個帳戶的資金置爲0)
commit;
------------------------------
select 活期+按期+固定 from account where name=b; --2000 總資產: 2000
 

虛讀

 
是指在一個事務內讀取到了別的事務插入的數據,致使先後讀取不一致。
(一個事務讀取到了另外一個事務已經提交的數據---增長記錄、刪除記錄),在某寫狀況下並非問題,在另外一些狀況下就是問題。 b 1000 c 2000 d 3000 a: start transaction select sum(money) from account;---3000 3000(b+c) ------------------- d:start transaction; insert into account values(d,3000); commit; ------------------- select count(*)from account;---3 3(算上插入的d總共三我的) 3000/3 = 1000 1000 (可是總金額仍是按照b和c兩我的算的,因此平均金額不對)
 

四個隔離級別:
Serializable:可避免髒讀、不可重複讀、虛讀狀況的發生。(串行化)
Repeatable read:可避免髒讀、不可重複讀狀況的發生。(可重複讀)不能夠避免虛讀
Read committed:可避免髒讀狀況發生(讀已提交)
Read uncommitted:最低級別,以上狀況均沒法保證。(讀未提交)

安全性考慮:Serializable>Repeatable read>Read committed>Read uncommitted
數據庫效率:Read uncommitted>Read committed>Repeatable read>Serializable

通常狀況下,咱們會使用Repeatable read、Read committed mysql數據庫默認的數據庫隔離級別Repeatable read

mysql中設置數據庫的隔離級別語句:

set [global/session] transaction isolation level xxxx;

若是使用global則修改的是數據庫的默認隔離級別,全部新開的窗口的隔離級別繼承自這個默認隔離級別若是使用session修改,則修改的是當前客戶端的隔離級別,和數據庫默認隔離級別無關。當前的客戶端是什麼隔離級別,就能防止什麼隔離級別問題,和其餘客戶端是什麼隔離級別無關。
mysql中設置數據庫的隔離級別語句:

select @@tx_isolation;

事務

事務指邏輯上的一組操做,組成這組操做的各個單元,要不所有成功,要不所有不成功。

數據庫開啓事務命令     

-- start transaction 開啓事務
-- Rollback 回滾事務,即撤銷指定的sql語句(只能回退insert delete update語句),回滾到上一次commit的位置
-- Commit 提交事務,提交未存儲的事務
--
-- savepoint 保留點 ,事務處理中設置的臨時佔位符 你能夠對它發佈回退(與整個事務回退不一樣)
實例

--建立表
create table account(
id int primary key auto_increment,
name varchar (25),
balance double
);

insert into account values (1,'alex',8000),(2,'ego',8000);

-- +----+------+---------+
-- | id | name | balance |
-- +----+------+---------+
-- | 1 | alex | 8000 |
-- | 2 | ego | 8000 |
-- +----+------+---------+


start transaction ;--開始事務

update account set balance=balance-5000 where name='alex';
select * from account;
-- +----+------+---------+ --此時數據並無寫入數據庫,只是顯示命令的結果,除非在操做下面寫commit
-- | id | name | balance |
-- +----+------+---------+
-- | 1 | alex | 3000 |
-- | 2 | ego | 8000 |
-- +----+------+---------+

savepoint update1; --設置保留點

update account set balance=balance+5000 where name='ego';
select * from account;

-- +----+------+---------+ --同樣數據沒有寫入數據庫
-- | id | name | balance |
-- +----+------+---------+
-- | 1 | alex | 3000 |
-- | 2 | ego | 13000 |
-- +----+------+---------+

savepoint update2;

rollback to update1; --回滾至操做update1處,update1以上的操做任然存在,update1下的操做將全被取消
select * from account;

-- +----+------+---------+
-- | id | name | balance |
-- +----+------+---------+
-- | 1 | alex | 3000 |
-- | 2 | ego | 8000 |
-- +----+------+---------+

rollback ; --直接回滾,則會回滾自前面的commit處,若是沒有commit就一直回滾至開頭
-- +----+------+---------+
-- | id | name | balance |
-- +----+------+---------+
-- | 1 | alex | 8000 |
-- | 2 | ego | 8000 |
-- +----+------+---------+

commit ; --提交數據,此時數據才真正寫入數據庫
select * from account;

-- +----+------+---------+
-- | id | name | balance |
-- +----+------+---------+
-- | 1 | alex | 8000 |
-- | 2 | ego | 8000 |
-- +----+------+---------+

 

Python3 pymysql事務處理,執行多條sql語句後提交

# -*- coding: utf-8 -*-

import pymysql.cursors
# 鏈接數據庫
connect = pymysql.Connect(
    host='localhost',
    port=3310,
    user='user',
    passwd='123',
    db='test',
    charset='utf8'
)
# 事務處理
sql_1 = "UPDATE staff SET saving = saving + 1000 WHERE user_id = '1001' "
sql_2 = "UPDATE staff SET expend = expend + 1000 WHERE user_id = '1001' "
sql_3 = "UPDATE staff SET income = income + 2000 WHERE user_id = '1001' "

try:
    cursor.execute(sql_1)  # 儲蓄增長1000
    cursor.execute(sql_2)  # 支出增長1000
    cursor.execute(sql_3)  # 收入增長2000
except Exception as e:
    connect.rollback()  # 事務回滾
    print('事務處理失敗', e)
else:
    connect.commit()  # 事務提交
    print('事務處理成功', cursor.rowcount)

# 關閉鏈接
cursor.close()
connect.close()

 

python pymysql cursor的問題

使用python操做mysql的時候通常都會使用以下語句:

官方示例
import pymysql.cursors # 鏈接到數據庫後實際上TCP的鏈接狀態是ESTABLISHED connection = pymysql.connect(host='localhost', user='user', password='passwd', db='db', charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor) try: with connection.cursor() as cursor: sql = "INSERT INTO `users` (`email`, `password`) VALUES (%s, %s)" cursor.execute(sql, ('webmaster@python.org', 'very-secret')) #默認不自動提交事務,因此須要手動提交 connection.commit() with connection.cursor() as cursor: sql = "SELECT `id`, `password` FROM `users` WHERE `email`=%s" cursor.execute(sql, ('webmaster@python.org',)) result = cursor.fetchone() print(result) finally: connection.close() 

在這段代碼裏,有一個疑惑的點是,咱們如今建立了一個鏈接,可是實例化了多個cursor,咱們可不可使用同一個鏈接的同一個cursor來重複使用,代碼以下

with connect.cursor() as cursor: cursor.execute("select * from person limit 1") print(id(cursor)) data = cursor.fetchone() print(data) print("=============") cursor.execute("select * from person limit 1") print(id(cursor)) data = cursor.fetchone() print(data) 

上面的代碼,咱們執行完了以後發現查詢操做是能夠直接使用的,而且不會產生衝突,咱們經過打印cursor的地址發現是同一個cursor。

插入操做
with connect.cursor() as cursor: for id in range(1, 100, 2): cursor.execute("insert into test(id)values(%d)"%id) print(id) id += 1 cursor.execute("insert into test(id)values(%d)"%id) time.sleep(2) print(id) 

在單進程單線程環境下依然沒有問題

刪除
with connect.cursor() as cursor: for id in range(100): # cursor.execute("insert into test(id)values(%d)" % id) cursor.execute("delete from test where id=%s"%id) time.sleep(5) time.sleep(10) 

也沒有問題

可是有博客說多進程環境下會出現問題,我一直想重現,可是沒有成功,等之後重現了再來更新。

可是

  • 建立了一個 cursor 之後,建議完成一個事務就 commit 一下,不要一直用它,這樣一直使用,並不會和數據庫完成數據同步,若是操做太多,提交的時候會超時,形成部分數據更新,部分數據丟失,數據不一致且效率低。
    而且握着 cursor 期間,數據庫端發生改變,也無法和客戶端同步。

參考連接:
Python 數據庫的Connection、Cursor兩大對象
PyMySQL 0.9.2
python - 在 python MySQLdb模塊中,是否應該重用遊標

你看一下MySQLdb下面的cursors模塊,DictCursor的這個功能是繼承於CursorDictRowsMixIn,這個MixIn提供了3個額外的方法: fetchoneDict、fetchmanyDict、fetchallDict。

>>> import MySQLdb >>> c = MySQLdb.connect('127.0.0.1', 'root', 'password', 'test') >>> x = c.cursor(MySQLdb.cursors.DictCursor) >>> x.execute('select * from user') 2L >>> x.fetchoneDict() {'age': 26L, 'id': 1L, 'name': 'test'}


2、execute()之sql注入

這裏只截圖演示三種SQL注入示例截圖

1

2

3

 

 

解決方法: 

# 原來是咱們對sql進行字符串拼接 # sql="select * from userinfo where name='%s' and password='%s'" %(username,pwd) # print(sql) # result=cursor.execute(sql) #改寫爲(execute幫咱們作字符串拼接,咱們無需且必定不能再爲%s加引號了) sql="select * from userinfo where name=%s and password=%s" #!!!注意%s須要去掉引號,由於pymysql會自動爲咱們加上 result=cursor.execute(sql,[user,pwd]) #pymysql模塊自動幫咱們解決sql注入的問題,只要咱們按照pymysql的規矩來。
 

pymysql .cursor屬性方法(tcy)

cursor.excutemany(query, args)#執行多個數據庫查詢或命令參數:query - 要在服務器上執行的查詢args - 序列或映射的序列。它用做參數。返回:受影響的行數(若是有)說明:提升多行INSERT和REPLACE的性能。不然它等同於使用execute()循環遍歷argsexecutemany()生成的最大語句大小爲max_allowed_pa​​cket - packet_header_sizecursor.max_stmt_length #1024000con.max_allowed_packet#16777216實例:str_insert = "INSERT INTO Cu_table (id) VALUES (%s)"cursor.executemany(str_insert,['A','B','C','D']) #一次插入A B C D 四個值方法:調用函數cursor.callproc(procname, args=())  # 調用數據庫中的存儲過程參數:procname表示數據庫中存儲過程的名字,args表示爲存儲過程傳入的參數。返回:返回原始args調用的結果做爲輸入序列的修改副本返回。該過程還能夠提供結果集做爲輸出。而後必須經過標準.fetch * ()方法使其可用調用無參數存儲過程:cursor.callproc('p2')  # 等價cursor.execute("call p2()")調用有參數存儲過程:cursor.callproc('p1', args=(1, 22, 3, 4))class pymysql.cursors.Cursor(connection)  # 遊標結果做爲元祖的元祖返回說明:這是您用於與數據庫交互的對象。不要本身建立Cursor實例。調用connections.Connection.cursor()class pymysql.cursors.SSCursor(connection)  # 無緩衝遊標結果做爲元祖的元祖返回,用途:用於返回大量數據查詢,或慢速網絡鏈接到遠程服務器不將每行數據複製到緩衝區,根據須要獲取行。客戶端內存使用少在慢速網絡上或結果集很是大時行返回速度快限制:MySQL協議不支持返回總行數,判斷有多少行惟一方法是迭代返回的每一行。目前沒法向後滾動,由於只有當前行保存在內存中。class pymysql.cursors.DictCursor(connection)  # 將結果做爲字典返回遊標class pymysql.cursors.SSDictCursor(connection)  # 無緩衝遊標結果做爲字典返回遊標屬性:cursor.max_stmt_length  # 1024000cursor.rownumber  # 5 #當前結果集中游標所在行的索引(起始行號爲 0)cursor.arraysize  # 1 #此讀/寫屬性指定用.fetchmany()一次獲取的行數。# 默認1表示一次獲取一行;也能夠用於執行.executemany()cursor.lastrowid  # None #只讀屬性提供上次修改行的rowid# DB僅在執行單個INSERT 操做時返回rowid 。# 如未設rowid或DB不支持rowid應將此屬性設置爲None# 如最後執行語句修改了多行,例如用INSERT和.executemany()時lastrowid語義是未定義cursor.rowcount  # 5 #最近一次 execute() 建立或影響的行數# 如無cursor.execute()或接口沒法肯定最後一個操做的rowcount則該屬性爲-1# 該行數屬性能夠在動態更新其值的方式來編碼。# 這對於僅在第一次調用.fetch()方法後返回可用rowcount值的 數據庫很是有用。commit()方法:在數據庫裏增,刪,改的時候。必需要進行提交,不然插入的時候數據不生效
相關文章
相關標籤/搜索