SQLAlchemy 中的 Session、sessionmaker、scoped_session
SQLAlchemy 中的 Session、sessionmaker、scoped_session
目錄
- 一、關(guān)于 Session
- 1. Session是緩存嗎?
- 2. Session作用:
- 3. Session生命周期:
- 4. Session什么時(shí)候創(chuàng)建,提交,關(guān)閉?
- 4. 獲取一個(gè)Session:
- 5. 關(guān)于SQLAlchemy 的 create_engine:
- 6. 關(guān)于線程安全:
- 二、單線程下 scoped_session 對(duì)創(chuàng)建 Session 的影響
- 1. 兩個(gè) Session 添加同一個(gè)對(duì)象
- 2. 不同的 Session 添加不同的對(duì)象
- 3. 用 scoped_session 創(chuàng)建 Session
- 三、多線程下 scoped_session 對(duì)創(chuàng)建 Session 的影響
- 1. 當(dāng)不用 scoped_session 時(shí):
- 2. 當(dāng)使用 scoped_session 時(shí):
一、關(guān)于 Session
Session 其實(shí) 就是一個(gè)會(huì)話, 可以和數(shù)據(jù)庫(kù)打交道的一個(gè)會(huì)話
在一般的意義上, 會(huì)話建立與數(shù)據(jù)庫(kù)的所有對(duì)話,并為你在其生命周期中加載或關(guān)聯(lián)的所有對(duì)象表示一個(gè)“等待區(qū)”。他提供了一個(gè)入口點(diǎn)獲得查詢對(duì)象, 向數(shù)據(jù)庫(kù)發(fā)送查詢,使用會(huì)話對(duì)象的當(dāng)前數(shù)據(jù)庫(kù)連接, 將結(jié)果行填充在對(duì)象中, 然后存儲(chǔ)在會(huì)話中, 在這種結(jié)構(gòu)中稱為身份映射 – 這種數(shù)據(jù)結(jié)構(gòu)維護(hù)了每一個(gè)副本的唯一, 這種唯一意味著一個(gè)對(duì)象只能有一個(gè)特殊的唯一主鍵。
會(huì)話以基本無(wú)狀態(tài)的形式開(kāi)始,一旦發(fā)出查詢或其他對(duì)象被持久化,它就會(huì)從一個(gè)引擎申請(qǐng)連接資源,該引擎要么與會(huì)話本身相關(guān)聯(lián),要么與正在操作的映射對(duì)象相關(guān)聯(lián)。此連接標(biāo)識(shí)正在進(jìn)行的事務(wù), 在會(huì)話提交或回滾其掛起狀態(tài)之前,該事務(wù)一直有效。
會(huì)話中維護(hù)的所有變化的對(duì)象都會(huì)被跟蹤 - 在再次查詢數(shù)據(jù)庫(kù)或提交當(dāng)前事務(wù)之前, 它將刷新對(duì)數(shù)據(jù)庫(kù)的所有更改, 這被稱為工作模式單元。
在使用會(huì)話時(shí)候,最重要的是要注意與它相關(guān)聯(lián)的對(duì)象是會(huì)話所持有的事務(wù)的代理對(duì)象 - 為了保持同步,有各種各樣的事件會(huì)導(dǎo)致對(duì)象重新訪問(wèn)數(shù)據(jù)庫(kù)??赡軓臅?huì)話中分離對(duì)象并繼續(xù)使用他們,盡管這種做法有其局限性。但是通常來(lái)說(shuō),當(dāng)你希望再次使用分離的對(duì)象時(shí)候,你會(huì)將他們與另一個(gè)會(huì)話重新關(guān)聯(lián)起來(lái), 以便他們能夠恢復(fù)表示數(shù)據(jù)庫(kù)狀態(tài)的正常任務(wù)。
1. Session是緩存嗎?
可能會(huì)將這里的session與http中的session搞混,需要注意的是,它有點(diǎn)用作緩存,因?yàn)樗鼘?shí)現(xiàn)了 身份映射 模式,并存儲(chǔ)了鍵入其主鍵的對(duì)象。但是,它不執(zhí)行任何類型的查詢緩存。 此外,默認(rèn)情況下,Session使用弱引用存儲(chǔ)對(duì)象實(shí)例。這也違背了將Session用作緩存的目的。關(guān)于session強(qiáng)應(yīng)用下次再討論。2. Session作用:
1. session創(chuàng)建和管理數(shù)據(jù)庫(kù)連接的會(huì)話 2. model object 通過(guò)session對(duì)象訪問(wèn)數(shù)據(jù)庫(kù),并把訪問(wèn)到的數(shù)據(jù)以 Identity Map的方式,映射到Model object中3. Session生命周期:
1. session在剛被創(chuàng)建的時(shí)候,還沒(méi)有和任何model object 綁定,可認(rèn)為是無(wú)狀態(tài)的 2. session 接受到query查詢語(yǔ)句, 執(zhí)行的結(jié)果或保持或者關(guān)聯(lián)到session中 3. 任意數(shù)量的model object被創(chuàng)建,并綁定到session中,session會(huì)管理這些對(duì)象 4. 一旦session 里面的objects 有變化,那可是要commit/rollback提交或者放棄changs4. Session什么時(shí)候創(chuàng)建,提交,關(guān)閉?
一般來(lái)說(shuō),session在需要訪問(wèn)數(shù)據(jù)庫(kù)的時(shí)候創(chuàng)建,在session訪問(wèn)數(shù)據(jù)庫(kù)的時(shí)候,準(zhǔn)確來(lái)說(shuō),應(yīng)該是“add/update/delete”數(shù)據(jù)庫(kù)的時(shí)候,會(huì)開(kāi)啟database transaction。假設(shè)沒(méi)有修改autocommit的默認(rèn)值(False), 那么,database transaction 一直會(huì)保持,只有等到session發(fā)生rolled back、committed、或者closed的時(shí)候才結(jié)束,一般建議,當(dāng)database transaction結(jié)束的時(shí)候,同時(shí)close session,以保證,每次發(fā)起請(qǐng)求,都會(huì)創(chuàng)建一個(gè)新的session特別是對(duì)web應(yīng)用來(lái)說(shuō),發(fā)起一個(gè)請(qǐng)求,若請(qǐng)求使用到Session訪問(wèn)數(shù)據(jù)庫(kù),則創(chuàng)建session,處理完這個(gè)請(qǐng)求后,關(guān)閉session4. 獲取一個(gè)Session:
Session 是一個(gè)直接實(shí)例化的常規(guī)的Python 類。然而, 為了標(biāo)準(zhǔn)會(huì)會(huì)話的配置和獲取方式, sessionmaker 類通常用于創(chuàng)建頂級(jí)會(huì)話配置, 然后可以在整個(gè)應(yīng)用程序中使用它, 就不需要重復(fù)配置參數(shù)。下面是sessionmaker 的使用方式
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker# 創(chuàng)建連接數(shù)據(jù)庫(kù)的引擎,session連接數(shù)據(jù)庫(kù)需要 my_engine = create_engine('mysql+pymysql://root:123456@localhost/my_db')# 創(chuàng)建一個(gè)配置過(guò)的Session類 Session = sessionmaker(bind=my_engine)# 實(shí)例化一個(gè)session db_session = Session()# 使用session myobject = MyObject('foo', 'bar') db_session.add(myobject) db_session.commit()在上面,該sessionmaker()創(chuàng)建了一個(gè)工廠類,在創(chuàng)建這個(gè)工廠類時(shí)我們配置了參數(shù)綁定了引擎。將其賦值給Session。每次實(shí)例化Session都會(huì)創(chuàng)建一個(gè)綁定了引擎的Session。這樣這個(gè)session在訪問(wèn)數(shù)據(jù)庫(kù)時(shí)都會(huì)通過(guò)這個(gè)綁定好的引擎來(lái)獲取連接資源
當(dāng)你編寫(xiě)應(yīng)用程序時(shí), 請(qǐng)將sessionmaker 工廠放在全局級(jí)別,視作應(yīng)用程序配置的一部分。例如:應(yīng)用程序包中有三個(gè).py文件,您可以將該sessionmaker行放在__init__.py文件中; 在其他模塊“from mypackage import Session”。這樣,所有的Session()的配置都由該配置中心控制。
5. 關(guān)于SQLAlchemy 的 create_engine:
直接只用 create_engine 時(shí),就會(huì)創(chuàng)建一個(gè)帶連接池的引擎:
my_engine = create_engine('mysql+pymysql://root:123456@localhost/my_db')創(chuàng)建一個(gè)session,連接池會(huì)分配一個(gè)connection。當(dāng)session在使用后顯示地調(diào)用 session.close(),也不能把這個(gè)連接關(guān)閉,而是由由QueuePool連接池管理并復(fù)用連接。
確保 session 在使用完成后用 session.close、session.commit 或 session.rollback 把連接還回 pool,這是一個(gè)必須在意的習(xí)慣。
關(guān)于SQLAlchemy 數(shù)據(jù)庫(kù)連接池:
session 和 connection 不是相同的東西, session 使用連接來(lái)操作數(shù)據(jù)庫(kù),一旦任務(wù)完成 session 會(huì)將數(shù)據(jù)庫(kù) connection 交還給 pool。在使用 create_engine 創(chuàng)建引擎時(shí),如果默認(rèn)不指定連接池設(shè)置的話,一般情況下,SQLAlchemy 會(huì)使用一個(gè) QueuePool 綁定在新創(chuàng)建的引擎上。并附上合適的連接池參數(shù)create_engine() 函數(shù)和連接池相關(guān)的參數(shù)有:
- pool_recycle, 默認(rèn)為 -1, 推薦設(shè)置為 7200, 即如果 connection 空閑了 7200 秒,自動(dòng)重新獲取,以防止 connection 被 db server 關(guān)閉。
- pool_size=5, 連接數(shù)大小,默認(rèn)為 5,正式環(huán)境該數(shù)值太小,需根據(jù)實(shí)際情況調(diào)大
- max_overflow=10, 超出 pool_size 后可允許的最大連接數(shù),默認(rèn)為 10, 這 10 個(gè)連接在使用過(guò)后,不放在 pool 中,而是被真正關(guān)閉的。
- pool_timeout=30, 獲取連接的超時(shí)閾值,默認(rèn)為 30 秒
SQLAlchemy不使用連接池:
在創(chuàng)建引擎時(shí)指定參數(shù) poolclass=NullPool 即禁用了SQLAlchemy提供的數(shù)據(jù)庫(kù)連接池。SQLAlchemy 就會(huì)在執(zhí)行 session.close() 后立刻斷開(kāi)數(shù)據(jù)庫(kù)連接。當(dāng)然,如果沒(méi)有被調(diào)用 session.close(),則數(shù)據(jù)庫(kù)連接不會(huì)被斷開(kāi),直到程序終止。
關(guān)于 SQLAlchemy 的 engine ,這里有一篇文章寫(xiě)的很好:http://sunnyingit.github.io/book/section_python/SQLalchemy-engine.html
6. 關(guān)于線程安全:
session不是線程安全的,在多線程的環(huán)境中,默認(rèn)情況下,多個(gè)線程將會(huì)共享同一個(gè)session。試想一下,假設(shè)A線程正在使用session處理數(shù)據(jù)庫(kù),B線程已經(jīng)執(zhí)行完成,把session給close了,那么此時(shí)A在使用session就會(huì)報(bào)錯(cuò),怎么避免這個(gè)問(wèn)題?
1. 可以考慮在這些線程之間共享Session及其對(duì)象。但是應(yīng)用程序需要確保實(shí)現(xiàn)正確的鎖定方案,以便多個(gè)線程不會(huì)同時(shí)訪問(wèn)Session或其狀態(tài)。SQLAlchemy 中的 scoped_session 就可以證線程安全,下面會(huì)有討論。 2. 為每個(gè)并發(fā)線程維護(hù)一個(gè)會(huì)話,而不是將對(duì)象從一個(gè)Session復(fù)制到另一個(gè)Session,通常使用Session.merge()方法將對(duì)象的狀態(tài)復(fù)制到一個(gè)不同Session的新的本地對(duì)象中。二、單線程下 scoped_session 對(duì)創(chuàng)建 Session 的影響
上面簡(jiǎn)單介紹了sessionmaker的作用,下面開(kāi)始探討 scoped_session 對(duì)創(chuàng)建 Session 的影響?,F(xiàn)在先探討單線程情況。
先聲明待會(huì)實(shí)驗(yàn)用的模型:
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String from sqlalchemy import create_engineBase = declarative_base engine = create_engine("mysql+pymysql://root:123456@127.0.0.1:3306/my_db?charset=utf8mb4")class Person(Base):__tablename__ = 'Person'id = Column(Integer, primary_key=True, autoincrement=True)name = Column(String(length=64), comment='姓名')mobile = Column(String(length=13), comment='手機(jī)號(hào)')id_card_number = Column(String(length=64), comment='身份證')def __str__(self):return '%s(name=%r,mobile=%r,id_card_number=%r)' % (self.__class__.__name__,self.name,self.mobile,self.id_card_number)# 在數(shù)據(jù)庫(kù)中創(chuàng)建模型對(duì)象的表 Base.metadata.create_all(engine)1. 兩個(gè) Session 添加同一個(gè)對(duì)象
1.1 在 commit 之前添加:
from sqlalchemy.orm import sessionmaker, scoped_sessionsession_factory = sessionmaker(bind=engine) # engine 在上面已經(jīng)創(chuàng)建好了person = Person(name='frank-' + 'job3', mobile='111111', id_card_number='123456789')Session= session_factory() s1= session_factory() # s1 : <sqlalchemy.orm.session.Session object at 0x107ec8c18>s2 = session_factory() # s2 : <sqlalchemy.orm.session.Session object at 0x107ee3ac8>print(s1 is s2) # Falseid(s1),id(s2) # 4427910168, 4428020424s1.add(person) s2.add(person) # 會(huì)報(bào)錯(cuò)! # sqlalchemy.exc.InvalidRequestError: Object '<Person at 0x22beb14bf60>' is already attached to session '2' (this is '3')結(jié)論:
通過(guò) sessionmaker 工廠創(chuàng)建了兩個(gè) Session ,而且可以看到 s1 s2 是兩個(gè)不同的 Session 。 在 s1 添加 person 后,繼續(xù)使用 s2 添加 person 報(bào)錯(cuò). 說(shuō) person 這個(gè)對(duì)象 已經(jīng)和 另一個(gè) Session 關(guān)聯(lián)一起來(lái)了, 所以再次關(guān)聯(lián)另一個(gè) Session 就會(huì)報(bào)錯(cuò)。1.2 在 commit 之后添加:
即在上面代碼的 s1.add(person) 之后, s1.commit() ,然后再 s2.add(persion)
這里就沒(méi)帖代碼了。
結(jié)論:
即使在 s1 提交之后,s2 再去添加 person 也會(huì)發(fā)生錯(cuò)誤,但 s1 的提交是成功了的,數(shù)據(jù) person 已經(jīng)存放在數(shù)據(jù)庫(kù)了。 當(dāng) s1 添加 person 并提交,然后關(guān)閉 s1 ,s2再去添加并提交 person 數(shù)據(jù)庫(kù),這不會(huì)報(bào)錯(cuò),但是數(shù)據(jù)庫(kù)也不會(huì)出現(xiàn)兩條 person 數(shù)據(jù)。1.3 再 close 之后添加:
p = Person(name='frank', mobile='11111111', id_card_number='123456789')s1.add(p) s1.commit()s2.add(p) s2.commit()# 也會(huì)報(bào)錯(cuò)!!! # sqlalchemy.exc.InvalidRequestError: Object '<Person at 0x21207e3e128>' is already attached to session '2' (this is '3')p = Person(name='frankcc', mobile='1111111122', id_card_number='1234567890')s1.add(p) s1.commit() s1.close() s2.add(p) s2.commit()# 不會(huì)報(bào)錯(cuò)結(jié)論:
s1 關(guān)閉之后, s2再去添加提交同一個(gè)對(duì)象,不會(huì)報(bào)錯(cuò),但是數(shù)據(jù)庫(kù)值有一條 person 數(shù)據(jù)。2. 不同的 Session 添加不同的對(duì)象
person4 = Person(name='frank-' + 'job4', mobile='4444444444', id_card_number='123456789') person1 = Person(name='frank-' + 'job1', mobile='111111', id_card_number='123456789')s1.add(person1) s2.add(person4) s1.commit() # 提交數(shù)據(jù) s2.commit() # 提交數(shù)據(jù), 寫(xiě)入數(shù)據(jù)庫(kù)結(jié)論:
當(dāng)然,s1 ,s2 添加提交不同的對(duì)象,不會(huì)出錯(cuò)。在數(shù)據(jù)庫(kù)成功新增數(shù)據(jù)。 mysql> select * from person; +----+------------+------------+----------------+ | id | name | mobile | id_card_number | +----+------------+------------+----------------+ | 1 | frank-job1 | 111111 | 123456789 | | 2 | frank-job4 | 4444444444 | 123456789 | +----+------------+------------+----------------+ 2 rows in set (0.00 sec)以上說(shuō)明:
一個(gè)對(duì)象一旦被一個(gè) Session 添加,除非關(guān)閉這個(gè) Session ,不然其他的 Session 無(wú)法添加這個(gè)對(duì)象。 一個(gè) Session 添加并提交一個(gè)對(duì)象,然后關(guān)閉該 Session ,其他的 Session 可以添加并提交這個(gè)對(duì)象,但是數(shù)據(jù)庫(kù)并不會(huì)有這條數(shù)據(jù)。3. 用 scoped_session 創(chuàng)建 Session
session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory)s1 = Session() # <sqlalchemy.orm.session.Session object at 0x0000020E58690240>s2 = Session() # <sqlalchemy.orm.session.Session object at 0x0000020E58690240>print(s1 is s2) # Truep = Person(name='frankaaabb', mobile='1111111122233', id_card_number='12345678900099')s1.add(p) s2.add(p) s2.commit()結(jié)論:
可以看到,通過(guò)scoped_session再去創(chuàng)建 Session ,返回的是同一個(gè) Session 。 scoped_session類似單例模式,當(dāng)我們調(diào)用使用的時(shí)候,會(huì)先在Registry里找找之前是否已經(jīng)創(chuàng)建Session,未創(chuàng)建則創(chuàng)建 Session ,已創(chuàng)建則直接返回。三、多線程下 scoped_session 對(duì)創(chuàng)建 Session 的影響
這里探討在多線程下使用 scoped_session 與不使用 scoped_session 的情況
1. 當(dāng)不用 scoped_session 時(shí):
當(dāng)不使用 scoped_session 時(shí),也分兩種情況,是否創(chuàng)建全局性 Session
1.1 多線程下不設(shè)置 Session 為全局變量
session_factory = sessionmaker(bind=engine) Session = session_factorydef job(name):session = Session()print(f"id session:{id(session)}")person = Person(name='frank-' + name, mobile='111111', id_card_number='123456789')print(f"{name} person is add..")session.add(person)time.sleep(1)if name == 'job3':# 線程3 提交, 其他線程不提交.session.commit()session.close()if __name__ == '__main__':thread_list = []# 創(chuàng)建5個(gè)線程for i in range(5):name = 'job' + str(i)t = threading.Thread(target=job, name=name, args=(name,))thread_list.append(t)for t in thread_list:t.start()for t in thread_list:t.join()結(jié)論:
每個(gè)線程下的 Session 都是不同的 Session 數(shù)據(jù)庫(kù)成功新增了線程3提交的數(shù)據(jù),其他的線程中的數(shù)據(jù)并沒(méi)有提交到數(shù)據(jù)庫(kù)中去。 id session:2557871997392 job0 person is add.. id session:2557871998064 job1 person is add.. id session:2557871998568 job2 person is add.. id session:2557871999072 job3 person is add.. id session:2557871999688 job4 person is add..mysql> select * from person; +----+------------+--------+----------------+ | id | name | mobile | id_card_number | +----+------------+--------+----------------+ | 14 | frank-job3 | 111111 | 123456789 | +----+------------+--------+----------------+ 1 row in set (0.00 sec)1.2 在多線程下用全局 Session
session_factory = sessionmaker(bind=engine) Session = session_factory session = Session()def job(name):global sessionprint(f"id session:{id(session)}")person = Person(name='frank-' + name, mobile='111111', id_card_number='123456789')print(f"{name} person is add..")session.add(person)time.sleep(1)if name == 'job3':# 線程3 提交, 其他線程不提交.session.commit()session.close()if __name__ == '__main__':thread_list = []# 創(chuàng)建5個(gè)線程for i in range(5):name = 'job' + str(i)t = threading.Thread(target=job, name=name, args=(name,))thread_list.append(t)for t in thread_list:t.start()for t in thread_list:t.join()結(jié)論:
全部線程下的 Session 都時(shí)同一個(gè) Session 每個(gè)線程下的數(shù)據(jù)都被提交到了數(shù)據(jù)庫(kù) id session:2737857674824 job0 person is add.. id session:2737857674824 job1 person is add.. id session:2737857674824 job2 person is add.. id session:2737857674824 job3 person is add.. id session:2737857674824 job4 person is add..mysql> select * from person; +----+------------+--------+----------------+ | id | name | mobile | id_card_number | +----+------------+--------+----------------+ | 15 | frank-job0 | 111111 | 123456789 | | 16 | frank-job2 | 111111 | 123456789 | | 17 | frank-job1 | 111111 | 123456789 | | 18 | frank-job3 | 111111 | 123456789 | | 19 | frank-job4 | 111111 | 123456789 | +----+------------+--------+----------------+ 5 rows in set (0.00 sec)2. 當(dāng)使用 scoped_session 時(shí):
2.1 多線程下不設(shè)置 Session 為全局變量
session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory)def job(name):session = Session()print(f"id session:{id(session)}")person = Person(name='frank-' + name, mobile='111111', id_card_number='123456789')print(f"{name} person is add..")session.add(person)time.sleep(1)if name == 'job3':# 線程3 提交, 其他線程不提交.session.commit()session.close()if __name__ == '__main__':thread_list = []# 創(chuàng)建5個(gè)線程for i in range(5):name = 'job' + str(i)t = threading.Thread(target=job, name=name, args=(name,))thread_list.append(t)for t in thread_list:t.start()for t in thread_list:t.join()結(jié)論:
每個(gè)線程下的 Session 都不相同 只有線程3下的數(shù)據(jù)被提交到了數(shù)據(jù)庫(kù) id session:2173841850832 job0 person is add.. id session:2173841851504 job1 person is add.. id session:2173841851896 job2 person is add.. id session:2173841852008 job3 person is add.. id session:2173841853128 job4 person is add..mysql> select * from person; +----+------------+--------+----------------+ | id | name | mobile | id_card_number | +----+------------+--------+----------------+ | 32 | frank-job3 | 111111 | 123456789 | +----+------------+--------+----------------+ 1 row in set (0.00 sec)2.2 多線程下設(shè)置 Session 為全局變量
session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session()def job(name):global sessionprint(f"id session:{id(session)}")person = Person(name='frank-' + name, mobile='111111', id_card_number='123456789')print(f"{name} person is add..")session.add(person)time.sleep(1)if name == 'job3':# 線程3 提交, 其他線程不提交.session.commit()session.close()if __name__ == '__main__':thread_list = []# 創(chuàng)建5個(gè)線程for i in range(5):name = 'job' + str(i)t = threading.Thread(target=job, name=name, args=(name,))thread_list.append(t)for t in thread_list:t.start()for t in thread_list:t.join()結(jié)論:
每個(gè)線程下的 Session 是同一個(gè) Session 每個(gè)線程下的數(shù)據(jù)都沒(méi)提交到了數(shù)據(jù)庫(kù) id session:2810724382032 job0 person is add.. id session:2810724382032 job1 person is add.. id session:2810724382032 job2 person is add.. id session:2810724382032 job3 person is add.. id session:2810724382032 job4 person is add..mysql> select * from person; +----+------------+--------+----------------+ | id | name | mobile | id_card_number | +----+------------+--------+----------------+ | 33 | frank-job0 | 111111 | 123456789 | | 34 | frank-job2 | 111111 | 123456789 | | 35 | frank-job1 | 111111 | 123456789 | | 36 | frank-job3 | 111111 | 123456789 | | 37 | frank-job4 | 111111 | 123456789 | +----+------------+--------+----------------+ 5 rows in set (0.00 sec)以上說(shuō)明:
在同一個(gè)線程中,有 scoped_session 的時(shí)候,返回的是同一個(gè) Session 對(duì)象。 在多線程下,即使通過(guò) scoped_session 創(chuàng)建Session,每個(gè)線程下的 Session 都是不一樣的,每個(gè)線程都有一個(gè)屬于自己的 Session 對(duì)象,這個(gè)對(duì)象只在本線程下共享。 scoped_session 只有在單線程下才能發(fā)揮其作用。在多線程下顯得沒(méi)有什么作用。總結(jié)
以上是生活随笔為你收集整理的SQLAlchemy 中的 Session、sessionmaker、scoped_session的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Matlab 2016 超详细安装教程
- 下一篇: MatLab 2016b下载资源