Python ORM框架SQLAlchemy學習筆記之數據添加和事務回滾介紹

PC教程網】關于Python ORM框架SQLAlchemy學習筆記之數據添加和事務回滾介紹介紹:1. 添加一個新對象 前面介紹了映射到實體表的映射類User,如果我們想將其持久化(Persist),那么就需要將這個由User類建立的對象實例添加到我們先前創建的Session會話實例中: 教程實例,下面小編為您針對Python ORM框架SQLAlchemy學習筆記之數據添加和事務回滾介紹進行分享:

1. 添加一個新對象

前面介紹了映射到實體表的映射類User,如果我們想將其持久化(Persist),那么就需要將這個由User類建立的對象實例添加到我們先前創建的Session會話實例中:

教程實例 代碼如下:

ed_user = User('ed', 'Ed Jones', 'edspassword')
session.add(ed_user)

上面兩段代碼執行完后對象持久化了么?你或許會興沖沖的跑去數據庫里查看,結果卻失望而歸——數據庫里什么都沒有。為什么呢?因為SQLAlchemy采取的是Lazyload策略,也就是說現在這個對象被標記為Pending準備狀態,但沒有執行任何可能導致數據庫變化的SQL語句。那么什么時候會執行SQL語句并真正持久化呢?這個要等SQLAlchemy覺得需要的時候,比如我們現在查詢這個對象、對象的一個屬性或者顯式的調用flush方法,這時候SQLAlchemy覺得它“是時候”或者“不得不”執行SQL數據庫查詢以便于把標記為Pending的數據寫入數據庫表中了。假如這時候你執行的獲取對象、對象屬性或者類似的操作,SQLAlchemy在執行完SQL語句后會將你所要查詢的數據反饋給你。


為了更好的說明這一點,這里舉一個例子,這里涉及到我們第一個查詢示例,我們調用了Query對象來幫助我們完成這些,比如這里我們獲取剛剛持久化的用戶ed,我們通過“過濾(filter by)”的方式來查詢用戶名為ed的用戶,當然我們只需要一個ed,假如有多個重名的ed的話,查詢將會返回所有叫ed的記錄集列表,我們就選擇第一個ed吧(first)。

教程實例 代碼如下:

>>> our_user = session.query(User).filter_by(name='ed').first()
BEGIN (implicit)
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('ed', 'Ed Jones', 'edspassword')
SELECT users.id AS users_id,
        users.name AS users_name,
        users.fullname AS users_fullname,
        users.password AS users_password
FROM users
WHERE users.name = ?
 LIMIT ? OFFSET ?
('ed', 1, 0)
>>> our_user
<User('ed','Ed Jones', 'edspassword')>

可以看到上面的查詢語句返回了一個User的實例,而這個實例恰恰是我們先前持久化的。同時由于我們指定了引擎的echo=True,所以再執行查詢時輸出了SQL語句,我們注意到除了普通的SELECT外,還有額外的INSERT語句,而INSERT處理的就是我們剛剛通過session.add()持久化標記為Pending的對象,也就是說你在實際操作持久化數據時才會由延遲加載(lazyload)真正觸發數據庫操作。

實際上Session查詢反饋給我們的User對象和我們剛剛持久化的對象是同一個對象,通過下面的代碼可以檢驗:

教程實例 代碼如下:

>>> ed_user is our_user
True

實際上這里ORM的操作概念有點類似于標識映射(identity map),也就是說在實體數據庫之前架設一張標識映射表,可以看作緩存表的一種,任何存儲數據庫的對象會事先停留在這張表上,如果我們要查詢一個對象,將事先查詢這張標識映射表,如果這個對象存在則直接取出,否則就會查詢實體數據庫,我覺得這個有點像緩存的作用,可以這么理解吧。


一旦一個帶有獨一無二的主鍵的對象被Session持久化了,所有使用該主鍵在同一Session上查詢的對象將是同一個Python對象。當然對于在這個會話中持久化另外一個具有相同主鍵的對象將會拋出異常錯誤(主鍵不能重復)。

如果我們想一次性添加多個對象到Session中可以調用add_all():

