Python數(shù)據(jù)庫操作(SQLAlchemy、SQLite等)面試題集附答案_第1頁
Python數(shù)據(jù)庫操作(SQLAlchemy、SQLite等)面試題集附答案_第2頁
Python數(shù)據(jù)庫操作(SQLAlchemy、SQLite等)面試題集附答案_第3頁
Python數(shù)據(jù)庫操作(SQLAlchemy、SQLite等)面試題集附答案_第4頁
Python數(shù)據(jù)庫操作(SQLAlchemy、SQLite等)面試題集附答案_第5頁
已閱讀5頁,還剩22頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

Python數(shù)據(jù)庫操作(SQLAlchemy、SQLite等)面試題集附答案Q1:SQLAlchemy的Core模式與ORM模式的核心區(qū)別是什么?實(shí)際開發(fā)中如何選擇?A:Core模式是SQLAlchemy的底層SQL抽象層,提供基于Python的SQL表達(dá)式構(gòu)建工具(如Table、Column、MetaData),允許開發(fā)者以更接近原生SQL的方式操作數(shù)據(jù)庫,適合需要精細(xì)控制SQL語句或處理復(fù)雜查詢的場景。ORM模式則通過對象-關(guān)系映射,將數(shù)據(jù)庫表映射為Python類,表記錄映射為類實(shí)例,字段映射為實(shí)例屬性,屏蔽了底層SQL細(xì)節(jié),適合業(yè)務(wù)邏輯層快速開發(fā)。選擇時(shí),若需高性能復(fù)雜查詢(如多表關(guān)聯(lián)、自定義函數(shù))或操作非關(guān)系型結(jié)構(gòu)(如JSON字段),優(yōu)先Core;若業(yè)務(wù)對象明確、注重代碼可維護(hù)性,優(yōu)先ORM。Q2:使用SQLAlchemyORM定義模型時(shí),為什么需要繼承declarative_base()提供的基類?基類的MetaData對象有何作用?A:declarative_base()創(chuàng)建的基類(通常命名為Base)封裝了ORM的核心功能,包括模型類到數(shù)據(jù)庫表的映射邏輯、字段類型校驗(yàn)、關(guān)系管理等。繼承該基類后,模型類才能被SQLAlchemy識別為映射類。Base.metadata是MetaData的實(shí)例,存儲了所有模型類的表結(jié)構(gòu)元數(shù)據(jù)(如表名、字段、索引、外鍵約束)。通過metadata.create_all(engine)可一次性將所有模型對應(yīng)的表創(chuàng)建到數(shù)據(jù)庫;metadata.drop_all(engine)則刪除所有表。MetaData還支持按模塊或功能分組(如不同MetaData實(shí)例管理不同業(yè)務(wù)的表),提升大型項(xiàng)目的結(jié)構(gòu)清晰度。Q3:在SQLAlchemyORM中,如何定義一對多(One-to-Many)關(guān)系?反向引用(backref)的作用是什么?A:一對多關(guān)系通過在“一”方模型中定義relationship字段,“多”方模型中定義外鍵實(shí)現(xiàn)。例如,User(用戶)與Post(帖子)是一對多:```pythonfromsqlalchemyimportForeignKeyfromsqlalchemy.ormimportrelationshipclassUser(Base):__tablename__='user'id=Column(Integer,primary_key=True)posts=relationship('Post',backref='user')一對多,反向引用為userclassPost(Base):__tablename__='post'id=Column(Integer,primary_key=True)user_id=Column(Integer,ForeignKey('user.id'))外鍵指向user表id```backref參數(shù)會在“多”方(Post)實(shí)例中自動添加一個(gè)反向引用屬性(如post.user),指向?qū)?yīng)的“一”方(User)實(shí)例,避免手動維護(hù)雙向關(guān)系。需注意backref會隱式創(chuàng)建relationship,可能導(dǎo)致性能問題,復(fù)雜場景建議使用back_populates顯式聲明雙向關(guān)系。Q4:SQLAlchemy中session的作用是什么?如何理解“工作單元(UnitofWork)”模式?A:session是ORM的核心交互接口,負(fù)責(zé)管理對象的生命周期(新增、修改、刪除)、事務(wù)控制及數(shù)據(jù)庫同步。它通過“工作單元”模式統(tǒng)一跟蹤所有對象狀態(tài)變更,在調(diào)用commit()時(shí)將累積的操作(如INSERT/UPDATE/DELETE)批量提交到數(shù)據(jù)庫,確保數(shù)據(jù)一致性。具體來說:-新創(chuàng)建的對象處于“transient”狀態(tài)(未關(guān)聯(lián)session);-add()后變?yōu)椤皃ending”(已關(guān)聯(lián)session但未提交);-commit()后變?yōu)椤皃ersistent”(已持久化到數(shù)據(jù)庫);-從數(shù)據(jù)庫查詢的對象直接是“persistent”狀態(tài);-delete()后變?yōu)椤癲eleted”狀態(tài),commit后從數(shù)據(jù)庫刪除。這種模式避免了逐條執(zhí)行SQL,減少數(shù)據(jù)庫交互次數(shù),同時(shí)通過flush()可手動觸發(fā)狀態(tài)同步(如需要獲取自增ID時(shí))。Q5:使用SQLite時(shí),連接字符串“sqlite:///mydb.db”與“sqlite:////absolute/path/mydb.db”有何區(qū)別?多線程環(huán)境下如何避免“Databaseislocked”錯(cuò)誤?A:單斜杠“sqlite:///mydb.db”表示相對路徑(當(dāng)前工作目錄下創(chuàng)建mydb.db);三斜杠“sqlite:////absolute/path/mydb.db”表示絕對路徑(如Linux的/absolute/path/mydb.db),Windows系統(tǒng)需用四斜杠(如“sqlite:///C:\\absolute\\path\\mydb.db”)。SQLite默認(rèn)啟用“check_same_thread=True”(連接僅允許創(chuàng)建它的線程使用),多線程環(huán)境下若不同線程共享連接會報(bào)“Databaseislocked”。解決方案:1.為每個(gè)線程創(chuàng)建獨(dú)立連接(通過session的bind參數(shù)或scoped_session管理);2.連接時(shí)設(shè)置“check_same_thread=False”(需確保同一時(shí)間僅一個(gè)線程操作數(shù)據(jù)庫):```pythonengine=create_engine('sqlite:///mydb.db?check_same_thread=False')```3.啟用寫操作的序列化(通過PRAGMAjournal_mode=WAL;開啟預(yù)寫日志,允許讀-寫并發(fā),但寫操作仍互斥)。Q6:SQLAlchemyORM中,filter()與filter_by()的區(qū)別是什么?舉例說明使用場景。A:filter()接受SQL表達(dá)式(基于模型類屬性),支持更復(fù)雜的條件組合(如多條件、函數(shù)調(diào)用);filter_by()接受關(guān)鍵字參數(shù)(字段名=值),適用于簡單的等式查詢。例如:-查詢年齡大于20且姓名以“張”開頭的用戶:```pythonfilter()支持復(fù)雜條件User.query.filter(User.age>20,U.like('張%'))```-查詢用戶名為“alice”的用戶(等價(jià)于U=='alice'):```pythonfilter_by()更簡潔User.query.filter_by(name='alice')```注意:filter_by()無法處理非等式條件(如>=、in_)或跨表字段,此時(shí)必須用filter()。Q7:如何處理SQLAlchemy中的N+1查詢問題?eagerloading的常用策略有哪些?A:N+1問題指查詢主對象時(shí)(1次查詢),逐個(gè)查詢關(guān)聯(lián)對象(N次查詢),導(dǎo)致數(shù)據(jù)庫交互次數(shù)暴增。例如:```pythonusers=User.query.all()1次查詢foruserinusers:print(user.posts)每次訪問posts觸發(fā)1次查詢,共N次```解決方法是使用eagerloading(預(yù)加載),通過一次查詢獲取主對象及其關(guān)聯(lián)對象。常用策略:-joinedload:使用JOIN語句將關(guān)聯(lián)對象加載到主查詢中(適合一對一、少量一對多):```pythonfromsqlalchemy.ormimportjoinedloadusers=User.query.options(joinedload(User.posts)).all()1次JOIN查詢```-selectinload:對一對多關(guān)系更高效,通過IN子句批量加載關(guān)聯(lián)對象(避免大JOIN的性能問題):```pythonfromsqlalchemy.ormimportselectinloadusers=User.query.options(selectinload(User.posts)).all()2次查詢(主+批量子)```-subqueryload:通過子查詢預(yù)加載,適用于復(fù)雜過濾條件的關(guān)聯(lián)對象。Q8:在SQLAlchemy中,如何執(zhí)行原生SQL語句?需要注意哪些安全問題?A:通過session.execute()或engine.execute()執(zhí)行原生SQL。ORM模式下推薦使用session.execute(),以便與當(dāng)前事務(wù)綁定:```python執(zhí)行查詢r(jià)esult=session.execute("SELECTFROMuserWHEREage>:age",{'age':20})forrowinresult:print()按列名訪問執(zhí)行寫操作session.execute("UPDATEuserSETscore=score+1WHEREid=:id",{'id':1})mit()需要顯式提交```安全問題:-必須使用參數(shù)化查詢(:name占位符),禁止直接拼接字符串,防止SQL注入;-原生SQL可能破壞ORM的封裝,導(dǎo)致不同數(shù)據(jù)庫方言(如SQLite與PostgreSQL的日期函數(shù)差異)兼容性問題;-結(jié)果集(Row對象)是元組或字典形式,需手動轉(zhuǎn)換為ORM對象(如需)。Q9:SQLite是否支持事務(wù)?SQLAlchemy如何管理SQLite的事務(wù)?A:SQLite完全支持ACID事務(wù),默認(rèn)情況下每個(gè)寫操作(INSERT/UPDATE/DELETE)自動包裹在事務(wù)中,執(zhí)行完畢自動提交。但通過BEGIN/COMMIT/ROLLBACK可顯式控制事務(wù)范圍。SQLAlchemy通過session管理事務(wù):-自動提交模式(autocommit=True):每個(gè)SQL語句執(zhí)行后立即提交(默認(rèn)關(guān)閉,因可能導(dǎo)致性能問題);-手動提交:默認(rèn)模式,所有操作在session中累積,調(diào)用commit()時(shí)提交事務(wù),rollback()時(shí)回滾;-上下文管理器:通過withsession.begin():自動處理提交/回滾(異常時(shí)回滾,正常結(jié)束提交):```pythonwithsession.begin():user=User(name='test')session.add(user)若此處拋出異常,事務(wù)自動回滾```注意:SQLite的事務(wù)是數(shù)據(jù)庫級別的(整個(gè)數(shù)據(jù)庫加鎖),高并發(fā)寫操作可能導(dǎo)致鎖競爭,需結(jié)合WAL模式優(yōu)化。Q10:如何為SQLAlchemy模型添加索引?復(fù)合索引和唯一索引的定義方式有何不同?A:通過Column的index參數(shù)或單獨(dú)的Index類添加索引。單字段索引可直接在Column中聲明:```pythonclassUser(Base):__tablename__='user'id=Column(Integer,primary_key=True)name=Column(String(50),index=True)單字段索引```復(fù)合索引(多字段索引)需使用Index類,放在模型類外:```pythonfromsqlalchemyimportIndexclassUser(Base):__tablename__='user'id=Column(Integer,primary_key=True)first_name=Column(String(50))last_name=Column(String(50))復(fù)合索引(first_name+last_name)Index('idx_name',User.first_name,User.last_name)```唯一索引(UNIQUE約束)通過unique參數(shù)或Index的unique=True實(shí)現(xiàn):```python單字段唯一索引email=Column(String(100),unique=True)復(fù)合唯一索引Index('idx_unique_email_phone',User.email,User.phone,unique=True)```注意:索引會提升查詢性能,但會降低寫操作(INSERT/UPDATE/DELETE)速度,需根據(jù)業(yè)務(wù)場景權(quán)衡。Q11:SQLAlchemy中如何處理數(shù)據(jù)庫遷移(Schema變更)?Alembic的核心命令有哪些?A:SQLAlchemy自身不提供遷移工具,需通過Alembic(SQLAlchemy作者開發(fā)的遷移工具)管理。核心步驟:1.初始化Alembic:alembicinit<目錄名>;2.配置alembic.ini中的sqlalchemy.url為數(shù)據(jù)庫連接字符串;3.在env.py中加載模型(target_metadata=Base.metadata);4.提供遷移腳本:alembicrevision--autogenerate-m"描述信息"(自動對比當(dāng)前模型與數(shù)據(jù)庫Schema提供變更);5.執(zhí)行遷移:alembicupgradehead(應(yīng)用最新遷移);6.回滾遷移:alembicdowngrade-1(回退到前一個(gè)版本)。Alembic的核心命令還包括:-history:查看遷移歷史;-current:查看當(dāng)前數(shù)據(jù)庫版本;-stamp:手動標(biāo)記數(shù)據(jù)庫版本(不執(zhí)行遷移)。Q12:使用SQLAlchemyORM時(shí),如何批量插入大量數(shù)據(jù)?add_all()與bulk_insert_mappings()的區(qū)別是什么?A:批量插入推薦使用bulk_insert_mappings()或bulk_save_objects(),比循環(huán)add()更高效。add_all()逐個(gè)將對象添加到session,會跟蹤每個(gè)對象的狀態(tài)(增加內(nèi)存開銷),提交時(shí)提供多個(gè)INSERT語句(或依賴數(shù)據(jù)庫的批量插入支持);而bulk_insert_mappings()直接接收字典列表,跳過ORM的狀態(tài)跟蹤,提供單條或批量INSERT語句(具體取決于數(shù)據(jù)庫驅(qū)動),性能更高(尤其插入1000條以上數(shù)據(jù)時(shí))。示例:```pythonadd_all():適用于需要后續(xù)操作對象的場景(如獲取自增ID)users=[User(name=f'user_{i}')foriinrange(100)]session.add_all(users)mit()可能提供100條INSERT語句(或數(shù)據(jù)庫批量優(yōu)化)bulk_insert_mappings():高性能批量插入,不跟蹤對象狀態(tài)data=[{'name':f'user_{i}'}foriinrange(1000)]session.bulk_insert_mappings(User,data)mit()通常提供1條INSERT...VALUES(...),(...)語句```注意:bulk操作不會觸發(fā)ORM的事件監(jiān)聽(如before_insert),且無法直接獲取插入后的對象(如需自增ID,需通過其他方式查詢)。Q13:SQLite的“無服務(wù)器(Serverless)”特性具體指什么?它對Python應(yīng)用開發(fā)有何影響?A:“無服務(wù)器”指SQLite不需要獨(dú)立的數(shù)據(jù)庫服務(wù)器進(jìn)程,數(shù)據(jù)庫以文件形式存儲在磁盤中,應(yīng)用程序通過文件IO直接訪問。這意味著:-部署簡單:無需安裝和配置數(shù)據(jù)庫服務(wù),單個(gè)文件即可完成數(shù)據(jù)存儲;-適合嵌入式場景:如桌面應(yīng)用、移動應(yīng)用的本地存儲;-并發(fā)限制:同一時(shí)間僅允許一個(gè)寫操作(讀操作可并發(fā)),不適合高并發(fā)的Web服務(wù)(但可通過WAL模式提升讀-寫并發(fā));-數(shù)據(jù)遷移方便:直接復(fù)制數(shù)據(jù)庫文件即可。Python中使用SQLite時(shí),需注意多線程下的連接管理(如前所述check_same_thread參數(shù)),以及大文件操作的性能問題(SQLite對GB級文件支持良好,但需確保磁盤IO足夠)。Q14:在SQLAlchemyORM中,如何定義多對多(Many-to-Many)關(guān)系?關(guān)聯(lián)表(AssociationTable)是否需要映射為模型類?A:多對多關(guān)系通過關(guān)聯(lián)表(中間表)實(shí)現(xiàn),關(guān)聯(lián)表包含兩個(gè)外鍵,分別指向兩個(gè)主表的主鍵。ORM中定義方式如下:```python關(guān)聯(lián)表(非模型類,僅作為關(guān)系橋梁)association_table=Table('user_role',Base.metadata,Column('user_id',Integer,ForeignKey('user.id')),Column('role_id',Integer,ForeignKey('role.id')))classUser(Base):__tablename__='user'id=Column(Integer,primary_key=True)roles=relationship('Role',secondary=association_table,back_populates='users')classRole(Base):__tablename__='role'id=Column(Integer,primary_key=True)users=relationship('User',secondary=association_table,back_populates='roles')```若關(guān)聯(lián)表僅包含外鍵(純關(guān)系表),無需映射為模型類;若關(guān)聯(lián)表需要額外字段(如用戶-角色的生效時(shí)間),則需定義為模型類(AssociationModel),并使用association_proxy簡化訪問:```pythonclassUserRole(Base):關(guān)聯(lián)模型類__tablename__='user_role'user_id=Column(Integer,ForeignKey('user.id'),primary_key=True)role_id=Column(Integer,ForeignKey('role.id'),primary_key=True)created_at=Column(DateTime,default=datetime.now)user=relationship('User',back_populates='user_roles')role=relationship('Role',back_populates='user_roles')classUser(Base):__tablename__='user'id=Column(Integer,primary_key=True)user_roles=relationship('UserRole',back_populates='user')roles=association_proxy('user_roles','role',creator=lambdarole_obj:UserRole(role=role_obj))代理訪問roles使用時(shí)可直接user.roles.append(role),自動創(chuàng)建UserRole記錄```Q15:SQLAlchemy的連接池(ConnectionPool)默認(rèn)配置是怎樣的?針對SQLite需要做哪些調(diào)整?A:SQLAlchemy默認(rèn)根據(jù)數(shù)據(jù)庫類型選擇連接池:-對于支持持久連接的數(shù)據(jù)庫(如PostgreSQL、MySQL),默認(rèn)使用QueuePool(連接池大小pool_size=5,最大溢出max_overflow=10);-SQLite因是文件型數(shù)據(jù)庫,默認(rèn)使用NullPool(不使用連接池,每次請求新連接),避免多線程共享連接導(dǎo)致的鎖問題。若需為SQLite啟用連接池(如單線程長期運(yùn)行的應(yīng)用),需顯式配置:```pythonfromsqlalchemy.poolimportStaticPoolengine=create_engine('sqlite:///mydb.db',poolclass=StaticPool,靜態(tài)池(單連接)connect_args={'check_same_thread':False}允許跨線程)```注意:SQLite的連接池需謹(jǐn)慎使用,因同一連接在多線程中使用可能導(dǎo)致數(shù)據(jù)不一致或崩潰。Q16:如何在SQLAlchemy中實(shí)現(xiàn)字段的默認(rèn)值(Default)?數(shù)據(jù)庫層默認(rèn)值與ORM層默認(rèn)值有何區(qū)別?A:字段默認(rèn)值可通過Column的default參數(shù)(ORM層)或server_default參數(shù)(數(shù)據(jù)庫層)設(shè)置:```pythonfromsqlalchemyimportfuncclassUser(Base):__tablename__='user'id=Column(Integer,primary_key=True)created_at=Column(DateTime,default=datetime.now)ORM層默認(rèn)(Python端提供時(shí)間)updated_at=Column(DateTime,server_default=func.now())數(shù)據(jù)庫層默認(rèn)(SQL函數(shù)提供時(shí)間)```區(qū)別:-ORM層默認(rèn)值:在對象創(chuàng)建時(shí)(add()之前)由Python代碼提供,適用于本地計(jì)算的值(如固定字符串、簡單時(shí)間);-數(shù)據(jù)庫層默認(rèn)值:在INSERT語句執(zhí)行時(shí)由數(shù)據(jù)庫提供(如數(shù)據(jù)庫的CURRENT_TIMESTAMP),適用于需要嚴(yán)格數(shù)據(jù)庫時(shí)間或依賴數(shù)據(jù)庫函數(shù)的場景(如UUID提供)。注意:若同時(shí)設(shè)置default和server_default,以數(shù)據(jù)庫層的值為準(zhǔn)(因數(shù)據(jù)庫會覆蓋ORM層的默認(rèn))。Q17:SQLAlchemy中如何處理數(shù)據(jù)庫連接超時(shí)?可配置的參數(shù)有哪些?A:連接超時(shí)可通過以下參數(shù)控制:-pool_timeout:連接池等待可用連接的超時(shí)時(shí)間(秒,默認(rèn)30);-connect_args:傳遞給數(shù)據(jù)庫驅(qū)動的連接參數(shù),如SQLite的timeout(等待數(shù)據(jù)庫鎖釋放的時(shí)間,默認(rèn)5秒);-echo_pool:調(diào)試時(shí)打印連接池狀態(tài),幫助定位超時(shí)問題。示例(SQLite設(shè)置連接超時(shí)10秒):```pythonengine=create_engine('sqlite:///mydb.db',pool_timeout=10,連接池等待超時(shí)connect_args={'timeout':10}數(shù)據(jù)庫鎖等待超時(shí))```若應(yīng)用長時(shí)間空閑,可配置pool_recycle(連接回收時(shí)間,秒)避免連接被數(shù)據(jù)庫服務(wù)器關(guān)閉(SQLite無此問題,但MySQL/PostgreSQL需要)。Q18:在SQLAlchemyORM中,如何實(shí)現(xiàn)級聯(lián)刪除(CascadeDelete)?需要注意哪些潛在問題?A:級聯(lián)刪除通過relationship的cascade參數(shù)實(shí)現(xiàn)。例如,刪除User時(shí)自動刪除其所有Post:```pythonclassUser(Base):__tablename__='user'id=Column(Integer,primary_key=True)posts=relationship('Post',cascade='all,delete',backref='user')級聯(lián)刪除classPost(Base):__tablename__='post'id=Column(Integer,primary_key=True)user_id=Column(Integer,ForeignKey('user.id',ondelete='CASCADE'))數(shù)據(jù)庫級聯(lián)(可選)```cascade參數(shù)常用值:-'all':包含save-update、merge、expunge、delete;-'delete':刪除主對象時(shí)刪除關(guān)聯(lián)對象;-'delete-orphan':關(guān)聯(lián)對象與主對象解除關(guān)系時(shí)自動刪除(需設(shè)置orphan_reap=True)。潛在問題:-數(shù)據(jù)庫級聯(lián)(ondelete='CASCADE')與ORM級聯(lián)需同步,避免不一致;-級聯(lián)刪除可能導(dǎo)致誤刪(如多對多關(guān)系中刪除一個(gè)對象可能級聯(lián)刪除中間表記錄),需謹(jǐn)慎評估;

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論