Átfogó útmutató a Python SQLAlchemy munkamenetkezeléséhez, robusztus tranzakciókezelési technikákkal az adatintegritás és konzisztencia biztosítására alkalmazásaiban.
Python SQLAlchemy Munkamenetkezelés: A Tranzakciókezelés Mesterfogásai az Adatintegritásért
Az SQLAlchemy egy hatékony és rugalmas Python könyvtár, amely átfogó eszköztárat biztosít az adatbázisokkal való interakcióhoz. Az SQLAlchemy szívében a munkamenet fogalma rejlik, amely egyfajta előkészítő területként szolgál az adatbázison végrehajtott összes művelethez. A megfelelő munkamenet- és tranzakciókezelés kulcsfontosságú az adatintegritás fenntartásához és az adatbázis konzisztens viselkedésének biztosításához, különösen összetett, párhuzamos kéréseket kezelő alkalmazásokban.
Az SQLAlchemy Munkamenetek Megértése
Az SQLAlchemy munkamenet egy munkaegységet, egy beszélgetést képvisel az adatbázissal. Nyomon követi az objektumokon végrehajtott változtatásokat, lehetővé téve, hogy egyetlen atomi műveletként rögzítse azokat az adatbázisban. Gondoljon rá úgy, mint egy munkaterületre, ahol módosításokat végez az adatokon, mielőtt hivatalosan mentené azokat. Egy jól menedzselt munkamenet nélkül adatinkonzisztenciákat és potenciális adatkorrupciót kockáztat.
Munkamenet Létrehozása
Mielőtt elkezdhetné az adatbázissal való interakciót, létre kell hoznia egy munkamenetet. Ez magában foglalja az adatbázishoz való kapcsolat létrehozását az SQLAlchemy engine-jének segítségével.
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# Database connection string
db_url = 'sqlite:///:memory:' # Replace with your database URL (e.g., PostgreSQL, MySQL)
# Create an engine
engine = create_engine(db_url, echo=False) # echo=True to see the generated SQL
# Define a base for declarative models
Base = declarative_base()
# Define a simple model
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String)
def __repr__(self):
return f""
# Create the table in the database
Base.metadata.create_all(engine)
# Create a session class
Session = sessionmaker(bind=engine)
# Instantiate a session
session = Session()
Ebben a példában:
- Importáljuk a szükséges SQLAlchemy modulokat.
- Definiálunk egy adatbázis-kapcsolati karakterláncot (`db_url`). Ez a példa egy memóriában lévő SQLite adatbázist használ az egyszerűség kedvéért, de ezt le kell cserélnie az adatbázis-rendszerének megfelelő kapcsolati karakterláncra (pl. PostgreSQL, MySQL). A pontos formátum az adatbázis engine-jétől és illesztőprogramjától függően változik. A helyes kapcsolati karakterlánc formátumát az SQLAlchemy dokumentációjában és az adatbázis-szolgáltatója dokumentációjában találja meg.
- Létrehozunk egy `engine`-t a `create_engine()` segítségével. Az engine felelős a kapcsolatkészlet kezeléséért és az adatbázissal való kommunikációért. Az `echo=True` paraméter hasznos lehet a hibakereséshez, mivel kiírja a generált SQL utasításokat a konzolra.
- Definiálunk egy alaposztályt (`Base`) a `declarative_base()` segítségével. Ez szolgál az összes SQLAlchemy modellünk alaposztályaként.
- Definiálunk egy `User` modellt, amelyet a `users` nevű adatbázis-táblához képezünk le.
- Létrehozzuk a táblát az adatbázisban a `Base.metadata.create_all(engine)` segítségével.
- Létrehozunk egy munkamenet-osztályt a `sessionmaker(bind=engine)` segítségével. Ez konfigurálja a munkamenet-osztályt a megadott engine használatára.
- Végül példányosítunk egy munkamenetet a `Session()` segítségével.
A Tranzakciók Megértése
A tranzakció adatbázis-műveletek sorozata, amelyet egyetlen logikai munkaegységként kezelnek. A tranzakciók betartják az ACID tulajdonságokat:
- Atomicitás: A tranzakcióban lévő összes művelet vagy teljesen sikerül, vagy teljesen meghiúsul. Ha a tranzakció bármely része sikertelen, az egész tranzakció visszavonásra kerül.
- Konzisztencia: A tranzakciónak érvényes állapotban kell tartania az adatbázist. Nem sérthet semmilyen adatbázis-korlátozást vagy szabályt.
- Izoláció: A párhuzamos tranzakciók el vannak szigetelve egymástól. Az egyik tranzakció által végrehajtott változtatások nem láthatók más tranzakciók számára, amíg az első tranzakciót nem véglegesítik.
- Tartósság: Miután egy tranzakciót véglegesítettek, annak változtatásai állandóak, és a rendszerhibákat is túlélik.
Az SQLAlchemy mechanizmusokat biztosít a tranzakciók kezelésére, biztosítva az ACID tulajdonságok fenntartását.
Alapvető Tranzakciókezelés
A leggyakoribb tranzakciós műveletek a véglegesítés és a visszavonás.
Tranzakciók Véglegesítése
Amikor a tranzakción belüli összes művelet sikeresen befejeződött, véglegesíti a tranzakciót. Ez rögzíti a változtatásokat az adatbázisban.
try:
# Add a new user
new_user = User(name='Alice Smith', email='alice.smith@example.com')
session.add(new_user)
# Commit the transaction
session.commit()
print("Transaction committed successfully!")
except Exception as e:
# Handle exceptions
print(f"An error occurred: {e}")
session.rollback()
print("Transaction rolled back.")
finally:
session.close()
Ebben a példában:
- Hozzáadunk egy új `User` objektumot a munkamenethez.
- Meghívjuk a `session.commit()` metódust a változtatások adatbázisba való rögzítéséhez.
- A kódot egy `try...except...finally` blokkba tesszük a lehetséges kivételek kezelésére.
- Ha kivétel történik, meghívjuk a `session.rollback()` metódust a tranzakció során végrehajtott változtatások visszavonására.
- Mindig meghívjuk a `session.close()` metódust a `finally` blokkban a munkamenet felszabadításához és a kapcsolat visszaadásához a kapcsolatkészletnek. Ez létfontosságú az erőforrás-szivárgások elkerüléséhez. A munkamenetek bezárásának elmulasztása a kapcsolatok kimerüléséhez és az alkalmazás instabilitásához vezethet.
Tranzakciók Visszavonása
Ha bármilyen hiba történik egy tranzakció során, vagy ha úgy dönt, hogy a változtatásokat nem szabad véglegesíteni, akkor visszavonja a tranzakciót. Ez visszaállítja az adatbázist a tranzakció megkezdése előtti állapotába.
try:
# Add a user with an invalid email (example to force a rollback)
invalid_user = User(name='Bob Johnson', email='invalid-email')
session.add(invalid_user)
# The commit will fail if the email is not validated on the database level
session.commit()
print("Transaction committed.")
except Exception as e:
print(f"An error occurred: {e}")
session.rollback()
print("Transaction rolled back successfully.")
finally:
session.close()
Ebben a példában, ha az `invalid_user` hozzáadása kivételt vált ki (pl. adatbázis-korlátozás megsértése miatt), a `session.rollback()` hívás visszavonja a sikertelen beillesztést, és az adatbázis változatlan marad.
Haladó Tranzakciókezelés
A `with` utasítás használata a Tranzakció Hatókörének Meghatározására
A tranzakciók kezelésének egy Pythonosabb és robusztusabb módja a `with` utasítás használata. Ez biztosítja, hogy a munkamenet megfelelően lezáródjon, még akkor is, ha kivételek lépnek fel.
from contextlib import contextmanager
@contextmanager
def session_scope():
"""Provide a transactional scope around a series of operations."""
session = Session()
try:
yield session
session.commit()
except Exception:
session.rollback()
raise
finally:
session.close()
# Usage:
with session_scope() as session:
new_user = User(name='Charlie Brown', email='charlie.brown@example.com')
session.add(new_user)
# Operations within the 'with' block
# If no exceptions occur, the transaction is committed automatically.
# If an exception occurs, the transaction is rolled back automatically.
print("User added.")
print("Transaction completed (committed or rolled back).")
A `session_scope` függvény egy kontextuskezelő. Amikor belép a `with` blokkba, új munkamenet jön létre. Amikor kilép a `with` blokkból, a munkamenet vagy véglegesítésre kerül (ha nem történt kivétel), vagy visszavonásra kerül (ha kivétel történt). A munkamenet mindig bezárásra kerül a `finally` blokkban.
Beágyazott Tranzakciók (Mentési Pontok)
Az SQLAlchemy támogatja a beágyazott tranzakciókat mentési pontok használatával. Egy mentési pont lehetővé teszi, hogy egy nagyobb tranzakción belül egy adott pontra vonjon vissza, anélkül, hogy az egész tranzakciót érintené.
try:
with session_scope() as session:
user1 = User(name='David Lee', email='david.lee@example.com')
session.add(user1)
session.flush() # Send changes to the database but don't commit yet
# Create a savepoint
savepoint = session.begin_nested()
try:
user2 = User(name='Eve Wilson', email='eve.wilson@example.com')
session.add(user2)
session.flush()
# Simulate an error
raise ValueError("Simulated error during nested transaction")
except Exception as e:
print(f"Nested transaction error: {e}")
savepoint.rollback()
print("Nested transaction rolled back to savepoint.")
# Continue with the outer transaction, user1 will still be added
user3 = User(name='Frank Miller', email='frank.miller@example.com')
session.add(user3)
except Exception as e:
print(f"Outer transaction error: {e}")
#Commit will commit user1 and user3, but not user2 due to the nested rollback
try:
with session_scope() as session:
#Verify only user1 and user3 exist
users = session.query(User).all()
for user in users:
print(user)
except Exception as e:
print(f"Unexpected Exception: {e}") #Should not happen
Ebben a példában:
- Külső tranzakciót indítunk a `session_scope()` segítségével.
- Hozzáadjuk a `user1`-et a munkamenethez és kiürítjük a változtatásokat az adatbázisba. A `flush()` elküldi a változtatásokat az adatbázis-szervernek, de *nem* véglegesíti azokat. Lehetővé teszi, hogy ellenőrizze, érvényesek-e a változtatások (pl. nincs-e korlátozás megsértés), mielőtt az egész tranzakciót véglegesítené.
- Létrehozunk egy mentési pontot a `session.begin_nested()` segítségével.
- A beágyazott tranzakción belül hozzáadjuk a `user2`-t és szimulálunk egy hibát.
- Visszavonjuk a beágyazott tranzakciót a mentési pontra a `savepoint.rollback()` segítségével. Ez csak a beágyazott tranzakción belül végrehajtott változtatásokat vonja vissza (azaz a `user2` hozzáadását).
- Folytatjuk a külső tranzakciót és hozzáadjuk a `user3`-at.
- A külső tranzakció véglegesítésre kerül, rögzítve a `user1` és `user3` elemeket az adatbázisban, míg a `user2` a mentési pont visszavonása miatt eldobásra kerül.
Izolációs Szintek Szabályozása
Az izolációs szintek határozzák meg, hogy a párhuzamos tranzakciók milyen mértékben vannak elszigetelve egymástól. A magasabb izolációs szintek nagyobb adatintegritást biztosítanak, de csökkenthetik a párhuzamosságot és a teljesítményt. Az SQLAlchemy lehetővé teszi a tranzakciók izolációs szintjének szabályozását.
Gyakori izolációs szintek:
- Read Uncommitted (Nem Véglegesített Olvasás): A legalacsonyabb izolációs szint. A tranzakciók láthatják más tranzakciók nem véglegesített változtatásait. Ez piszkos olvasásokhoz vezethet.
- Read Committed (Véglegesített Olvasás): A tranzakciók csak más tranzakciók véglegesített változtatásait láthatják. Ez megakadályozza a piszkos olvasásokat, de nem ismételhető olvasásokhoz és fantom olvasásokhoz vezethet.
- Repeatable Read (Ismételhető Olvasás): A tranzakciók ugyanazokat az adatokat láthatják a tranzakció során, még akkor is, ha más tranzakciók módosítják azokat. Ez megakadályozza a piszkos olvasásokat és a nem ismételhető olvasásokat, de fantom olvasásokhoz vezethet.
- Serializable (Sorosítható): A legmagasabb izolációs szint. A tranzakciók teljesen el vannak szigetelve egymástól. Ez megakadályozza a piszkos olvasásokat, a nem ismételhető olvasásokat és a fantom olvasásokat, de jelentősen csökkentheti a párhuzamosságot.
Az alapértelmezett izolációs szint az adatbázis-rendszertől függ. Az izolációs szintet beállíthatja az engine létrehozásakor vagy egy tranzakció megkezdésekor.
Példa (PostgreSQL):
from sqlalchemy.dialects.postgresql import dialect
# Set isolation level when creating the engine
engine = create_engine('postgresql://user:password@host:port/database',
connect_args={'options': '-c statement_timeout=1000'} #Example of timeout
)
# Set the isolation level when beginning a transaction (database specific)
# For postgresql, it's recommended to set it on the connection, not engine.
from sqlalchemy import event
from sqlalchemy.pool import Pool
@event.listens_for(Pool, "connect")
def set_isolation_level(dbapi_connection, connection_record):
existing_autocommit = dbapi_connection.autocommit
dbapi_connection.autocommit = True
cursor = dbapi_connection.cursor()
cursor.execute("SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE")
dbapi_connection.autocommit = existing_autocommit
cursor.close()
# Then transactions created via SQLAlchemy will use the configured isolation level.
Fontos: Az izolációs szintek beállításának módja adatbázis-specifikus. A helyes szintaxisért tekintse meg az adatbázis dokumentációját. Az izolációs szintek helytelen beállítása váratlan viselkedéshez vagy hibákhoz vezethet.
Párhuzamosság Kezelése
Amikor több felhasználó vagy folyamat egyszerre fér hozzá ugyanazokhoz az adatokhoz, létfontosságú a párhuzamosság megfelelő kezelése az adatkorrupció megelőzése és az adatintegritás biztosítása érdekében. Az SQLAlchemy számos mechanizmust biztosít a párhuzamosság kezelésére, beleértve az optimista és pesszimista zárolást.
Optimista Zárolás
Az optimista zárolás feltételezi, hogy a konfliktusok ritkák. Ellenőrzi, hogy más tranzakciók végeztek-e módosításokat, mielőtt egy tranzakciót véglegesítene. Ha konfliktust észlel, a tranzakció visszavonásra kerül.
Az optimista zárolás megvalósításához általában hozzáad egy verziószám oszlopot a táblájához. Ez az oszlop automatikusan növelődik minden alkalommal, amikor a sor frissítésre kerül.
from sqlalchemy import Column, Integer, String, Integer
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class Article(Base):
__tablename__ = 'articles'
id = Column(Integer, primary_key=True)
title = Column(String)
content = Column(String)
version = Column(Integer, nullable=False, default=1)
def __repr__(self):
return f""
#Inside of the try catch block
def update_article(session, article_id, new_content):
article = session.query(Article).filter_by(id=article_id).first()
if article is None:
raise ValueError("Article not found")
original_version = article.version
# Update the content and increment the version
article.content = new_content
article.version += 1
# Attempt to update, checking the version column in the WHERE clause
rows_affected = session.query(Article).filter(
Article.id == article_id,
Article.version == original_version
).update({
Article.content: new_content,
Article.version: article.version
}, synchronize_session=False)
if rows_affected == 0:
session.rollback()
raise ValueError("Conflict: Article has been updated by another transaction.")
session.commit()
Ebben a példában:
- Hozzáadunk egy `version` oszlopot az `Article` modellhez.
- Az cikk frissítése előtt eltároljuk az aktuális verziószámot.
- Az `UPDATE` utasításban szerepel egy `WHERE` záradék, amely ellenőrzi, hogy a verziószám oszlop továbbra is megegyezik-e a tárolt verziószámmal. A `synchronize_session=False` megakadályozza, hogy az SQLAlchemy újra betöltse a frissített objektumot; explicit módon kezeljük a verziózást.
- Ha a verziószám oszlopot egy másik tranzakció megváltoztatta, az `UPDATE` utasítás nem fog érinteni egyetlen sort sem (a rows_affected 0 lesz), és kivételt dobunk.
- Visszavonjuk a tranzakciót, és értesítjük a felhasználót, hogy konfliktus történt.
Pesszimista Zárolás
A pesszimista zárolás feltételezi, hogy a konfliktusok valószínűek. Zárat szerez egy sorra vagy táblára, mielőtt módosítaná azt. Ez megakadályozza, hogy más tranzakciók módosítsák az adatokat, amíg a zárat fel nem oldják.
Az SQLAlchemy számos funkciót biztosít zárak megszerzésére, például a `with_for_update()`-t.
# Example using PostgreSQL
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, declarative_base
# Database setup (replace with your actual database URL)
db_url = 'postgresql://user:password@host:port/database'
engine = create_engine(db_url, echo=False) #Set echo to true if you would like to see the SQL generated
Base = declarative_base()
class Item(Base):
__tablename__ = 'items'
id = Column(Integer, primary_key=True)
name = Column(String)
value = Column(Integer)
def __repr__(self):
return f"- "
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
#Function to update the item (within a try/except)
def update_item_value(session, item_id, new_value):
# Acquire a pessimistic lock on the item
item = session.query(Item).filter(Item.id == item_id).with_for_update().first()
if item is None:
raise ValueError("Item not found")
# Update the item's value
item.value = new_value
session.commit()
return True
Ebben a példában:
- A `with_for_update()`-t használjuk egy zár megszerzésére az `Item` soron, mielőtt frissítenénk azt. Ez megakadályozza, hogy más tranzakciók módosítsák a sort, amíg az aktuális tranzakciót nem véglegesítik vagy vissza nem vonják. A `with_for_update()` függvény adatbázis-specifikus; a részletekért tekintse meg az adatbázis dokumentációját. Egyes adatbázisok eltérő zárolási mechanizmusokkal vagy szintaxissal rendelkezhetnek.
Fontos: A pesszimista zárolás csökkentheti a párhuzamosságot és a teljesítményt, ezért csak szükség esetén használja.
Kivételkezelési Bevált Gyakorlatok
A megfelelő kivételkezelés kritikus fontosságú az adatintegritás biztosításához és az alkalmazás összeomlásainak megelőzéséhez. Az adatbázis-műveleteket mindig `try...except` blokkokba kell ágyazni, és a kivételeket megfelelően kell kezelni.
Íme néhány bevált gyakorlat a kivételkezeléshez:
- Specifikus kivételek elkapása: Kerülje az olyan általános kivételek elkapását, mint az `Exception`. Fogjon el specifikus kivételeket, mint például a `sqlalchemy.exc.IntegrityError` vagy a `sqlalchemy.exc.OperationalError`, hogy a különböző hibatípusokat eltérően kezelje.
- Tranzakciók visszavonása: Mindig vonja vissza a tranzakciót, ha kivétel történik.
- Kivételek naplózása: Naplózza a kivételeket a problémák diagnosztizálásához és javításához. Tartalmazzon minél több kontextust a naplókban (pl. felhasználói azonosító, bemeneti adatok, időbélyeg).
- Kivételek újra dobása, ha szükséges: Ha nem tudja kezelni a kivételt, dobja újra, hogy egy magasabb szintű kezelő foglalkozhasson vele.
- Erőforrások felszabadítása: Mindig zárja be a munkamenetet, és szabadítson fel minden más erőforrást egy `finally` blokkban.
import logging
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, declarative_base
from sqlalchemy.exc import IntegrityError, OperationalError
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# Database setup (replace with your actual database URL)
db_url = 'postgresql://user:password@host:port/database'
engine = create_engine(db_url, echo=False)
Base = declarative_base()
class Product(Base):
__tablename__ = 'products'
id = Column(Integer, primary_key=True)
name = Column(String)
price = Column(Integer)
def __repr__(self):
return f""
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
# Function to add a product
def add_product(session, name, price):
try:
new_product = Product(name=name, price=price)
session.add(new_product)
session.commit()
logging.info(f"Product '{name}' added successfully.")
return True
except IntegrityError as e:
session.rollback()
logging.error(f"IntegrityError: {e}")
#Handle database constraint violations (e.g., duplicate name)
return False
except OperationalError as e:
session.rollback()
logging.error(f"OperationalError: {e}")
#Handle connection errors or other operational issues
return False
except Exception as e:
session.rollback()
logging.exception(f"An unexpected error occurred: {e}")
# Handle any other unexpected errors
return False
finally:
session.close()
Ebben a példában:
- Konfiguráljuk a naplózást az események rögzítésére a folyamat során.
- Specifikus kivételeket fogunk el, mint például az `IntegrityError` (korlátozások megsértésére) és az `OperationalError` (kapcsolódási hibákra).
- Visszavonjuk a tranzakciót az `except` blokkokban.
- Naplózzuk a kivételeket a `logging` modul segítségével. A `logging.exception()` metódus automatikusan tartalmazza a stack trace-t a naplóüzenetben.
- Újra dobjuk a kivételt, ha nem tudjuk kezelni.
- Bezárjuk a munkamenetet a `finally` blokkban.
Adatbázis Kapcsolatkészletezés (Connection Pooling)
Az SQLAlchemy kapcsolatkészletezést használ az adatbázis-kapcsolatok hatékony kezelésére. Egy kapcsolatkészlet nyitott kapcsolatok halmazát tartja fenn az adatbázissal, lehetővé téve az alkalmazások számára, hogy új kapcsolatok létrehozása helyett újra felhasználják a meglévőket minden kéréshez. Ez jelentősen javíthatja a teljesítményt, különösen olyan alkalmazásokban, amelyek nagyszámú párhuzamos kérést kezelnek.
Az SQLAlchemy `create_engine()` függvénye automatikusan létrehoz egy kapcsolatkészletet. A kapcsolatkészletet az `create_engine()` függvénynek átadott argumentumokkal konfigurálhatja.
Gyakori kapcsolatkészlet-paraméterek:
- pool_size: A készletben lévő kapcsolatok maximális száma.
- max_overflow: A `pool_size` felett létrehozható kapcsolatok száma.
- pool_recycle: Az a másodpercszám, ami után egy kapcsolat újrahasznosításra kerül.
- pool_timeout: Az az időtartam másodpercben, ameddig várni kell egy elérhető kapcsolatra.
engine = create_engine('postgresql://user:password@host:port/database',
pool_size=5, #Maximum pool size
max_overflow=10, #Maximum overflow
pool_recycle=3600, #Recycle connections after 1 hour
pool_timeout=30
)
Fontos: Válasszon megfelelő kapcsolatkészlet-beállításokat az alkalmazás igényei és az adatbázis-szerver képességei alapján. A rosszul konfigurált kapcsolatkészlet teljesítményproblémákhoz vagy kapcsolatkimerüléshez vezethet.
Aszinkron Tranzakciók (Async SQLAlchemy)
A modern, nagy párhuzamosságot igénylő alkalmazásokhoz, különösen az AsyncIO-hoz hasonló aszinkron keretrendszerekkel (pl. FastAPI) épített alkalmazásokhoz az SQLAlchemy egy aszinkron verziót kínál, az Async SQLAlchemy-t.
Az Async SQLAlchemy az alapvető SQLAlchemy komponensek aszinkron verzióit biztosítja, lehetővé téve adatbázis-műveletek végrehajtását az eseményciklus blokkolása nélkül. Ez jelentősen javíthatja az alkalmazások teljesítményét és skálázhatóságát.
Íme egy alapvető példa az Async SQLAlchemy használatára:
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import declarative_base
from sqlalchemy import Column, Integer, String
import asyncio
# Database setup (replace with your actual database URL)
db_url = 'postgresql+asyncpg://user:password@host:port/database'
engine = create_async_engine(db_url, echo=False)
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String)
def __repr__(self):
return f""
async def create_db_and_tables():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
async def add_user(name, email):
async with AsyncSession(engine) as session:
new_user = User(name=name, email=email)
session.add(new_user)
await session.commit()
async def main():
await create_db_and_tables()
await add_user("Async User", "async.user@example.com")
if __name__ == "__main__":
asyncio.run(main())
Főbb különbségek a szinkron SQLAlchemy-hez képest:
- `create_async_engine` használata `create_engine` helyett.
- `AsyncSession` használata `Session` helyett.
- Minden adatbázis-művelet aszinkron, és `await` kulcsszóval kell várni rájuk.
- Aszinkron adatbázis-illesztőprogramokat (pl. `asyncpg` PostgreSQL esetén) kell használni.
Fontos: Az Async SQLAlchemy olyan adatbázis-illesztőprogramot igényel, amely támogatja az aszinkron műveleteket. Győződjön meg róla, hogy a megfelelő illesztőprogram telepítve és konfigurálva van.
Összefoglalás
Az SQLAlchemy munkamenet- és tranzakciókezelésének elsajátítása elengedhetetlen a robusztus és megbízható, adatbázisokkal kommunikáló Python alkalmazások építéséhez. A munkamenetek, tranzakciók, izolációs szintek és párhuzamosság fogalmainak megértésével, valamint a kivételkezelés és a kapcsolatkészletezés bevált gyakorlatainak betartásával biztosíthatja az adatintegritást és optimalizálhatja alkalmazásai teljesítményét.
Akár egy kis webalkalmazást, akár egy nagyszabású vállalati rendszert épít, az SQLAlchemy biztosítja azokat az eszközöket, amelyekre szüksége van az adatbázis-interakciók hatékony kezeléséhez. Ne feledje, hogy mindig az adatintegritást helyezze előtérbe, és kecsesen kezelje a lehetséges hibákat az alkalmazások megbízhatóságának biztosítása érdekében.
Érdemes megismerkedni olyan haladó témákkal, mint például:
- Kétfázisú véglegesítés (2PC): Több adatbázist érintő tranzakciókhoz.
- Sharding: Adatok elosztására több adatbázis-szerveren.
- Adatbázis migrációk: Olyan eszközök, mint az Alembic használata az adatbázis séma változásainak kezelésére.