教程實例 代碼如下:

>>> session.add_all([
...     User('wendy', 'Wendy Williams', 'foobar'),
...     User('mary', 'Mary Contrary', 'xxg527'),
...     User('fred', 'Fred Flinstone', 'blah')])

下面再談談修改,假如Ed覺得他的密碼不太安全,決定修改,可以直接這么做:
教程實例 代碼如下:

>>> ed_user.password = 'f8s7ccs'

同樣的道理,這個改動不會立即反映到數據庫里,當然Session意識到你要修改Ed的密碼,它會暫時緩沖這個改動,我們可以通過dirty方法了解到我們的改動:
教程實例 代碼如下:

>>> session.dirty
IdentitySet([<User('ed','Ed Jones', 'f8s7ccs')>])

同樣的我們可以通過new方法“窺看”到先前用add_all()持久化的對象列表:
教程實例 代碼如下:

>>> session.new 
IdentitySet([<User('wendy','Wendy Williams', 'foobar')>,
<User('mary','Mary Contrary', 'xxg527')>,
<User('fred','Fred Flinstone', 'blah')>])

當然這些改動都沒有真正反饋到數據庫里,相當于都被ORM緩沖了。接下來我們可以顯式的調用commit()來告訴Session:“我們目前就添加或者改動這么多可以提交數據庫了”:
教程實例 代碼如下:

>>> session.commit()
UPDATE users SET password=? WHERE users.id = ?
('f8s7ccs', 1)
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('wendy', 'Wendy Williams', 'foobar')
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('mary', 'Mary Contrary', 'xxg527')
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('fred', 'Fred Flinstone', 'blah')
COMMIT

于是剛才緩沖的數據或者變更全部被作為事務一次性flush到數據庫了,通過輸出的SQL語句我們也可以看出來。

這個操作完成后被會話(Session)引用的數據庫連接資源將被回收到連接池中,接下來的對于這個Session的任何操作將會觸發一個新的事務(Transaction),當然會再次和連接池申請獲得數據庫連接資源。

之前文章介紹到Ed的User對象的id為None,現在讓我們來看看吧:

教程實例 代碼如下:

>>> ed_user.id
BEGIN (implicit)
SELECT users.id AS users_id,
        users.name AS users_name,
        users.fullname AS users_fullname,
        users.password AS users_password
FROM users
WHERE users.id = ?
(1,)
1

除了由于echo=True導致輸出的SQL語句,看看是不是有了值,值為1。

無論是立即(commit、flush)或者通過“首次訪問加載(load-on-first-access)”,在Session在數據庫插入一條新記錄后,所有新生成的標識和數據庫生成的默認值對于實例來說才可以被訪問到。

當調用了commit()以后,SQLAlchemy將會刷新當前事務的所有數據到數據庫里。

2. 事務回滾

本文以及同系列的文章是以自己的想法翻譯的,不當之處還請指正,不做權威依據。好了,下面我還是簡單介紹一下事務回滾吧,其實這個和數據庫的事務回滾一個意思,就是我們做錯事后要撤消之前的變更。

因為Session是作為事務(transaction)來工作的,所以我們可以回滾(roll back)先前所做的更改。接下來讓我們做兩個稍后會被撤銷(回滾)的更改,第一個是修改ed_user.name:

教程實例 代碼如下:

>>> ed_user.name = 'Edwardo'

第二個是增加一個“不期望”的用戶fake_user:
教程實例 代碼如下:

>>> fake_user = User('fakeuser', 'Invalid', '12345')
>>> session.add(fake_user)

查詢當前會話,我們可以看到這兩個變更已經被flush到當前事務里了:
教程實例 代碼如下:

>>> session.query(User).filter(User.name.in_(['Edwardo', 'fakeuser'])).all()
UPDATE users SET name=? WHERE users.id = ?
('Edwardo', 1)
INSERT INTO users (name, fullname, password) VALUES (?, ?, ?)
('fakeuser', 'Invalid', '12345')
SELECT users.id AS users_id,
        users.name AS users_name,
        users.fullname AS users_fullname,
        users.password AS users_password
