python
sqlalchemy
如果你有注意到的話應該會發現到前面大多說明的是CORE的用法,那這邊開始就會來談談ORM的部份。官方建議在進入這邊之前可以先讀讀:
這大致上就是官方教程的一部份,順著讀過來也有一定的觀念了,不用太擔心。
當我們使用ORM的時候,Session就是做為建構Insert結構,然後在執行的交易記錄中把它們做為INSERT statements發送出去。我們要Session做的就是把object entires(就是要寫入的資料)加進去,然後要確保這些資料能夠在需要時候以flush的方式寫入資料庫。這樣的過程就是unit of work pattern。
在ORM的話,我們所建立的class、User與Address,不僅能夠拿來定義資料表,也可以直接做為操作使用,下面給出兩個範例:
兩個object分別代表兩筆記錄,目前還沒有寫入資料庫,你可以發現鍵值(pk)的部份是None:
這時候的狀態是屬於『transient』,也就是非持久化或暫時的狀態,而且也跟Session八字沒一撇,毫無關聯。
下面我們就來利用Session
處理後續的過程,這次的作法跟之前的with
較不一樣:
然後利用Session.add
將預計寫入的資料peding進去:
這時候可以用Session.new
來看一下這些pending進去的資料狀況:
可以發現,這時候跟資料庫還是沒有任何的關係,因為Session採用的是unit of work的方式,這意思就是異動會累積,然後在你有需要的時候才會實際跟資料庫有實際的交握,也就是flush:
要注意,這時候的transcation仍然是open的狀態,直到我們呼叫Session.commit(), Session.rollback(), Session.close()
。不過也不是每次都要利用flush,直接的commit也是可以的。
在插入這兩個物件之後,它們的狀態就不再是transient,而是persistent。而且這時候這兩個物件的id
也不再是None,有屬於它們的屬性值了:
物件的primary key identity對於Session來說是非常重要的,因為物件就是用identity map跟記憶體中的這個識別值做連結的。那這個identity map指的就是把目前已經載入到記憶體的物件做個連結,靠的就是這個primary key identity。關於這部份我們可以用Session.get()
來試一下:
值得注意的是,這個identity map所對應到的一定是一個唯一的物件:
完成整個交易記錄就可以把它提交:
提交之後,我們處理的物件仍然還是在Session,這個狀態會一直到把這個Session關閉。
要怎麼利用ORM更新資料呢?我們可以利用Session.exectue
來做一系列的搜尋:
上面這個表達式說的是,從User
去搜尋name="sandy"
的資料:
好,現在這個sandy
代表的就是資料表中id=2
的這筆記錄。
如果你去改變這個物件(sandy
)的屬性,那Session就會追蹤這個變化,這個部份會在Session.dirty
顯示:
現在,只要這個Session做一次flush,那就會更新資料庫的值。記得,在發出任何的SELECT之前,都會自動的發出flush,也就是autoflush。直接來搜尋一次,測試給你看:
我們沒有執行flush,只是重新的做一次搜尋,可以發現得到的sql statement存在update,你可以列印出來驗證:
因為已經flush了,自然不存在Session.dirty
的清單中:
當然啦,我們的整個交易記錄還沒有確認,所以實際資料庫中,sandy的fullname仍然是Cheeks
就是了。
來吧,讓我們來完成整個演練吧,再來就是刪除,先從資料庫來筆資料:
一樣的,你刪,但是沒有flush之前什麼事都是沒有發生的:
這個物件仍然是存在Session中,一直到flush,一樣的,搜尋一下來觸發autoflush:
應該可以注意到,這邊除了我們所執行的user_account之外,還有一個address的table也被執行,這是一個cascade(級聯),如果有對應的資料存在的話,也會一併的處理掉。
一樣的,目前的操作都是在Session,沒有commit就不會影響資料庫。
Session有一個方法Session.rollback()
,總之就是把目前正進行中的處理都做一個ROLLBACK。像剛剛我們做的sandy的改名,只要你執行Session.rollback()
,那這個改變就會會回滾了,不止它喔,目前所有Session相關的通通expire(失效):
從sandy.__dict__
更仔細的來看這個失效過程:
這個dict
裡面沒有東西,就只有一個SQLAlchemy的內部狀態,這就是失效的狀況,現在再來看一次sandy.fullname
可以發現,一切都還原了:
可以發現,在確認sandy.fullname
的時候重新做了一次select。這時候再來看一次sandy.__dict__
:
完整的資料庫記錄寫入sandy.__dict__
了。那剛剛我們刪除掉已經不存在Session的物件patrick
也回到session內:
這次的操作我們並不是利用with
讓整個session在一個上下文中執行,所以我們就必需要手動來關閉:
當我們執行close
的時候會有幾件事發生:
Session.rollback()
sandy, partick, squidward
,通通都detached(啪,沒啦):不過那些被分離(detached)的物件你還是可以用Session.add()
來跟新的Session,或是原本的Session來重新關聯,這會重新建議它們跟資料庫之間的關聯: