創(chuàng)建會(huì)話
我們現(xiàn)在準(zhǔn)備去和數(shù)據(jù)庫進(jìn)行交互。ORM
操作數(shù)據(jù)庫的工具就是session
,當(dāng)我們第一次設(shè)置應(yīng)用程序杆查,和create_engin()
在同一個(gè)級(jí)別的,我們定義一個(gè)Session
類臀蛛,這個(gè)是一個(gè)工廠為我們產(chǎn)生Seesion
對(duì)象亲桦。
>>> from sqlalchemy.orm import sessionmaker
>>> Session = sessionmaker(bind=engine)
我們可以發(fā)現(xiàn)我們的sessionmaker()
方法有一個(gè)bind的參數(shù)。當(dāng)你的應(yīng)用在沒有Engine
時(shí)浊仆,在你定義你的模型級(jí)對(duì)象是只需要像下面這樣定義:
>>>Session = sessionmaker()
在這之后客峭,當(dāng)你創(chuàng)建了你的引擎create_engine()
,想讓引擎連接到會(huì)話上,可以使用configure()
:
>>> Session.configure(bind=engine)
這個(gè)定制的Session
類將創(chuàng)建綁定到我們數(shù)據(jù)庫的新的Session
對(duì)象抡柿。當(dāng)調(diào)用sessionmaker
時(shí)候也可以定義其他的事物特征舔琅,之后的內(nèi)容會(huì)講到。然后洲劣,每當(dāng)需要與數(shù)據(jù)庫進(jìn)行對(duì)話時(shí)备蚓,都會(huì)實(shí)例化一個(gè)會(huì)話Session
:
>>> session = Session()
上面我們的Session
和我們的數(shù)據(jù)庫引擎想關(guān)聯(lián),但是它沒有打開任何的數(shù)據(jù)庫連接囱稽。
當(dāng)它第一次使用時(shí)郊尝,它從引擎維護(hù)的連接池檢索連接,并保持這個(gè)款連接战惊,直到我們提交所有更改或關(guān)閉會(huì)話對(duì)象流昏。
添加、更新一個(gè)對(duì)象
為了持久化我們的User
對(duì)象样傍,我們將使用add()
將它添加到會(huì)話中:
>>>yu_user = User(name="yu", fullname="yuziyong", password="123")
>>> session.add(yu_user)
此刻横缔,我們可以說這個(gè)實(shí)例是持久化的,
沒有任何SQL語句執(zhí)行衫哥,并且對(duì)象尚未由數(shù)據(jù)庫中的行表示茎刚。這個(gè)Session
將會(huì)在需要時(shí)發(fā)出SQL持久化yuziyong
,使用一個(gè)稱之為刷新的過程。如果我們查找數(shù)據(jù)庫中的"yuziyong",所有持久化的信息將首先被刷新撤逢,并立即發(fā)出查詢膛锭。
下面舉個(gè)例子粮坞,我們創(chuàng)建一個(gè)新的查詢,加載User實(shí)例初狰,我們使用name
進(jìn)行過濾出名字為ricky的結(jié)果莫杈,
并指出我們只想獲取完整列表中的第一個(gè)結(jié)果。返回一個(gè)等效于我們添加的用戶實(shí)例:
>>> >>> our_user = session.query(User).filter_by(name="yu").first()
2017-03-08 22:31:13,130 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, password) VALUES (%(name)s, %(fullname)s, %(password)s) RETURNING users.id
2017-03-08 22:31:13,130 INFO sqlalchemy.engine.base.Engine {'fullname': 'yuziyong', 'password': '123', 'name': 'yu'}
2017-03-08 22:31:13,130 INFO sqlalchemy.engine.base.Engine 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 = %(name_1)s
LIMIT %(param_1)s
2017-03-08 22:31:13,130 INFO sqlalchemy.engine.base.Engine {'name_1': 'yu', 'param_1': 1}
事實(shí)上奢入,Session已經(jīng)識(shí)別出返回的行與在其內(nèi)部對(duì)象映射中已經(jīng)表示的行是相同的行筝闹,所以我們實(shí)際上得到了與剛才添加的相同的實(shí)例。
>>> our_user is yu_user
True
我們還可以使用add_all()
來一次往session中添加多個(gè):
>>> session.add_all([
... User(name='wendy', fullname='Wendy Williams', password='foobar'),
... User(name='mary', fullname='Mary Contrary', password='xxg527'),
... User(name='fred', fullname='Fred Flinstone', password='blah')])
現(xiàn)在我們決定改變yu的密碼:
>>> yu_user.password='000'
Session
會(huì)注意到變化腥光,例如:它知道yu的密碼被修改:
>>> session.dirty
IdentitySet([<User(name=yu, fullname=yuziyong, password=000)>])
>>>
現(xiàn)在三個(gè)新的對(duì)象正在等待:
>>> session.new
IdentitySet([<User(name='wendy', fullname='Wendy Williams', password='foobar')>,
<User(name='mary', fullname='Mary Contrary', password='xxg527')>,
<User(name='fred', fullname='Fred Flinstone', password='blah')>])
我們告訴Session
,我們想要對(duì)數(shù)據(jù)庫發(fā)出所有剩余的更改并提交事務(wù)关顷,使用session.commit()
>>> session.commit()
commit()清除數(shù)據(jù)庫中剩余的任何更改,并提交事務(wù),會(huì)話引用的連接資源現(xiàn)在返回到連接池武福。
事物回滾
由于會(huì)話在一個(gè)事務(wù)中工作议双,我們可以回滾更改。讓我們做兩個(gè)更改捉片,我們將還原yu_user的用戶名設(shè)置為ziyong.
>>> yu_user.name = 'ziyong'
然后我們添加一個(gè)新的非法的用戶:
>>> fake_user = User(name='fakeuser', fullname='Invalid', password='12345')
>>> session.add(fake_user)
查詢會(huì)話平痰,我們可以看到它們被刷入當(dāng)前事務(wù):
>>> session.query(User).filter(User.name.in_(['Edwardo', 'fakeuser'])).all()
2017-03-08 22:53:58,535 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2017-03-08 22:53:58,535 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.fullname AS users_fullname, users.password AS users_password
FROM users
WHERE users.id = %(param_1)s
2017-03-08 22:53:58,535 INFO sqlalchemy.engine.base.Engine {'param_1': 6}
2017-03-08 22:53:58,535 INFO sqlalchemy.engine.base.Engine UPDATE users SET name=%(name)s WHERE users.id = %(users_id)s
2017-03-08 22:53:58,535 INFO sqlalchemy.engine.base.Engine {'users_id': 6, 'name': 'ziyong'}
2017-03-08 22:53:58,535 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, password) VALUES (%(name)s, %(fullname)s, %(password)s) RETURNING users.id
2017-03-08 22:53:58,535 INFO sqlalchemy.engine.base.Engine {'fullname': 'Invalid', 'password': '12345', 'name': 'fakauser'}
2017-03-08 22:53:58,535 INFO sqlalchemy.engine.base.Engine 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 (%(name_1)s, %(name_2)s)
2017-03-08 22:53:58,535 INFO sqlalchemy.engine.base.Engine {'name_2': 'fakeuser', 'name_1': 'Edwardo'}
[]
回滾,我們能看到yu_user
的名字回滾為yu
,并且剛添加的非法用戶也沖會(huì)話中刪除伍纫。
>>> session.rollback()
2017-03-08 22:57:44,322 INFO sqlalchemy.engine.base.Engine ROLLBACK
>>> yu_user.name
2017-03-08 22:57:51,135 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2017-03-08 22:57:51,135 INFO sqlalchemy.engine.base.Engine 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 = %(param_1)s
2017-03-08 22:57:51,135 INFO sqlalchemy.engine.base.Engine {'param_1': 6}
u'yu'
>>> fake_user in session
False
>>>
再次查詢:
>>> session.query(User).filter(User.name.in_(['yu', 'fakeuser'])).all()
2017-03-08 23:01:47,980 INFO sqlalchemy.engine.base.Engine 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 (%(name_1)s, %(name_2)s)
2017-03-08 23:01:47,980 INFO sqlalchemy.engine.base.Engine {'name_2': 'fakeuser', 'name_1': 'yu'}
[<User(name=yu, fullname=yuziyong, password=000)>]