FROM users
WHERE users.name IN (?, ?)
('Edwardo', 'fakeuser')
[<User('Edwardo','Ed Jones', 'f8s7ccs')>, <User('fakeuser','Invalid', '12345')>]

好吧,接下來是見證奇跡的時刻,我們回滾(rolling back)事務:
教程實例 代碼如下:

>>> session.rollback()
ROLLBACK
>>> ed_user.name
BEGIN (implicit)
SELECT users.id AS users_id,
        users.name AS users_name,
        users.fullname AS users_fullname,
        users.password AS users_password
FROM users
WHERE users.id = ?
(1,)
u'ed'
>>> fake_user in session
False


我們可以看到ed_user的名字變回ed,并且我們不期望的用戶fake_user被“踢出”會話(Session)了。

最后,我們可以查詢一下用戶名在['ed', 'fakeuser']范圍的用戶,確保我們的更改是有效的:

教程實例 代碼如下:

>>> session.query(User).filter(User.name.in_(['ed', 'fakeuser'])).all()
SELECT users.id AS users_id,
        users.name AS users_name,
        users.fullname AS users_fullname,
        users.password AS users_password
FROM users
WHERE users.name IN (?, ?)
('ed', 'fakeuser')
[<User('ed','Ed Jones', 'f8s7ccs')>]

好了,今天就到這里,今天我們講解了添加對象和事務回滾,或多或少穿插了些簡單的查詢,接下來我們會介紹較為復雜一些的查詢語句,敬請期待!

相關教程

Python ORM框架SQLAlchemy學習筆記之關系映射實例

昨天簡單介紹了SQLAlchemy的使用,但是沒有能夠涉及其最精彩的ORM部分,今天我將簡單說明一下,當然主要還是講解官方文檔的內容,由于是學習筆記,有可能存在精簡或者自己理解的部 …

Lua學習筆記之數據結構

Lua學習筆記之數據結構

最近研究Lua,順便寫點筆記吧!數據結構是沒有語言之分的,只不過不同的語言實現起來的語法不同,既然是Lua菜鳥,就來實現幾個常用的數據結構來練練語法吧!首先是作為數據結構 …

Lua學習筆記之數據類型

Lua學習筆記之數據類型

從本篇博客開始研究一下Lua,現在的Lua真得是很火,因為Cocos2d-x寫游戲的時候會用到,所以就拿過來學學吧,先從基礎的語法開始,然后慢慢的深入。本人也是剛剛學習,希望和學習 …

MySQL學習筆記之數據的增、刪、改實現方法

本文實例講述了MySQL學習筆記之數據的增、刪、改實現方法。分享給大家供大家參考,具體如下: 一、增加數據 插入代碼格式: insert into 表明 [列名…] values (值…) create table test21(nam …

MySQL學習筆記之數據定義表約束,分頁方法總結

本文實例講述了MySQL學習筆記之數據定義表約束,分頁方法。分享給大家供大家參考,具體如下: 1. primary key 主鍵 特點:主鍵是用于唯一標識一條記錄的約束,一張表最多只能有一個主 …

Python學習筆記_數據排序方法

1. 原地排序:采用sort()方法,按照指定的順序排列數據后用排序后的數據替換原來的數據(原來的順序丟失),如: 教程實例 代碼如下: data1=[4,2,6,432,78,43,22,896,42,677,12] data1.sort() data1 …

JavaScript學習筆記之數組隨機排序

推薦閱讀: JavaScript學習筆記之數組求和方法 JavaScript學習筆記之數組的增、刪、改、查 JavaScript中提供了sort()和reverse()方法對數組項重新排序。但很多時候這兩個方法無法滿足我們實際 …

JavaScript學習筆記之數組求和方法

JavaScript學習筆記之數組求和方法

推薦閱讀: JavaScript學習筆記之數組的增、刪、改、查 通過最近學習,越來越感覺JavaScript的強大與魅力之處,僅數組一個知識點就讓我這樣的初學者折騰了很久。折騰是折騰,但還是很 …

内蒙古十一选五任五推荐号