SQLAlchemy 2.0 Dokumentation
Dialekte
- PostgreSQL
- MySQL und MariaDB
- SQLite¶
- Unterstützung für die SQLite-Datenbank.
- Datums- und Zeit-Datentypen
- SQLite Auto-Increment-Verhalten
- Datenbanksperrverhalten / Nebenläufigkeit
- Transaktionsisolationsstufe / Autocommit
- INSERT/UPDATE/DELETE…RETURNING
- SAVEPOINT-Unterstützung
- Transaktionales DDL
- Fremdschlüssel-Unterstützung
- ON CONFLICT-Unterstützung für Constraints
- INSERT…ON CONFLICT (Upsert)
- Typ-Reflektion
- Partielle Indizes
- Gepunktete Spaltennamen
- SQLite-spezifische Tabellenoptionen
- Reflektieren interner Schema-Tabellen
- SQLite-Datentypen
- SQLite DML-Konstrukte
- Pysqlite
- DBAPI
- Verbinden
- Treiber
- Verbindungszeichenfolgen
- Regulärer Ausdruck-Unterstützung
- Kompatibilität mit sqlite3 "nativen" Datum- und Zeit-Datentypen
- Threading/Pooling-Verhalten
- Umgang mit gemischten String / Binärspalten
- Serielle Isolation / Savepoints / Transaktionales DDL
- Benutzerdefinierte Funktionen
- Aiosqlite
- Pysqlcipher
- Oracle
- Microsoft SQL Server
Projektversionen
- Vorhergehend: MySQL und MariaDB
- Nächstes: Oracle
- Nach oben: Startseite
- Auf dieser Seite
- SQLite
- Unterstützung für die SQLite-Datenbank.
- Datums- und Zeit-Datentypen
- SQLite Auto-Increment-Verhalten
- Datenbanksperrverhalten / Nebenläufigkeit
- Transaktionsisolationsstufe / Autocommit
- INSERT/UPDATE/DELETE…RETURNING
- SAVEPOINT-Unterstützung
- Transaktionales DDL
- Fremdschlüssel-Unterstützung
- ON CONFLICT-Unterstützung für Constraints
- INSERT…ON CONFLICT (Upsert)
- Typ-Reflektion
- Partielle Indizes
- Gepunktete Spaltennamen
- SQLite-spezifische Tabellenoptionen
- Reflektieren interner Schema-Tabellen
- SQLite-Datentypen
- SQLite DML-Konstrukte
- Pysqlite
- DBAPI
- Verbinden
- Treiber
- Verbindungszeichenfolgen
- Regulärer Ausdruck-Unterstützung
- Kompatibilität mit sqlite3 "nativen" Datum- und Zeit-Datentypen
- Threading/Pooling-Verhalten
- Umgang mit gemischten String / Binärspalten
- Serielle Isolation / Savepoints / Transaktionales DDL
- Benutzerdefinierte Funktionen
- Aiosqlite
- Pysqlcipher
SQLite¶
Unterstützung für die SQLite-Datenbank.
Die folgende Tabelle fasst die aktuellen Support-Level für Datenbank-Release-Versionen zusammen.
Support-Typ |
Versionen |
|---|---|
3.12+ |
|
3.7.16+ |
DBAPI-Unterstützung¶
Die folgenden Dialekt-/DBAPI-Optionen sind verfügbar. Bitte beachten Sie die einzelnen DBAPI-Abschnitte für Verbindungsinformationen.
Datums- und Zeit-Datentypen¶
SQLite hat keine integrierten DATETIME-, TIME- oder DATETIME-Datentypen, und pysqlite bietet keine Out-of-the-Box-Funktionalität für die Übersetzung von Werten zwischen Python datetime-Objekten und einem von SQLite unterstützten Format. Die eigenen DateTime- und verwandten Typen von SQLAlchemy bieten Datumsformatierungs- und Parsing-Funktionalität, wenn SQLite verwendet wird. Die Implementierungsklassen sind DATETIME, DATE und TIME. Diese Typen repräsentieren Daten und Zeiten als ISO-formatierte Strings, die sich auch gut für die Sortierung eignen. Es gibt keine Abhängigkeit von typischen "libc"-Internals für diese Funktionen, sodass historische Daten vollständig unterstützt werden.
Sicherstellung der Text-Affinität¶
Das für diese Typen gerenderte DDL ist die Standardanzeige DATE, TIME und DATETIME. Benutzerdefinierte Speicherformate können jedoch auch auf diese Typen angewendet werden. Wenn das Speicherformat keine Alpha-Zeichen enthält, wird das DDL für diese Typen als DATE_CHAR, TIME_CHAR und DATETIME_CHAR gerendert, sodass die Spalte weiterhin Text-Affinität aufweist.
Siehe auch
Typ-Affinität – in der SQLite-Dokumentation
SQLite Auto-Increment-Verhalten¶
Hintergrundinformationen zu SQLite's Autoincrement finden Sie unter: https://sqlite.org/autoinc.html
Schlüsselkonzepte
SQLite hat eine implizite "Auto-Increment"-Funktion, die für jede nicht-zusammengesetzte Primärschlüsselspalte stattfindet, die speziell mit "INTEGER PRIMARY KEY" für den Typ + Primärschlüssel erstellt wird.
SQLite hat auch ein explizites "AUTOINCREMENT"-Schlüsselwort, das nicht dem impliziten Autoincrement-Feature entspricht; dieses Schlüsselwort wird nicht für den allgemeinen Gebrauch empfohlen. SQLAlchemy rendert dieses Schlüsselwort nicht, es sei denn, es wird eine spezielle SQLite-spezifische Direktive verwendet (siehe unten). Es erfordert jedoch weiterhin, dass der Typ der Spalte "INTEGER" heißt.
Verwendung des AUTOINCREMENT-Schlüsselworts¶
Um das AUTOINCREMENT-Schlüsselwort explizit auf der Primärschlüsselspalte beim Rendern von DDL zu rendern, fügen Sie das Flag sqlite_autoincrement=True zum Table-Konstrukt hinzu
Table(
"sometable",
metadata,
Column("id", Integer, primary_key=True),
sqlite_autoincrement=True,
)Zulassen des Auto-Increment-Verhaltens für SQLAlchemy-Typen außer Integer/INTEGER¶
Das Typsystem von SQLite basiert auf Namenskonventionen. Unter anderem bedeutet dies, dass jeder Typname, der die Teilzeichenfolge "INT" enthält, als "integer affinity" eingestuft wird. Ein Typ namens "BIGINT", "SPECIAL_INT" oder sogar "XYZINTQPR" wird von SQLite als "integer" affinity betrachtet. **Das SQLite-Auto-Increment-Feature, ob implizit oder explizit aktiviert, erfordert jedoch, dass der Name des Spaltentyps exakt die Zeichenfolge "INTEGER" ist.** Wenn eine Anwendung daher einen Typ wie BigInteger für einen Primärschlüssel verwendet, muss dieser Typ auf SQLite als Name "INTEGER" gerendert werden, wenn die anfängliche CREATE TABLE-Anweisung ausgegeben wird, damit das Auto-Increment-Verhalten verfügbar ist.
Ein Ansatz zur Erreichung dieses Ziels ist die Verwendung von Integer auf SQLite nur mit TypeEngine.with_variant()
table = Table(
"my_table",
metadata,
Column(
"id",
BigInteger().with_variant(Integer, "sqlite"),
primary_key=True,
),
)Ein anderer ist die Verwendung einer Unterklasse von BigInteger, die ihren DDL-Namen beim Kompilieren gegen SQLite zu INTEGER überschreibt
from sqlalchemy import BigInteger
from sqlalchemy.ext.compiler import compiles
class SLBigInteger(BigInteger):
pass
@compiles(SLBigInteger, "sqlite")
def bi_c(element, compiler, **kw):
return "INTEGER"
@compiles(SLBigInteger)
def bi_c(element, compiler, **kw):
return compiler.visit_BIGINT(element, **kw)
table = Table(
"my_table", metadata, Column("id", SLBigInteger(), primary_key=True)
)Datenbanksperrverhalten / Nebenläufigkeit¶
SQLite ist nicht für ein hohes Maß an Schreibnebenläufigkeit ausgelegt. Die Datenbank selbst ist als Datei konzipiert und wird während Schreibvorgängen innerhalb von Transaktionen vollständig gesperrt, was bedeutet, dass genau eine "Verbindung" (tatsächlich ein Dateihandle) während dieser Zeit exklusiven Zugriff auf die Datenbank hat – alle anderen "Verbindungen" werden während dieser Zeit blockiert.
Die Python DBAPI-Spezifikation sieht auch ein Verbindungsmodell vor, das sich immer in einer Transaktion befindet; es gibt keine connection.begin()-Methode, nur connection.commit() und connection.rollback(), bei denen sofort eine neue Transaktion begonnen wird. Dies könnte darauf hindeuten, dass der SQLite-Treiber theoretisch nur zu einem Zeitpunkt ein einziges Dateihandle für eine bestimmte Datenbankdatei zulassen würde; es gibt jedoch mehrere Faktoren sowohl innerhalb von SQLite selbst als auch innerhalb des pysqlite-Treibers, die diese Einschränkung erheblich lockern.
Unabhängig von den verwendeten Sperrmodi sperrt SQLite jedoch immer die Datenbankdatei, sobald eine Transaktion gestartet wurde und DML (z. B. INSERT, UPDATE, DELETE) mindestens gesendet wurde, und dies blockiert andere Transaktionen zumindest an dem Punkt, an dem sie ebenfalls versuchen, DML zu senden. Standardmäßig ist die Dauer dieses Blocks sehr kurz, bevor er mit einem Fehler abläuft.
Dieses Verhalten wird kritischer, wenn es in Verbindung mit dem SQLAlchemy ORM verwendet wird. SQLAlchemy's Session-Objekt läuft standardmäßig innerhalb einer Transaktion und kann mit seinem Autoflush-Modell DML vor jeder SELECT-Anweisung ausgeben. Dies kann dazu führen, dass eine SQLite-Datenbank schneller gesperrt wird als erwartet. Der Sperrmodus von SQLite und dem pysqlite-Treiber kann bis zu einem gewissen Grad manipuliert werden, es sollte jedoch beachtet werden, dass die Erreichung eines hohen Grades an Schreibnebenläufigkeit mit SQLite ein verlorener Kampf ist.
Weitere Informationen zur mangelnden Schreibnebenläufigkeit von SQLite per Design finden Sie unter Situationen, in denen ein anderes RDBMS besser funktioniert – Hohe Nebenläufigkeit unten auf der Seite.
Die folgenden Unterabschnitte stellen Bereiche vor, die vom dateibasierten Architektur von SQLite betroffen sind und in der Regel Workarounds erfordern, um bei Verwendung des pysqlite-Treibers zu funktionieren.
Transaktionsisolationsstufe / Autocommit¶
SQLite unterstützt "Transaktionsisolation" auf nicht standardmäßige Weise, auf zwei Achsen. Eine davon ist die PRAGMA read_uncommitted-Anweisung. Diese Einstellung kann SQLite im Wesentlichen zwischen seinem Standardmodus SERIALIZABLE-Isolation und einem "Dirty Read"-Isolationsmodus, der normalerweise als READ UNCOMMITTED bezeichnet wird, umschalten.
SQLAlchemy bindet sich über den Parameter create_engine.isolation_level von create_engine() an diese PRAGMA-Anweisung. Gültige Werte für diesen Parameter bei Verwendung mit SQLite sind "SERIALIZABLE" und "READ UNCOMMITTED", die jeweils einem Wert von 0 und 1 entsprechen. SQLite verwendet standardmäßig SERIALIZABLE, sein Verhalten wird jedoch durch das Standardverhalten des pysqlite-Treibers beeinflusst.
Bei Verwendung des pysqlite-Treibers ist auch die Isolationsstufe "AUTOCOMMIT" verfügbar, die die pysqlite-Verbindung über das Attribut .isolation_level auf der DBAPI-Verbindung ändert und sie für die Dauer der Einstellung auf None setzt.
Neu in Version 1.3.16: Unterstützung für die SQLite AUTOCOMMIT-Isolationsstufe bei Verwendung des pysqlite / sqlite3 SQLite-Treibers hinzugefügt.
Die andere Achse, auf der die Transaktionssperrung von SQLite beeinflusst wird, ist die Art der verwendeten BEGIN-Anweisung. Die drei Varianten sind "deferred", "immediate" und "exclusive", wie unter BEGIN TRANSACTION beschrieben. Eine einfache BEGIN-Anweisung verwendet den Modus "deferred", bei dem die Datenbankdatei erst bei der ersten Lese- oder Schreiboperation gesperrt wird und der Lesezugriff für andere Transaktionen offen bleibt, bis die erste Schreiboperation erfolgt. Aber auch hier ist es wichtig zu beachten, dass der pysqlite-Treiber dieses Verhalten beeinträchtigt, indem er nicht einmal BEGIN emittiert, bis die erste Schreiboperation erfolgt.
Warnung
Der transaktionale Geltungsbereich von SQLite wird durch ungelöste Probleme im pysqlite-Treiber beeinträchtigt, der BEGIN-Anweisungen stärker verzögert, als dies oft praktikabel ist. Siehe die Abschnitte Serielle Isolation / Savepoints / Transaktionales DDL oder Serielle Isolation / Savepoints / Transaktionales DDL (asyncio-Version) für Techniken zur Umgehung dieses Verhaltens.
INSERT/UPDATE/DELETE…RETURNING¶
Der SQLite-Dialekt unterstützt die INSERT|UPDATE|DELETE..RETURNING-Syntax von SQLite 3.35. INSERT..RETURNING kann in einigen Fällen automatisch verwendet werden, um neu generierte Identifikatoren anstelle des traditionellen Ansatzes der Verwendung von cursor.lastrowid abzurufen. Derzeit wird cursor.lastrowid für einfache Einzelausdrucksfälle wegen seiner besseren Leistung immer noch bevorzugt.
Um eine explizite RETURNING-Klausel anzugeben, verwenden Sie die Methode _UpdateBase.returning() auf einer pro-Anweisung-Basis
# INSERT..RETURNING
result = connection.execute(
table.insert().values(name="foo").returning(table.c.col1, table.c.col2)
)
print(result.all())
# UPDATE..RETURNING
result = connection.execute(
table.update()
.where(table.c.name == "foo")
.values(name="bar")
.returning(table.c.col1, table.c.col2)
)
print(result.all())
# DELETE..RETURNING
result = connection.execute(
table.delete()
.where(table.c.name == "foo")
.returning(table.c.col1, table.c.col2)
)
print(result.all())Neu in Version 2.0: Unterstützung für SQLite RETURNING hinzugefügt
SAVEPOINT-Unterstützung¶
SQLite unterstützt SAVEPOINTs, die nur funktionieren, sobald eine Transaktion begonnen wurde. Die SAVEPOINT-Unterstützung von SQLAlchemy ist über die Methode Connection.begin_nested() auf Core-Ebene und Session.begin_nested() auf ORM-Ebene verfügbar. SAVEPOINTs funktionieren jedoch mit pysqlite überhaupt nicht, es sei denn, es werden Workarounds angewendet.
Warnung
Die SAVEPOINT-Funktion von SQLite wird durch ungelöste Probleme in den Treibern pysqlite und aiosqlite beeinträchtigt, die BEGIN-Anweisungen stärker verzögern, als dies oft praktikabel ist. Siehe die Abschnitte Serielle Isolation / Savepoints / Transaktionales DDL und Serielle Isolation / Savepoints / Transaktionales DDL (asyncio-Version) für Techniken zur Umgehung dieses Verhaltens.
Transaktionales DDL¶
Die SQLite-Datenbank unterstützt auch transaktionales DDL. In diesem Fall startet der pysqlite-Treiber nicht nur keine Transaktionen, sondern beendet auch jede bestehende Transaktion, wenn DDL erkannt wird, sodass erneut Workarounds erforderlich sind.
Warnung
Das transaktionale DDL von SQLite wird durch ungelöste Probleme im pysqlite-Treiber beeinträchtigt, der kein BEGIN emittiert und zusätzlich ein COMMIT erzwingt, um jede Transaktion abzubrechen, wenn DDL angetroffen wird. Siehe den Abschnitt Serielle Isolation / Savepoints / Transaktionales DDL für Techniken zur Umgehung dieses Verhaltens.
Fremdschlüssel-Unterstützung¶
SQLite unterstützt die FOREIGN KEY-Syntax beim Erstellen von CREATE-Anweisungen für Tabellen, jedoch haben diese Constraints standardmäßig keine Auswirkungen auf den Betrieb der Tabelle.
Die Constraint-Prüfung auf SQLite hat drei Voraussetzungen
Mindestens Version 3.6.19 von SQLite muss verwendet werden
Die SQLite-Bibliothek muss ohne die Symbole SQLITE_OMIT_FOREIGN_KEY oder SQLITE_OMIT_TRIGGER kompiliert sein.
Die Anweisung
PRAGMA foreign_keys = ONmuss für alle Verbindungen vor der Verwendung gesendet werden – einschließlich des ersten Aufrufs vonMetaData.create_all().
SQLAlchemy ermöglicht das automatische Senden der PRAGMA-Anweisung für neue Verbindungen durch die Verwendung von Events
from sqlalchemy.engine import Engine
from sqlalchemy import event
@event.listens_for(Engine, "connect")
def set_sqlite_pragma(dbapi_connection, connection_record):
cursor = dbapi_connection.cursor()
cursor.execute("PRAGMA foreign_keys=ON")
cursor.close()Warnung
Wenn SQLite-Fremdschlüssel aktiviert sind, ist es nicht möglich, CREATE- oder DROP-Anweisungen für Tabellen mit wechselseitig abhängigen Fremdschlüssel-Constraints auszugeben; um das DDL für diese Tabellen auszugeben, muss ALTER TABLE verwendet werden, um diese Constraints separat zu erstellen oder zu löschen, wofür SQLite keine Unterstützung hat.
Siehe auch
SQLite Foreign Key Support – auf der SQLite-Website.
Events – SQLAlchemy Event API.
- Erstellung/Löschung von Fremdschlüssel-Constraints über ALTER – weitere Informationen zu den Einrichtungen von SQLAlchemy zur Handhabung
wechselseitig abhängiger Fremdschlüssel-Constraints.
ON CONFLICT-Unterstützung für Constraints¶
Siehe auch
Dieser Abschnitt beschreibt die DDL-Version von "ON CONFLICT" für SQLite, die in einer CREATE TABLE-Anweisung auftritt. Für "ON CONFLICT" im Zusammenhang mit einer INSERT-Anweisung siehe INSERT…ON CONFLICT (Upsert).
SQLite unterstützt eine nicht standardmäßige DDL-Klausel namens ON CONFLICT, die auf Primärschlüssel-, UNIQUE-, CHECK- und NOT NULL-Constraints angewendet werden kann. In DDL wird sie entweder innerhalb der "CONSTRAINT"-Klausel oder innerhalb der Spaltendefinition selbst gerendert, abhängig von der Position des Ziel-Constraints. Um diese Klausel in DDL zu rendern, kann der Erweiterungsparameter sqlite_on_conflict mit einem String-Konfliktlösungsalgorithmus innerhalb der Objekte PrimaryKeyConstraint, UniqueConstraint, CheckConstraint angegeben werden. Innerhalb des Objekts Column gibt es individuelle Parameter sqlite_on_conflict_not_null, sqlite_on_conflict_primary_key, sqlite_on_conflict_unique, die jeweils den drei Arten von relevanten Constraints entsprechen, die von einem Column-Objekt angegeben werden können.
Siehe auch
ON CONFLICT – in der SQLite-Dokumentation
Neu in Version 1.3.
Die Parameter sqlite_on_conflict akzeptieren ein String-Argument, das nur der zu wählende Auflösungsname ist, der auf SQLite einer von ROLLBACK, ABORT, FAIL, IGNORE und REPLACE sein kann. Zum Beispiel, um einen UNIQUE-Constraint hinzuzufügen, der den IGNORE-Algorithmus spezifiziert
some_table = Table(
"some_table",
metadata,
Column("id", Integer, primary_key=True),
Column("data", Integer),
UniqueConstraint("id", "data", sqlite_on_conflict="IGNORE"),
)Das obige rendert CREATE TABLE DDL als
CREATE TABLE some_table (
id INTEGER NOT NULL,
data INTEGER,
PRIMARY KEY (id),
UNIQUE (id, data) ON CONFLICT IGNORE
)Bei Verwendung des Flags Column.unique zum Hinzufügen eines UNIQUE-Constraints zu einer einzelnen Spalte kann der Parameter sqlite_on_conflict_unique ebenfalls zum Column hinzugefügt werden, der dann dem UNIQUE-Constraint im DDL hinzugefügt wird
some_table = Table(
"some_table",
metadata,
Column("id", Integer, primary_key=True),
Column(
"data", Integer, unique=True, sqlite_on_conflict_unique="IGNORE"
),
)Rendert
CREATE TABLE some_table (
id INTEGER NOT NULL,
data INTEGER,
PRIMARY KEY (id),
UNIQUE (data) ON CONFLICT IGNORE
)Um den FAIL-Algorithmus für einen NOT NULL-Constraint anzuwenden, wird sqlite_on_conflict_not_null verwendet
some_table = Table(
"some_table",
metadata,
Column("id", Integer, primary_key=True),
Column(
"data", Integer, nullable=False, sqlite_on_conflict_not_null="FAIL"
),
)Dies rendert die Inline-ON-CONFLICT-Phrase der Spalte
CREATE TABLE some_table (
id INTEGER NOT NULL,
data INTEGER NOT NULL ON CONFLICT FAIL,
PRIMARY KEY (id)
)Ebenso für einen Inline-Primärschlüssel verwenden Sie sqlite_on_conflict_primary_key
some_table = Table(
"some_table",
metadata,
Column(
"id",
Integer,
primary_key=True,
sqlite_on_conflict_primary_key="FAIL",
),
)SQLAlchemy rendert den PRIMARY KEY-Constraint separat, sodass der Konfliktlösungsalgorithmus auf den Constraint selbst angewendet wird
CREATE TABLE some_table (
id INTEGER NOT NULL,
PRIMARY KEY (id) ON CONFLICT FAIL
)INSERT…ON CONFLICT (Upsert)¶
Siehe auch
Dieser Abschnitt beschreibt die DML-Version von "ON CONFLICT" für SQLite, die in einer INSERT-Anweisung auftritt. Für "ON CONFLICT" im Zusammenhang mit einer CREATE TABLE-Anweisung siehe ON CONFLICT-Unterstützung für Constraints.
Ab Version 3.24.0 unterstützt SQLite "Upserts" (Update oder Insert) von Zeilen in eine Tabelle über die ON CONFLICT-Klausel der INSERT-Anweisung. Eine Kandidatenzeile wird nur eingefügt, wenn diese Zeile keine UNIQUE- oder Primärschlüssel-Constraints verletzt. Im Falle einer Verletzung eines UNIQUE-Constraints kann eine sekundäre Aktion stattfinden, die entweder "DO UPDATE" (was bedeutet, dass die Daten in der Zielzeile aktualisiert werden sollen) oder "DO NOTHING" (was bedeutet, diese Zeile stillschweigend zu überspringen) ist.
Konflikte werden anhand von Spalten bestimmt, die Teil bestehender UNIQUE-Constraints und Indizes sind. Diese Constraints werden identifiziert, indem die Spalten und Bedingungen angegeben werden, aus denen die Indizes bestehen.
SQLAlchemy bietet Unterstützung für ON CONFLICT über die SQLite-spezifische Funktion insert(), die die generativen Methoden Insert.on_conflict_do_update() und Insert.on_conflict_do_nothing() bereitstellt
>>> from sqlalchemy.dialects.sqlite import insert
>>> insert_stmt = insert(my_table).values(
... id="some_existing_id", data="inserted value"
... )
>>> do_update_stmt = insert_stmt.on_conflict_do_update(
... index_elements=["id"], set_=dict(data="updated value")
... )
>>> print(do_update_stmt)
INSERT INTO my_table (id, data) VALUES (?, ?)
ON CONFLICT (id) DO UPDATE SET data = ?
>>> do_nothing_stmt = insert_stmt.on_conflict_do_nothing(index_elements=["id"])
>>> print(do_nothing_stmt)
INSERT INTO my_table (id, data) VALUES (?, ?)
ON CONFLICT (id) DO NOTHING
Neu in Version 1.4.
Siehe auch
Upsert – in der SQLite-Dokumentation.
Angabe des Ziels¶
Beide Methoden liefern das "Ziel" des Konflikts mittels Spalteninferenz
Das Argument
Insert.on_conflict_do_update.index_elementsspezifiziert eine Sequenz, die String-Spaltennamen,Column-Objekte und/oder SQL-Ausdruckselemente enthält, die einen eindeutigen Index oder einen eindeutigen Constraint identifizieren würden.Bei Verwendung von
Insert.on_conflict_do_update.index_elementszur Inferenz eines Index kann ein partieller Index durch Angabe des ParametersInsert.on_conflict_do_update.index_whereinferiert werden>>> stmt = insert(my_table).values(user_email="a@b.com", data="inserted data") >>> do_update_stmt = stmt.on_conflict_do_update( ... index_elements=[my_table.c.user_email], ... index_where=my_table.c.user_email.like("%@gmail.com"), ... set_=dict(data=stmt.excluded.data), ... ) >>> print(do_update_stmt)
INSERT INTO my_table (data, user_email) VALUES (?, ?) ON CONFLICT (user_email) WHERE user_email LIKE '%@gmail.com' DO UPDATE SET data = excluded.data
Die SET-Klausel¶
ON CONFLICT...DO UPDATE wird verwendet, um eine Aktualisierung der bereits vorhandenen Zeile durchzuführen, wobei jede Kombination aus neuen Werten sowie Werten aus der vorgeschlagenen Einfügung verwendet wird. Diese Werte werden über den Parameter Insert.on_conflict_do_update.set_ angegeben. Dieser Parameter akzeptiert ein Wörterbuch, das direkte Werte für UPDATE enthält
>>> stmt = insert(my_table).values(id="some_id", data="inserted value")
>>> do_update_stmt = stmt.on_conflict_do_update(
... index_elements=["id"], set_=dict(data="updated value")
... )
>>> print(do_update_stmt)
INSERT INTO my_table (id, data) VALUES (?, ?)
ON CONFLICT (id) DO UPDATE SET data = ?
Warnung
Die Methode Insert.on_conflict_do_update() berücksichtigt nicht Python-seitige Standard-UPDATE-Werte oder Generierungsfunktionen, z. B. solche, die mit Column.onupdate angegeben wurden. Diese Werte werden für einen ON CONFLICT-Stil von UPDATE nicht ausgeführt, es sei denn, sie werden manuell im Wörterbuch Insert.on_conflict_do_update.set_ angegeben.
Aktualisierung mit den ausgeschlossenen INSERT-Werten¶
Um auf die vorgeschlagene Einfügezeile zu verweisen, ist der spezielle Alias Insert.excluded als Attribut des Objekts Insert verfügbar; dieses Objekt erstellt ein "excluded."-Präfix für eine Spalte, das DO UPDATE anweist, die Zeile mit dem Wert zu aktualisieren, der eingefügt worden wäre, wenn der Constraint fehlgeschlagen wäre
>>> stmt = insert(my_table).values(
... id="some_id", data="inserted value", author="jlh"
... )
>>> do_update_stmt = stmt.on_conflict_do_update(
... index_elements=["id"],
... set_=dict(data="updated value", author=stmt.excluded.author),
... )
>>> print(do_update_stmt)
INSERT INTO my_table (id, data, author) VALUES (?, ?, ?)
ON CONFLICT (id) DO UPDATE SET data = ?, author = excluded.author
Zusätzliche WHERE-Kriterien¶
Die Methode Insert.on_conflict_do_update() akzeptiert auch eine WHERE-Klausel über den Parameter Insert.on_conflict_do_update.where, der die Zeilen begrenzt, die ein UPDATE erhalten
>>> stmt = insert(my_table).values(
... id="some_id", data="inserted value", author="jlh"
... )
>>> on_update_stmt = stmt.on_conflict_do_update(
... index_elements=["id"],
... set_=dict(data="updated value", author=stmt.excluded.author),
... where=(my_table.c.status == 2),
... )
>>> print(on_update_stmt)
INSERT INTO my_table (id, data, author) VALUES (?, ?, ?)
ON CONFLICT (id) DO UPDATE SET data = ?, author = excluded.author
WHERE my_table.status = ?
Überspringen von Zeilen mit DO NOTHING¶
ON CONFLICT kann verwendet werden, um das Einfügen einer Zeile vollständig zu überspringen, wenn ein Konflikt mit einem UNIQUE-Constraint auftritt; unten ist dies mit der Methode Insert.on_conflict_do_nothing() illustriert
>>> stmt = insert(my_table).values(id="some_id", data="inserted value")
>>> stmt = stmt.on_conflict_do_nothing(index_elements=["id"])
>>> print(stmt)
INSERT INTO my_table (id, data) VALUES (?, ?) ON CONFLICT (id) DO NOTHING
Wenn DO NOTHING ohne Angabe von Spalten oder Constraints verwendet wird, hat dies den Effekt, das Einfügen für jede aufgetretene UNIQUE-Verletzung zu überspringen
>>> stmt = insert(my_table).values(id="some_id", data="inserted value")
>>> stmt = stmt.on_conflict_do_nothing()
>>> print(stmt)
INSERT INTO my_table (id, data) VALUES (?, ?) ON CONFLICT DO NOTHING
Typ-Reflektion¶
SQLite-Typen unterscheiden sich von denen der meisten anderen Datenbank-Backends, da der String-Name des Typs normalerweise nicht eins zu eins einem "Typ" entspricht. Stattdessen verknüpft SQLite das Verhalten der Spaltentypisierung mit einer von fünf sogenannten "Typ-Affinitäten" auf der Grundlage eines Musterabgleichs für den Typ.
Der Reflexionsprozess von SQLAlchemy verwendet beim Überprüfen von Typen eine einfache Nachschlagetabelle, um die zurückgegebenen Schlüsselwörter mit bereitgestellten SQLAlchemy-Typen zu verknüpfen. Diese Nachschlagetabelle ist im SQLite-Dialekt vorhanden, wie auch für alle anderen Dialekte. Der SQLite-Dialekt hat jedoch eine andere "Fallback"-Routine für den Fall, dass ein bestimmter Typname nicht in der Nachschlagetabelle gefunden wird; stattdessen implementiert er das SQLite-"Typ-Affinitäts"-Schema, das unter https://www.sqlite.org/datatype3.html Abschnitt 2.1 zu finden ist.
Die bereitgestellte Typzuordnung erstellt direkte Zuordnungen von einem exakten String-Namensabgleich für die folgenden Typen
BIGINT, BLOB, BOOLEAN, BOOLEAN, CHAR, DATE, DATETIME, FLOAT, DECIMAL, FLOAT, INTEGER, INTEGER, NUMERIC, REAL, SMALLINT, TEXT, TIME, TIMESTAMP, VARCHAR, NVARCHAR, NCHAR
Wenn ein Typname nicht mit einem der obigen Typen übereinstimmt, wird stattdessen die "Typ-Affinitäts"-Suche verwendet
INTEGERwird zurückgegeben, wenn der Typname die ZeichenfolgeINTenthältTEXTwird zurückgegeben, wenn der Typname die ZeichenfolgeCHAR,CLOBoderTEXTenthältNullTypewird zurückgegeben, wenn der Typname die ZeichenfolgeBLOBenthältREALwird zurückgegeben, wenn der Typname die ZeichenfolgeREAL,FLOAoderDOUBenthält.Andernfalls wird der Typ
NUMERICverwendet.
Partielle Indizes¶
Ein partieller Index, z. B. einer, der eine WHERE-Klausel verwendet, kann mit dem DDL-System über das Argument sqlite_where angegeben werden.
tbl = Table("testtbl", m, Column("data", Integer))
idx = Index(
"test_idx1",
tbl.c.data,
sqlite_where=and_(tbl.c.data > 5, tbl.c.data < 10),
)Der Index wird zur Erstellungszeit wie folgt gerendert:
CREATE INDEX test_idx1 ON testtbl (data)
WHERE data > 5 AND data < 10Punktierte Spaltennamen¶
Die Verwendung von Tabellen- oder Spaltennamen, die explizit Punkte enthalten, wird nicht empfohlen. Während dies im Allgemeinen eine schlechte Idee für relationale Datenbanken ist, da der Punkt ein syntaktisch bedeutendes Zeichen ist, hat der SQLite-Treiber bis Version 3.10.0 von SQLite einen Fehler, der erfordert, dass SQLAlchemy diese Punkte in Ergebnisdatensätzen herausfiltert.
Der Fehler, der vollständig außerhalb von SQLAlchemy liegt, kann wie folgt veranschaulicht werden:
import sqlite3
assert sqlite3.sqlite_version_info < (
3,
10,
0,
), "bug is fixed in this version"
conn = sqlite3.connect(":memory:")
cursor = conn.cursor()
cursor.execute("create table x (a integer, b integer)")
cursor.execute("insert into x (a, b) values (1, 1)")
cursor.execute("insert into x (a, b) values (2, 2)")
cursor.execute("select x.a, x.b from x")
assert [c[0] for c in cursor.description] == ["a", "b"]
cursor.execute(
"""
select x.a, x.b from x where a=1
union
select x.a, x.b from x where a=2
"""
)
assert [c[0] for c in cursor.description] == ["a", "b"], [
c[0] for c in cursor.description
]Die zweite Behauptung schlägt fehl.
Traceback (most recent call last):
File "test.py", line 19, in <module>
[c[0] for c in cursor.description]
AssertionError: ['x.a', 'x.b']Wo oben der Treiber fälschlicherweise die Namen der Spalten angibt, einschließlich des Namens der Tabelle, was völlig inkonsistent ist im Vergleich dazu, wenn die UNION nicht vorhanden ist.
SQLAlchemy verlässt sich auf die Vorhersehbarkeit der Spaltennamen bei der Zuordnung zur ursprünglichen Anweisung, sodass das SQLAlchemy-Dialekt keine andere Wahl hat, als diese herauszufiltern.
from sqlalchemy import create_engine
eng = create_engine("sqlite://")
conn = eng.connect()
conn.exec_driver_sql("create table x (a integer, b integer)")
conn.exec_driver_sql("insert into x (a, b) values (1, 1)")
conn.exec_driver_sql("insert into x (a, b) values (2, 2)")
result = conn.exec_driver_sql("select x.a, x.b from x")
assert result.keys() == ["a", "b"]
result = conn.exec_driver_sql(
"""
select x.a, x.b from x where a=1
union
select x.a, x.b from x where a=2
"""
)
assert result.keys() == ["a", "b"]Beachten Sie, dass oben, obwohl SQLAlchemy die Punkte herausfiltert, beide Namen immer noch adressierbar sind.
>>> row = result.first()
>>> row["a"]
1
>>> row["x.a"]
1
>>> row["b"]
1
>>> row["x.b"]
1Daher wirkt sich die von SQLAlchemy angewandte Problemumgehung nur auf CursorResult.keys() und Row.keys() in der öffentlichen API aus. In dem sehr spezifischen Fall, in dem eine Anwendung gezwungen ist, Spaltennamen mit Punkten zu verwenden, und die Funktionalität von CursorResult.keys() und Row.keys() diese punktierten Namen unverändert zurückgeben muss, kann die Ausführungsoption sqlite_raw_colnames bereitgestellt werden, entweder auf pro-Connection-Basis
result = conn.execution_options(sqlite_raw_colnames=True).exec_driver_sql(
"""
select x.a, x.b from x where a=1
union
select x.a, x.b from x where a=2
"""
)
assert result.keys() == ["x.a", "x.b"]oder auf pro-Engine-Basis.
engine = create_engine(
"sqlite://", execution_options={"sqlite_raw_colnames": True}
)Bei Verwendung der Ausführungsoption pro Engine beachten Sie, dass Core- und ORM-Abfragen, die UNION verwenden, möglicherweise nicht ordnungsgemäß funktionieren.
SQLite-spezifische Tabellenoptionen¶
Eine Option für CREATE TABLE wird direkt vom SQLite-Dialekt in Verbindung mit dem Table-Konstrukt unterstützt
WITHOUT ROWID:Table("some_table", metadata, ..., sqlite_with_rowid=False)
STRICT:Table("some_table", metadata, ..., sqlite_strict=True)
Neu in Version 2.0.37.
Siehe auch
Reflektieren interner Schematabellen¶
Reflexionsmethoden, die Tabellenlisten zurückgeben, werden sogenannte „SQLite interne Schemaobjekt“-Namen weglassen, die von SQLite als Objektnamen betrachtet werden, die mit sqlite_ beginnen. Ein Beispiel für ein solches Objekt ist die Tabelle sqlite_sequence, die generiert wird, wenn der Spaltenparameter AUTOINCREMENT verwendet wird. Um diese Objekte zurückzugeben, kann der Parameter sqlite_include_internal=True an Methoden wie MetaData.reflect() oder Inspector.get_table_names() übergeben werden.
Neu in Version 2.0: Der Parameter sqlite_include_internal=True wurde hinzugefügt. Zuvor wurden diese Tabellen von SQLAlchemy-Reflexionsmethoden nicht ignoriert.
Hinweis
Der Parameter sqlite_include_internal bezieht sich nicht auf die „System“-Tabellen, die in Schemata wie sqlite_master vorhanden sind.
Siehe auch
SQLite interne Schemaobjekte – in der SQLite-Dokumentation.
SQLite-Datentypen¶
Wie bei allen SQLAlchemy-Dialekten sind alle Großbuchstaben-Typen, die als gültig für SQLite bekannt sind, von der obersten Ebene des Dialekts importierbar, unabhängig davon, ob sie aus sqlalchemy.types oder aus dem lokalen Dialekt stammen.
from sqlalchemy.dialects.sqlite import (
BLOB,
BOOLEAN,
CHAR,
DATE,
DATETIME,
DECIMAL,
FLOAT,
INTEGER,
NUMERIC,
JSON,
SMALLINT,
TEXT,
TIME,
TIMESTAMP,
VARCHAR,
)| Objektname | Beschreibung |
|---|---|
Repräsentiert ein Python-Datumsobjekt in SQLite mithilfe einer Zeichenfolge. |
|
Repräsentiert ein Python-Datums-/Uhrzeitobjekt in SQLite mithilfe einer Zeichenfolge. |
|
SQLite JSON-Typ. |
|
Repräsentiert ein Python-Zeitobjekt in SQLite mithilfe einer Zeichenfolge. |
- class sqlalchemy.dialects.sqlite.DATETIME¶
Repräsentiert ein Python-Datums-/Uhrzeitobjekt in SQLite mithilfe einer Zeichenfolge.
Das Standardformat für die Speicherung als Zeichenfolge ist
"%(year)04d-%(month)02d-%(day)02d %(hour)02d:%(minute)02d:%(second)02d.%(microsecond)06d"
z. B.
2021-03-15 12:05:57.105542
Das eingehende Speicherformat wird standardmäßig mithilfe der Python-Funktion
datetime.fromisoformat()analysiert.Geändert in Version 2.0:
datetime.fromisoformat()wird für die standardmäßige Analyse von Datums-/Uhrzeitzeichenfolgen verwendet.Das Speicherformat kann bis zu einem gewissen Grad mithilfe der Parameter
storage_formatundregexpangepasst werden, wie z. B.:import re from sqlalchemy.dialects.sqlite import DATETIME dt = DATETIME( storage_format=( "%(year)04d/%(month)02d/%(day)02d %(hour)02d:%(minute)02d:%(second)02d" ), regexp=r"(\d+)/(\d+)/(\d+) (\d+)-(\d+)-(\d+)", )
- Parameter:
storage_format¶ – Formatzeichenfolge, die auf das Wörterbuch mit den Schlüsseln Jahr, Monat, Tag, Stunde, Minute, Sekunde und Mikrosekunde angewendet wird.
regexp¶ – Regulärer Ausdruck, der auf eingehende Ergebniszeilen angewendet wird und die Verwendung von
datetime.fromisoformat()zur Analyse eingehender Zeichenfolgen ersetzt. Wenn der reguläre Ausdruck benannte Gruppen enthält, wird das resultierende Trefferwörterbuch als Schlüsselwortargumente an den Pythondatetime()-Konstruktor übergeben. Andernfalls, wenn Positionsgruppen verwendet werden, wird derdatetime()-Konstruktor mit Positionsargumenten über*map(int, match_obj.groups(0))aufgerufen.
Klassensignatur
class
sqlalchemy.dialects.sqlite.DATETIME(sqlalchemy.dialects.sqlite.base._DateTimeMixin,sqlalchemy.types.DateTime)
- class sqlalchemy.dialects.sqlite.DATE¶
Repräsentiert ein Python-Datumsobjekt in SQLite mithilfe einer Zeichenfolge.
Das Standardformat für die Speicherung als Zeichenfolge ist
"%(year)04d-%(month)02d-%(day)02d"
z. B.
2011-03-15
Das eingehende Speicherformat wird standardmäßig mithilfe der Python-Funktion
date.fromisoformat()analysiert.Geändert in Version 2.0:
date.fromisoformat()wird für die standardmäßige Analyse von Datumszeichenfolgen verwendet.Das Speicherformat kann bis zu einem gewissen Grad mithilfe der Parameter
storage_formatundregexpangepasst werden, wie z. B.:import re from sqlalchemy.dialects.sqlite import DATE d = DATE( storage_format="%(month)02d/%(day)02d/%(year)04d", regexp=re.compile("(?P<month>\d+)/(?P<day>\d+)/(?P<year>\d+)"), )
- Parameter:
storage_format¶ – Formatzeichenfolge, die auf das Wörterbuch mit den Schlüsseln Jahr, Monat und Tag angewendet wird.
regexp¶ – Regulärer Ausdruck, der auf eingehende Ergebniszeilen angewendet wird und die Verwendung von
date.fromisoformat()zur Analyse eingehender Zeichenfolgen ersetzt. Wenn der reguläre Ausdruck benannte Gruppen enthält, wird das resultierende Trefferwörterbuch als Schlüsselwortargumente an den Pythondate()-Konstruktor übergeben. Andernfalls, wenn Positionsgruppen verwendet werden, wird derdate()-Konstruktor mit Positionsargumenten über*map(int, match_obj.groups(0))aufgerufen.
Klassensignatur
class
sqlalchemy.dialects.sqlite.DATE(sqlalchemy.dialects.sqlite.base._DateTimeMixin,sqlalchemy.types.Date)
- class sqlalchemy.dialects.sqlite.JSON¶
SQLite JSON-Typ.
SQLite unterstützt JSON ab Version 3.9 über seine JSON1-Erweiterung. Beachten Sie, dass JSON1 eine ladbare Erweiterung ist und daher möglicherweise nicht verfügbar ist oder zur Laufzeit geladen werden muss.
Wenn der Basistyp
JSONgegen ein SQLite-Backend verwendet wird, wird automatischJSONverwendet.Siehe auch
JSON- Hauptdokumentation für den generischen plattformübergreifenden JSON-Datentyp.Der Typ
JSONunterstützt die Persistenz von JSON-Werten sowie die Kernindexoperationen, die vom DatentypJSONbereitgestellt werden, indem die Operationen so angepasst werden, dass die FunktionJSON_EXTRACT, die in die FunktionJSON_QUOTEeingekapselt ist, auf Datenbankebene gerendert wird. Extrahierte Werte werden in Anführungszeichen gesetzt, um sicherzustellen, dass die Ergebnisse immer JSON-Zeichenfolgenwerte sind.Neu in Version 1.3.
Mitglieder
Klassensignatur
class
sqlalchemy.dialects.sqlite.JSON(sqlalchemy.types.JSON)-
method
sqlalchemy.dialects.sqlite.JSON.__init__(none_as_null: bool = False)¶ geerbt von der
sqlalchemy.types.JSON.__init__Methode vonJSONErstellt einen
JSON-Typ.- Parameter:
none_as_null=False¶ –
Wenn True, wird der Wert
Noneals SQL NULL-Wert persistiert, nicht als JSON-Kodierung vonnull. Beachten Sie, dass bei False dienull()-Konstruktion immer noch verwendet werden kann, um einen NULL-Wert zu persistieren, der direkt als Parameterwert übergeben werden kann, der vomJSON-Typ als SQL NULL speziell interpretiert wird.from sqlalchemy import null conn.execute(table.insert(), {"data": null()})
Hinweis
JSON.none_as_nullgilt nicht für die Werte, die anColumn.defaultundColumn.server_defaultübergeben werden; ein Wert vonNone, der für diese Parameter übergeben wird, bedeutet „kein Standard vorhanden“.Zusätzlich gilt bei Verwendung in SQL-Vergleichsausdrücken der Python-Wert
Noneweiterhin für SQL null und nicht für JSON NULL. Der WertJSON.NULLsollte für SQL-Ausdrücke verwendet werden, die mit JSON null verglichen werden sollen. Das FlagJSON.none_as_nullbezieht sich ausdrücklich auf die Persistenz des Werts in einer INSERT- oder UPDATE-Anweisung.Siehe auch
-
method
- class sqlalchemy.dialects.sqlite.TIME¶
Repräsentiert ein Python-Zeitobjekt in SQLite mithilfe einer Zeichenfolge.
Das Standardformat für die Speicherung als Zeichenfolge ist
"%(hour)02d:%(minute)02d:%(second)02d.%(microsecond)06d"
z. B.
12:05:57.10558
Das eingehende Speicherformat wird standardmäßig mithilfe der Python-Funktion
time.fromisoformat()analysiert.Geändert in Version 2.0:
time.fromisoformat()wird für die standardmäßige Analyse von Zeitzeichenfolgen verwendet.Das Speicherformat kann bis zu einem gewissen Grad mithilfe der Parameter
storage_formatundregexpangepasst werden, wie z. B.:import re from sqlalchemy.dialects.sqlite import TIME t = TIME( storage_format="%(hour)02d-%(minute)02d-%(second)02d-%(microsecond)06d", regexp=re.compile("(\d+)-(\d+)-(\d+)-(?:-(\d+))?"), )
- Parameter:
storage_format¶ – Formatzeichenfolge, die auf das Wörterbuch mit den Schlüsseln Stunde, Minute, Sekunde und Mikrosekunde angewendet wird.
regexp¶ – Regulärer Ausdruck, der auf eingehende Ergebniszeilen angewendet wird und die Verwendung von
datetime.fromisoformat()zur Analyse eingehender Zeichenfolgen ersetzt. Wenn der reguläre Ausdruck benannte Gruppen enthält, wird das resultierende Trefferwörterbuch als Schlüsselwortargumente an den Pythontime()-Konstruktor übergeben. Andernfalls, wenn Positionsgruppen verwendet werden, wird dertime()-Konstruktor mit Positionsargumenten über*map(int, match_obj.groups(0))aufgerufen.
Klassensignatur
class
sqlalchemy.dialects.sqlite.TIME(sqlalchemy.dialects.sqlite.base._DateTimeMixin,sqlalchemy.types.Time)
SQLite DML-Konstrukte¶
| Objektname | Beschreibung |
|---|---|
insert(table) |
Konstruiert eine |
SQLite-spezifische Implementierung von INSERT. |
- function sqlalchemy.dialects.sqlite.insert(table: _DMLTableArgument) → Insert¶
Konstruiert eine
Insert-Konstruktion, die spezifisch für SQLite ist.Die Funktion
sqlalchemy.dialects.sqlite.insert()erstellt einsqlalchemy.dialects.sqlite.Insert. Diese Klasse basiert auf der Dialekt-unabhängigenInsert-Konstruktion, die mit der Funktioninsert()in SQLAlchemy Core konstruiert werden kann.Die
Insert-Konstruktion enthält zusätzliche MethodenInsert.on_conflict_do_update(),Insert.on_conflict_do_nothing().
- class sqlalchemy.dialects.sqlite.Insert¶
SQLite-spezifische Implementierung von INSERT.
Fügt Methoden für SQLite-spezifische Syntaxen wie ON CONFLICT hinzu.
Das Objekt
Insertwird mit der Funktionsqlalchemy.dialects.sqlite.insert()erstellt.Neu in Version 1.4.
Siehe auch
Mitglieder
excluded, inherit_cache, on_conflict_do_nothing(), on_conflict_do_update()
Klassensignatur
class
sqlalchemy.dialects.sqlite.Insert(sqlalchemy.sql.expression.Insert)-
attribute
sqlalchemy.dialects.sqlite.Insert.excluded¶ Stellt den
excluded-Namensraum für eine ON CONFLICT-Anweisung bereit.Die ON CONFLICT-Klausel von SQLite erlaubt den Verweis auf die einzufügende Zeile, bekannt als
excluded. Dieses Attribut stellt alle Spalten dieser Zeile zur Verfügung, auf die verwiesen werden kann.Tipp
Das Attribut
Insert.excludedist eine Instanz vonColumnCollection, die eine Schnittstelle bietet, die der derTable.c-Sammlung entspricht, die unter Zugriff auf Tabellen und Spalten beschrieben ist. Mit dieser Sammlung sind normale Namen wie Attribute zugänglich (z. B.stmt.excluded.some_column), aber spezielle Namen und Wörterbuchmethodennamen sollten über den indexierten Zugriff zugegriffen werden, wie z. B.stmt.excluded["column name"]oderstmt.excluded["values"]. Weitere Beispiele finden Sie in der Docstring vonColumnCollection.
-
attribute
sqlalchemy.dialects.sqlite.Insert.inherit_cache: bool | None = False¶ Gibt an, ob diese
HasCacheKey-Instanz das Cache-Schlüssel-Generierungsschema ihrer direkten Oberklasse verwenden soll.Das Attribut hat standardmäßig den Wert
None, was bedeutet, dass ein Konstrukt noch nicht berücksichtigt hat, ob es für die Teilnahme an der Caching-Mechanik geeignet ist. Dies ist funktional äquivalent zum Setzen des Wertes aufFalse, außer dass auch eine Warnung ausgegeben wird.Dieses Flag kann auf
Truefür eine bestimmte Klasse gesetzt werden, wenn die SQL, die diesem Objekt entspricht, nicht auf Basis von Attributen geändert wird, die lokal zu dieser Klasse und nicht zu ihrer Oberklasse gehören.Siehe auch
Unterstützung für Caching für benutzerdefinierte Konstrukte aktivieren - Allgemeine Richtlinien für die Einstellung des Attributs
HasCacheKey.inherit_cachefür SQL-Konstrukte von Drittanbietern oder benutzerdefinierte SQL-Konstrukte.
-
method
sqlalchemy.dialects.sqlite.Insert.on_conflict_do_nothing(index_elements: Iterable[Column[Any] | str | DDLConstraintColumnRole] | None = None, index_where: WhereHavingRole | None = None) → Self¶ Gibt eine DO NOTHING-Aktion für die ON CONFLICT-Klausel an.
- Parameter:
index_elements¶ – Eine Sequenz, die aus Zeichenfolgen-Spaltennamen,
Column-Objekten oder anderen Spaltenausdrucksobjekten besteht, die zur Ableitung eines Zielindex oder einer eindeutigen Einschränkung verwendet werden.index_where¶ – Zusätzliches WHERE-Kriterium, das zur Ableitung eines bedingten Zielindex verwendet werden kann.
-
method
sqlalchemy.dialects.sqlite.Insert.on_conflict_do_update(index_elements: Iterable[Column[Any] | str | DDLConstraintColumnRole] | None = None, index_where: WhereHavingRole | None = None, set_: Mapping[Any, Any] | ColumnCollection[Any, Any] | None = None, where: WhereHavingRole | None = None) → Self¶ Gibt eine DO UPDATE SET-Aktion für die ON CONFLICT-Klausel an.
- Parameter:
index_elements¶ – Eine Sequenz, die aus Zeichenfolgen-Spaltennamen,
Column-Objekten oder anderen Spaltenausdrucksobjekten besteht, die zur Ableitung eines Zielindex oder einer eindeutigen Einschränkung verwendet werden.index_where¶ – Zusätzliches WHERE-Kriterium, das zur Ableitung eines bedingten Zielindex verwendet werden kann.
set_¶ –
Ein Wörterbuch oder ein anderes Mapping-Objekt, bei dem die Schlüssel entweder Namen von Spalten in der Zieltabelle oder
Column-Objekte oder andere ORM-gemappte Spalten, die mit denen der Zieltabelle übereinstimmen, sowie Ausdrücke oder Literale als Werte sind, die die auszuführendenSET-Aktionen angeben.Neu in Version 1.4: Der Parameter
Insert.on_conflict_do_update.set_unterstütztColumn-Objekte aus der ZielTableals Schlüssel.Warnung
Dieses Wörterbuch berücksichtigt keine Python-seitig angegebenen Standard-UPDATE-Werte oder Generierungsfunktionen, z. B. solche, die mithilfe von
Column.onupdateangegeben wurden. Diese Werte werden für einen ON CONFLICT-Stil von UPDATE nicht verwendet, es sei denn, sie werden manuell im WörterbuchInsert.on_conflict_do_update.set_angegeben.where¶ – Optionales Argument. Ein Ausdrucksobjekt, das eine
WHERE-Klausel darstellt, die die vonDO UPDATE SETbetroffenen Zeilen einschränkt. Zeilen, die dieWHERE-Bedingung nicht erfüllen, werden nicht aktualisiert (effektiv einDO NOTHINGfür diese Zeilen).
-
attribute
Pysqlite¶
Unterstützung für die SQLite-Datenbank über den pysqlite-Treiber.
Beachten Sie, dass pysqlite derselbe Treiber ist wie das Modul sqlite3, das in der Python-Distribution enthalten ist.
DBAPI¶
Dokumentation und Download-Informationen (falls zutreffend) für pysqlite sind verfügbar unter: https://docs.pythonlang.de/library/sqlite3.html
Verbindung¶
Verbindungszeichenfolge
sqlite+pysqlite:///file_pathTreiber¶
Die Python-DBAPI sqlite3 ist in allen modernen Python-Versionen Standard; für cPython und Pypy ist keine zusätzliche Installation erforderlich.
Verbindungszeichenfolgen¶
Die Dateispezifikation für die SQLite-Datenbank wird als „Datenbank“-Teil der URL übernommen. Beachten Sie, dass das Format einer SQLAlchemy-URL ist:
driver://user:pass@host/databaseDas bedeutet, dass der eigentliche Dateiname, der verwendet werden soll, mit den Zeichen rechts vom dritten Schrägstrich beginnt. Das Verbinden mit einem relativen Dateipfad sieht also so aus:
# relative path
e = create_engine("sqlite:///path/to/database.db")Ein absoluter Pfad, der durch einen vorangestellten Schrägstrich gekennzeichnet ist, bedeutet, dass Sie vier Schrägstriche benötigen:
# absolute path
e = create_engine("sqlite:////path/to/database.db")Bei Verwendung eines Windows-Pfads können reguläre Laufwerksspezifikationen und Backslashes verwendet werden. Wahrscheinlich werden doppelte Backslashes benötigt:
# absolute path on Windows
e = create_engine("sqlite:///C:\\path\\to\\database.db")Um eine SQLite-Datenbank vom Typ :memory: zu verwenden, geben Sie sie als Dateinamen mit sqlite:///:memory: an. Dies ist auch der Standard, wenn kein Dateipfad vorhanden ist und nur sqlite:// angegeben wird und nichts weiter.
# in-memory database (note three slashes)
e = create_engine("sqlite:///:memory:")
# also in-memory database
e2 = create_engine("sqlite://")URI-Verbindungen¶
Moderne Versionen von SQLite unterstützen ein alternatives System zum Verbinden über eine URI auf Treiber-Ebene, was den Vorteil hat, dass zusätzliche Argumente auf Treiber-Ebene übergeben werden können, einschließlich Optionen wie „read only“. Der Python-Treiber sqlite3 unterstützt diesen Modus unter modernen Python 3-Versionen. Der SQLAlchemy pysqlite-Treiber unterstützt diesen Verwendungsmodus, indem „uri=true“ in der Abfragezeichenfolge der URL angegeben wird. Die SQLite-Ebene „URI“ wird als „database“-Teil der SQLAlchemy-URL beibehalten (d. h. nach einem Schrägstrich).
e = create_engine("sqlite:///file:path/to/database?mode=ro&uri=true")Hinweis
Der Parameter „uri=true“ muss in der Abfragezeichenfolge der URL erscheinen. Er funktioniert derzeit nicht wie erwartet, wenn er nur im create_engine.connect_args-Parameter-Dictionary enthalten ist.
Die Logik gleicht die gleichzeitige Anwesenheit von SQLAlchemy's Abfragezeichenfolge und SQLite's Abfragezeichenfolge aus, indem sie die Parameter, die zum Python sqlite3-Treiber gehören, von denen trennt, die zur SQLite-URI gehören. Dies wird durch die Verwendung einer festen Liste von Parametern erreicht, die bekanntermaßen vom Python-Teil des Treibers akzeptiert werden. Um beispielsweise eine URL einzuschließen, die die Python sqlite3-Parameter „timeout“ und „check_same_thread“ sowie die SQLite-Parameter „mode“ und „nolock“ angibt, können diese alle zusammen in der Abfragezeichenfolge übergeben werden.
e = create_engine(
"sqlite:///file:path/to/database?"
"check_same_thread=true&timeout=10&mode=ro&nolock=1&uri=true"
)Oben werden die pysqlite / sqlite3 DBAPI-Argumente wie folgt übergeben
sqlite3.connect(
"file:path/to/database?mode=ro&nolock=1",
check_same_thread=True,
timeout=10,
uri=True,
)Bezüglich zukünftiger Parameter, die entweder zu den Python- oder nativen Treibern hinzugefügt werden. Neue Parameternamen, die zum SQLite-URI-Schema hinzugefügt werden, sollten von diesem Schema automatisch übernommen werden. Neue Parameternamen, die zur Python-Treiberseite hinzugefügt werden, können durch Angabe im create_engine.connect_args-Dictionary übernommen werden, bis die Dialektunterstützung von SQLAlchemy hinzugefügt wird. Für den unwahrscheinlichen Fall, dass der native SQLite-Treiber einen neuen Parameternamen hinzufügt, der mit einem der vorhandenen, bekannten Python-Treiberparameter (wie z. B. „timeout“) überlappt, müsste der SQLAlchemy-Dialekt für das URL-Schema angepasst werden, um dies weiterhin zu unterstützen.
Wie immer bei allen SQLAlchemy-Dialekten kann der gesamte „URL“-Prozess in create_engine() über den create_engine.creator-Parameter umgangen werden, der einen benutzerdefinierten Aufruf ermöglicht, der direkt eine Python sqlite3-Treiberverbindung erstellt.
Neu in Version 1.3.9.
Siehe auch
Uniform Resource Identifiers – in der SQLite-Dokumentation
Unterstützung für reguläre Ausdrücke¶
Neu in Version 1.4.
Die Unterstützung für den Operator ColumnOperators.regexp_match() wird mithilfe der Funktion re.search von Python bereitgestellt. SQLite selbst enthält keinen funktionierenden Operator für reguläre Ausdrücke; stattdessen enthält es einen nicht implementierten Platzhalteroperator REGEXP, der eine benutzerdefinierte Funktion aufruft, die bereitgestellt werden muss.
Die Implementierung von SQLAlchemy nutzt den pysqlite-Hook create_function wie folgt
def regexp(a, b):
return re.search(a, b) is not None
sqlite_connection.create_function(
"regexp",
2,
regexp,
)Derzeit gibt es keine Unterstützung für Flags für reguläre Ausdrücke als separates Argument, da diese vom REGEXP-Operator von SQLite nicht unterstützt werden. Sie können jedoch inline in den regulären Ausdruck eingefügt werden. Weitere Informationen finden Sie unter Python-Reguläre Ausdrücke.
Siehe auch
Python-Reguläre Ausdrücke: Dokumentation zur Syntax von Python-Regulären Ausdrücken.
Kompatibilität mit den nativen Datum- und Zeitstempeltypen von sqlite3¶
Der pysqlite-Treiber enthält die Optionen sqlite3.PARSE_DECLTYPES und sqlite3.PARSE_COLNAMES, die dazu führen, dass jede Spalte oder jeder Ausdruck, der explizit als „date“ oder „timestamp“ bezeichnet wird, in ein Python-Datum- oder -Zeitstempelobjekt konvertiert wird. Die vom pysqlite-Dialekt bereitgestellten Datums- und Zeitstempeltypen sind mit diesen Optionen derzeit nicht kompatibel, da sie das ISO-Datum/-Zeitstempel einschließlich Mikrosekunden rendern, was der pysqlite-Treiber nicht tut. Darüber hinaus rendert SQLAlchemy derzeit nicht automatisch die „cast“-Syntax, die für die eigenständigen Funktionen „current_timestamp“ und „current_date“ erforderlich ist, um nativ Datetime-/Datums-Typen zurückzugeben. Leider stellt pysqlite die Standard-DBAPI-Typen in cursor.description nicht bereit, sodass SQLAlchemy keine Möglichkeit hat, diese Typen im laufenden Betrieb ohne aufwändige Typenprüfungen pro Zeile zu erkennen.
Unter Berücksichtigung, dass die Parsing-Option von pysqlite nicht empfohlen wird und auch nicht notwendig sein sollte, wenn sie mit SQLAlchemy verwendet wird, kann die Verwendung von PARSE_DECLTYPES erzwungen werden, wenn man „native_datetime=True“ auf create_engine() konfiguriert.
engine = create_engine(
"sqlite://",
connect_args={
"detect_types": sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES
},
native_datetime=True,
)Mit dieser aktivierten Flagge führen die Datentypen DATE und TIMESTAMP (aber Achtung – nicht DATETIME oder TIME… schon verwirrt?) keine Bindungsparameter oder Ergebnisverarbeitung durch. Die Ausführung von „func.current_date()“ gibt einen String zurück. „func.current_timestamp()“ ist als Rückgabe eines DATETIME-Typs in SQLAlchemy registriert, sodass diese Funktion weiterhin eine Ergebnisverarbeitung auf SQLAlchemy-Ebene erhält.
Threading/Pooling-Verhalten¶
Die sqlite3 DBAPI verbietet standardmäßig die Verwendung einer bestimmten Verbindung in einem Thread, der nicht derjenige ist, in dem sie erstellt wurde. Da SQLite weiterentwickelt wurde, hat sich sein Verhalten unter mehreren Threads verbessert und beinhaltet sogar Optionen für speicherinterne Datenbanken, die in mehreren Threads verwendet werden können.
Das Thread-Verbot ist als „check same thread“ bekannt und kann mit dem sqlite3-Parameter check_same_thread gesteuert werden, der diese Prüfung deaktiviert oder aktiviert. Das Standardverhalten von SQLAlchemy ist hier, check_same_thread automatisch auf False zu setzen, sobald eine datenbankbasierte Datenbank verwendet wird, um die Kompatibilität mit der Standard-Poolklasse QueuePool herzustellen.
Der SQLAlchemy pysqlite DBAPI richtet den Verbindungs-Pool je nach Art der angeforderten SQLite-Datenbank unterschiedlich ein.
Wenn eine SQLite-Datenbank vom Typ
:memory:angegeben wird, verwendet der Dialekt standardmäßigSingletonThreadPool. Dieser Pool verwaltet eine einzige Verbindung pro Thread, sodass alle Zugriffe auf die Engine innerhalb des aktuellen Threads dieselbe:memory:-Datenbank verwenden – andere Threads greifen auf eine andere:memory:-Datenbank zu. Der Parametercheck_same_threadist standardmäßig aufTruegesetzt.Wenn eine datenbankbasierte Datenbank angegeben wird, verwendet der Dialekt
QueuePoolals Quelle für Verbindungen. Gleichzeitig ist die Flaggecheck_same_threadstandardmäßig auf False gesetzt, sofern nicht überschrieben.Geändert in Version 2.0: SQLite-Datenbank-Engines verwenden jetzt standardmäßig
QueuePool. Zuvor wurdeNullPoolverwendet. Die KlasseNullPoolkann durch Angabe über den Parametercreate_engine.poolclassverwendet werden.
Deaktivierung des Verbindungs-Poolings für Dateidatenbanken¶
Das Pooling kann für eine datenbankbasierte Datei deaktiviert werden, indem die Implementierung von NullPool für den Parameter poolclass() angegeben wird.
from sqlalchemy import NullPool
engine = create_engine("sqlite:///myfile.db", poolclass=NullPool)Es wurde beobachtet, dass die Implementierung von NullPool einen extrem geringen Leistungs-Overhead für wiederholte Abrufe aufgrund des fehlenden Verbindungs-Wiederverwendung durch QueuePool aufweist. Es kann jedoch dennoch vorteilhaft sein, diese Klasse zu verwenden, wenn die Anwendung Probleme mit gesperrten Dateien hat.
Verwendung einer In-Memory-Datenbank in mehreren Threads¶
Um eine :memory:-Datenbank in einem Multithread-Szenario zu verwenden, muss dasselbe Verbindungsobjekt zwischen den Threads geteilt werden, da die Datenbank nur im Gültigkeitsbereich dieser Verbindung existiert. Die Implementierung von StaticPool verwaltet eine einzige Verbindung global, und die Flagge check_same_thread kann als False an Pysqlite übergeben werden.
from sqlalchemy.pool import StaticPool
engine = create_engine(
"sqlite://",
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)Beachten Sie, dass die Verwendung einer :memory:-Datenbank in mehreren Threads eine aktuelle SQLite-Version erfordert.
Verwendung von temporären Tabellen mit SQLite¶
Aufgrund der Art und Weise, wie SQLite temporäre Tabellen behandelt, muss für die Verwendung einer temporären Tabelle in einer datenbankbasierten SQLite-Datei über mehrere Abrufe aus dem Verbindungs-Pool, wie z. B. bei der Verwendung einer ORM Session, bei der die temporäre Tabelle auch nach Aufruf von Session.commit() oder Session.rollback() bestehen bleiben soll, ein Pool verwendet werden, der eine einzelne Verbindung verwaltet. Verwenden Sie SingletonThreadPool, wenn der Gültigkeitsbereich nur innerhalb des aktuellen Threads benötigt wird, oder StaticPool, wenn der Gültigkeitsbereich für diesen Fall für mehrere Threads benötigt wird.
# maintain the same connection per thread
from sqlalchemy.pool import SingletonThreadPool
engine = create_engine("sqlite:///mydb.db", poolclass=SingletonThreadPool)
# maintain the same connection across all threads
from sqlalchemy.pool import StaticPool
engine = create_engine("sqlite:///mydb.db", poolclass=StaticPool)Beachten Sie, dass SingletonThreadPool für die Anzahl der zu verwendenden Threads konfiguriert werden sollte; darüber hinaus werden Verbindungen auf nicht deterministische Weise geschlossen.
Umgang mit gemischten String-/Binärspalten¶
Die SQLite-Datenbank ist schwach typisiert, und daher ist es möglich, dass bei Verwendung von Binärwerten, die in Python als b'some string' dargestellt werden, eine bestimmte SQLite-Datenbank Datenwerte innerhalb verschiedener Zeilen enthält, von denen einige als b''-Wert vom Pysqlite-Treiber zurückgegeben werden und andere als Python-Strings, z. B. ''-Werte. Dieses Problem tritt bekanntermaßen nicht auf, wenn der LargeBinary-Datentyp von SQLAlchemy konsequent verwendet wird. Wenn jedoch eine bestimmte SQLite-Datenbank Daten enthält, die mit dem Pysqlite-Treiber direkt eingefügt wurden, oder wenn der String-Typ von SQLAlchemy verwendet wurde, der später zu LargeBinary geändert wurde, ist die Tabelle nicht konsistent lesbar, da der LargeBinary-Datentyp von SQLAlchemy keine Strings verarbeitet und daher keine Möglichkeit hat, einen Wert im String-Format zu „kodieren“.
Um eine SQLite-Tabelle zu behandeln, die gemischte String-/Binärdaten in derselben Spalte enthält, verwenden Sie einen benutzerdefinierten Typ, der jede Zeile einzeln prüft.
from sqlalchemy import String
from sqlalchemy import TypeDecorator
class MixedBinary(TypeDecorator):
impl = String
cache_ok = True
def process_result_value(self, value, dialect):
if isinstance(value, str):
value = bytes(value, "utf-8")
elif value is not None:
value = bytes(value)
return valueVerwenden Sie dann den obigen MixedBinary-Datentyp anstelle von LargeBinary.
Seriell isolierte Transaktionen / Savepoints / Transaktionale DDL¶
Im Abschnitt Datenbank-Sperrverhalten / Nebenläufigkeit verweisen wir auf die Probleme des pysqlite-Treibers, die mehrere Funktionen von SQLite daran hindern, korrekt zu funktionieren. Der pysqlite DBAPI-Treiber weist mehrere langjährige Fehler auf, die die Korrektheit seines Transaktionsverhaltens beeinträchtigen. In seinem Standardbetriebsmodus sind SQLite-Funktionen wie SERIALIZABLE-Isolation, transaktionale DDL und SAVEPOINT-Unterstützung nicht funktionsfähig, und um diese Funktionen zu nutzen, müssen Workarounds angewendet werden.
Das Problem besteht im Wesentlichen darin, dass der Treiber versucht, die Absicht des Benutzers zu erraten, indem er Transaktionen nicht startet und manchmal vorzeitig beendet, um das Sperrverhalten der SQLite-Datenbanken zu minimieren, obwohl SQLite selbst „Shared“-Sperren für Leseaktivitäten verwendet.
SQLAlchemy beschließt, dieses Verhalten standardmäßig nicht zu ändern, da es das lang erwartete Verhalten des pysqlite-Treibers ist; wenn und wenn der pysqlite-Treiber versucht, diese Probleme zu beheben, wird dies eher ein Treiber für Standardeinstellungen für SQLAlchemy sein.
Die gute Nachricht ist, dass wir mit ein paar Ereignissen die Transaktionsunterstützung vollständig implementieren können, indem wir die Funktionalität von pysqlite vollständig deaktivieren und selbst BEGIN emittieren. Dies wird durch zwei Ereignis-Listener erreicht.
from sqlalchemy import create_engine, event
engine = create_engine("sqlite:///myfile.db")
@event.listens_for(engine, "connect")
def do_connect(dbapi_connection, connection_record):
# disable pysqlite's emitting of the BEGIN statement entirely.
# also stops it from emitting COMMIT before any DDL.
dbapi_connection.isolation_level = None
@event.listens_for(engine, "begin")
def do_begin(conn):
# emit our own BEGIN
conn.exec_driver_sql("BEGIN")Warnung
Bei Verwendung des obigen Rezepts wird empfohlen, die Einstellung für die Connection.execution_options.isolation_level bei Connection und create_engine() mit dem SQLite-Treiber nicht zu verwenden, da diese Funktion notwendigerweise auch die Einstellung „.isolation_level“ ändern wird.
Oben fangen wir eine neue pysqlite-Verbindung ab und deaktivieren jede transaktionale Integration. Dann, an dem Punkt, an dem SQLAlchemy weiß, dass der Transaktionsbereich beginnen soll, emittieren wir selbst "BEGIN".
Wenn wir die Kontrolle über "BEGIN" übernehmen, können wir auch direkt die Sperrmodi von SQLite kontrollieren, die unter BEGIN TRANSACTION eingeführt wurden, indem wir den gewünschten Sperrmodus zu unserem "BEGIN" hinzufügen.
@event.listens_for(engine, "begin")
def do_begin(conn):
conn.exec_driver_sql("BEGIN EXCLUSIVE")Siehe auch
BEGIN TRANSACTION – auf der SQLite-Website
sqlite3 SELECT does not BEGIN a transaction – im Python-Bugtracker
sqlite3 module breaks transactions and potentially corrupts data – im Python-Bugtracker
Benutzerdefinierte Funktionen¶
pysqlite unterstützt eine Methode create_function(), die es uns ermöglicht, eigene benutzerdefinierte Funktionen (UDFs) in Python zu erstellen und sie direkt in SQLite-Abfragen zu verwenden. Diese Funktionen werden mit einer bestimmten DBAPI-Verbindung registriert.
SQLAlchemy verwendet Connection-Pooling für datenbankbasierte SQLite-Dateien, daher müssen wir sicherstellen, dass die UDF beim Erstellen der Verbindung an diese angehängt wird. Dies wird mit einem Ereignis-Listener erreicht.
from sqlalchemy import create_engine
from sqlalchemy import event
from sqlalchemy import text
def udf():
return "udf-ok"
engine = create_engine("sqlite:///./db_file")
@event.listens_for(engine, "connect")
def connect(conn, rec):
conn.create_function("udf", 0, udf)
for i in range(5):
with engine.connect() as conn:
print(conn.scalar(text("SELECT UDF()")))Aiosqlite¶
Unterstützung für die SQLite-Datenbank über den aiosqlite-Treiber.
DBAPI¶
Dokumentation und Download-Informationen (falls zutreffend) für aiosqlite sind verfügbar unter: https://pypi.org/project/aiosqlite/
Verbinden¶
Verbindungszeichenfolge
sqlite+aiosqlite:///file_pathDer aiosqlite-Dialekt bietet Unterstützung für die SQLAlchemy asyncio-Schnittstelle, die auf pysqlite läuft.
aiosqlite ist ein Wrapper um pysqlite, der für jede Verbindung einen Hintergrund-Thread verwendet. Es verwendet keine nicht-blockierende E/A, da SQLite-Datenbanken nicht socket-basiert sind. Es bietet jedoch eine funktionierende asyncio-Schnittstelle, die für Tests und Prototypen nützlich ist.
Mithilfe einer speziellen asyncio-Mediationsschicht kann der aiosqlite-Dialekt als Backend für das SQLAlchemy asyncio-Erweiterungspaket verwendet werden.
Dieser Dialekt sollte normalerweise nur mit der Engine-Erstellungsfunktion create_async_engine() verwendet werden.
from sqlalchemy.ext.asyncio import create_async_engine
engine = create_async_engine("sqlite+aiosqlite:///filename")Die URL übergibt alle Argumente an den pysqlite-Treiber, sodass alle Verbindungsargumente dieselben sind wie für Pysqlite.
Benutzerdefinierte Funktionen¶
aiosqlite erweitert pysqlite um asynchrone Unterstützung, sodass wir eigene benutzerdefinierte Funktionen (UDFs) in Python erstellen und sie direkt in SQLite-Abfragen verwenden können, wie hier beschrieben: Benutzerdefinierte Funktionen.
Seriell isolierte Transaktionen / Savepoints / Transaktionale DDL (asyncio-Version)¶
Ähnlich wie pysqlite unterstützt aiosqlite die SAVEPOINT-Funktion nicht.
Die Lösung ähnelt der unter Seriell isolierte Transaktionen / Savepoints / Transaktionale DDL. Dies wird durch die Ereignis-Listener in async erreicht.
from sqlalchemy import create_engine, event
from sqlalchemy.ext.asyncio import create_async_engine
engine = create_async_engine("sqlite+aiosqlite:///myfile.db")
@event.listens_for(engine.sync_engine, "connect")
def do_connect(dbapi_connection, connection_record):
# disable aiosqlite's emitting of the BEGIN statement entirely.
# also stops it from emitting COMMIT before any DDL.
dbapi_connection.isolation_level = None
@event.listens_for(engine.sync_engine, "begin")
def do_begin(conn):
# emit our own BEGIN
conn.exec_driver_sql("BEGIN")Warnung
Bei Verwendung des obigen Rezepts wird empfohlen, die Einstellung für die Connection.execution_options.isolation_level bei Connection und create_engine() mit dem SQLite-Treiber nicht zu verwenden, da diese Funktion notwendigerweise auch die Einstellung „.isolation_level“ ändern wird.
Pooling-Verhalten¶
Der SQLAlchemy aiosqlite DBAPI richtet den Verbindungs-Pool je nach Art der angeforderten SQLite-Datenbank unterschiedlich ein.
Wenn eine SQLite-Datenbank vom Typ
:memory:angegeben wird, verwendet der Dialekt standardmäßigStaticPool. Dieser Pool verwaltet eine einzige Verbindung, sodass alle Zugriffe auf die Engine dieselbe:memory:-Datenbank verwenden.Wenn eine datenbankbasierte Datenbank angegeben wird, verwendet der Dialekt
AsyncAdaptedQueuePoolals Quelle für Verbindungen.Geändert in Version 2.0.38: SQLite-Datenbank-Engines verwenden jetzt standardmäßig
AsyncAdaptedQueuePool. Zuvor wurdeNullPoolverwendet. Die KlasseNullPoolkann durch Angabe über den Parametercreate_engine.poolclassverwendet werden.
Pysqlcipher¶
Unterstützung für die SQLite-Datenbank über den pysqlcipher-Treiber.
Dialekt zur Unterstützung von DBAPIs, die das SQLCipher-Backend verwenden.
Verbinden¶
Verbindungszeichenfolge
sqlite+pysqlcipher://:passphrase@/file_path[?kdf_iter=<iter>]Treiber¶
Die aktuelle Logik zur Auswahl des Dialekts ist
Wenn der Parameter
create_engine.moduleein DBAPI-Modul liefert, wird dieses Modul verwendet.Andernfalls, für Python 3, wird https://pypi.org/project/sqlcipher3/ gewählt.
Wenn nicht verfügbar, wird auf https://pypi.org/project/pysqlcipher3/ zurückgegriffen.
Für Python 2 wird https://pypi.org/project/pysqlcipher/ verwendet.
Warnung
Die DBAPI-Treiber pysqlcipher3 und pysqlcipher werden nicht mehr gewartet; der sqlcipher3-Treiber scheint derzeit aktuell zu sein. Für zukünftige Kompatibilität kann jeder pysqlcipher-kompatible DBAPI wie folgt verwendet werden.
import sqlcipher_compatible_driver
from sqlalchemy import create_engine
e = create_engine(
"sqlite+pysqlcipher://:password@/dbname.db",
module=sqlcipher_compatible_driver,
)Diese Treiber nutzen die SQLCipher-Engine. Dieses System führt im Wesentlichen neue PRAGMA-Befehle in SQLite ein, die das Festlegen eines Passworts und anderer Verschlüsselungsparameter ermöglichen, wodurch die Datenbankdatei verschlüsselt werden kann.
Verbindungszeichenfolgen¶
Das Format der Verbindungszeichenfolge ist in jeder Hinsicht dasselbe wie beim pysqlite-Treiber, mit der Ausnahme, dass das Feld „password“ nun akzeptiert wird, das ein Passwort enthalten sollte.
e = create_engine("sqlite+pysqlcipher://:testing@/foo.db")Für einen absoluten Dateipfad sollten zwei führende Schrägstriche für den Datenbanknamen verwendet werden.
e = create_engine("sqlite+pysqlcipher://:testing@//path/to/foo.db")Eine Auswahl zusätzlicher verschlüsselungsbezogener Pragmas, die von SQLCipher unterstützt werden, wie unter https://www.zetetic.net/sqlcipher/sqlcipher-api/ dokumentiert, kann in der Abfragezeichenfolge übergeben werden und führt dazu, dass dieses PRAGMA für jede neue Verbindung aufgerufen wird. Derzeit werden cipher, kdf_iter cipher_page_size und cipher_use_hmac unterstützt.
e = create_engine(
"sqlite+pysqlcipher://:testing@/foo.db?cipher=aes-256-cfb&kdf_iter=64000"
)Warnung
Frühere Versionen von sqlalchemy berücksichtigten die in der URL-Zeichenfolge übergebenen verschlüsselungsbezogenen Pragmas nicht, die stillschweigend ignoriert wurden. Dies kann zu Fehlern beim Öffnen von Dateien führen, die von einer früheren sqlalchemy-Version gespeichert wurden, wenn die Verschlüsselungsoptionen nicht übereinstimmen.
Pooling-Verhalten¶
Der Treiber nimmt eine Änderung am Standard-Poolverhalten von pysqlite vor, wie in Threading/Pooling-Verhalten beschrieben. Es wurde beobachtet, dass der pysqlcipher-Treiber bei der Verbindung deutlich langsamer ist als der pysqlite-Treiber, höchstwahrscheinlich aufgrund des Verschlüsselungs-Overheads. Daher verwendet der Dialekt hier standardmäßig die Implementierung von SingletonThreadPool anstelle des NullPool-Pools, der von pysqlite verwendet wird. Wie immer ist die Pool-Implementierung vollständig konfigurierbar über den Parameter create_engine.poolclass; die StaticPool ist möglicherweise für die Single-Threaded-Nutzung praktikabler, oder NullPool kann verwendet werden, um zu verhindern, dass unverschlüsselte Verbindungen lange offen gehalten werden, auf Kosten einer langsameren Startzeit für neue Verbindungen.
Die Designs von flambé! dem Drachen und Der Alchemist wurden von Rotem Yaari erstellt und großzügig gespendet.
Erstellt mit Sphinx 7.2.6. Dokumentation zuletzt generiert: Di 11 Mär 2025 14:40:17 EDT