Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
SQLAlchemy ist das am weitesten verbreitete Python-ORM- und Datenbank-Toolkit. Beginnend mit SQLAlchemy 2.1.0b2 ermöglicht ein integrierter Dialekt für den mssql-python-Treiber die Verwendung von SQLAlchemy ORM und Core mit Microsoft SQL und Azure SQL-Datenbank.
Important
Der mssql-python-Dialekt wurde in SQLAlchemy 2.1.0b2 (veröffentlicht am 16. April 2026) hinzugefügt. SQLAlchemy 2.1 ist derzeit eine Pre-Release-Serie und wird für die Produktionsnutzung nicht empfohlen. Bevor Sie von SQLAlchemy 2.0 aktualisieren, sollten Sie wissen:
- APIs könnten sich vor der endgültigen stabilen Version (2.1 GA) ändern.
- Teste deine Arbeitsbelastung gründlich vor der Bereitstellung
- Verwenden Sie stabiles SQLAlchemy 2.0.x für Produktionssysteme, bis Version 2.1 GA erreicht
-
Verbinde deine Abhängigkeit mit einer bestimmten Version (zum Beispiel
sqlalchemy==2.1.0b2), anstatt Versionsbereiche zu verwenden
Siehe den Abschnitt Bekannte Einschränkungen für Details dazu, wann Vorabversionen verwendet werden sollten.
Voraussetzungen
- Python 3.10 oder höher. SQLAlchemy 2.1 hat die Unterstützung für Python 3.9 und früher eingestellt.
- Die Pakete
mssql-pythonundsqlalchemy(2.1.0b2 oder höher).
Die Beispiele in diesem Artikel verwenden die AdventureWorksLT-Beispieldatenbank . Wenn Sie AdventureWorksLT nicht installiert haben, sehen Sie sich die AdventureWorks-Beispieldatenbanken an.
Installieren Sie die Vorabversion
Da SQLAlchemy 2.1 sich in der Beta befindet, pip install sqlalchemy installiert standardmäßig die neueste stabile Version 2.0.x. Installieren Sie die Pre-Release ausdrücklich:
pip install mssql-python "sqlalchemy>=2.1.0b2"
Überprüfen Sie die installierte Version:
import sqlalchemy
print(sqlalchemy.__version__) # Should show 2.1.0b2 or later
Verbindungs-URLs
Der mssql-python-Dialekt verwendet mssql+mssqlpython als URL-Schema. Das allgemeine Format lautet:
mssql+mssqlpython://<username>:<password>@<host>:<port>/<database>
SQL-Authentifizierung
Für die SQL-Authentifizierung fügen Sie Benutzername und Passwort in die Verbindungs-URL ein:
from sqlalchemy import create_engine
# Replace <password> with your actual password. Avoid using the sa account in production.
engine = create_engine(
"mssql+mssqlpython://dbuser:<password>@localhost:1433/<database>"
)
Microsoft Entra-Authentifizierung
Für die Microsoft Entra-Authentifizierung verwenden Sie einen leeren Benutzernamen und den authentication Abfrageparameter:
from sqlalchemy import create_engine
engine = create_engine(
"mssql+mssqlpython://@<server>.database.windows.net/<database>"
"?authentication=ActiveDirectoryDefault&encrypt=yes"
)
Note
ActiveDirectoryDefault verwendet DefaultAzureCredential, das mehrere Anmeldeinformationsanbieter nacheinander ausprobiert. Die erste Verbindung kann langsam sein, weil das SDK die Kette durchläuft, bis es einen funktionierenden Anbieter findet. In der Produktion gilt: Wenn du weißt, welchen Zugangsdatentyp deine Umgebung verwendet, gib ihn direkt an (zum Beispiel ActiveDirectoryMSI für eine verwaltete Identität), um den Chain Walk zu vermeiden. Weitere Informationen finden Sie unter Microsoft Entra-Authentifizierung.
URLs programmatisch erstellen
Verwenden Sie sqlalchemy.engine.URL.create, um eine manuelle URL-Kodierung zu vermeiden:
from sqlalchemy.engine import URL
url = URL.create(
"mssql+mssqlpython",
username="dbuser",
password="<password>",
host="localhost",
port=1433,
database="<database>",
)
engine = create_engine(url)
Definiere ORM-Modelle
Verwenden Sie das deklarative Mapping von SQLAlchemy, um Modelle zu definieren, die auf Microsoft SQL-Tabellen abgebildet sind.
from datetime import datetime
from decimal import Decimal
from sqlalchemy import Identity, String, Numeric, Integer, DateTime, func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class Product(Base):
__tablename__ = "Product"
__table_args__ = {"schema": "SalesLT"}
product_id: Mapped[int] = mapped_column(
"ProductID", Integer, Identity(), primary_key=True
)
name: Mapped[str] = mapped_column("Name", String(50))
product_number: Mapped[str] = mapped_column("ProductNumber", String(25))
color: Mapped[str | None] = mapped_column("Color", String(15))
list_price: Mapped[Decimal] = mapped_column("ListPrice", Numeric(19, 4))
standard_cost: Mapped[Decimal] = mapped_column("StandardCost", Numeric(19, 4))
size: Mapped[str | None] = mapped_column("Size", String(5))
product_category_id: Mapped[int | None] = mapped_column("ProductCategoryID", Integer)
sell_start_date: Mapped[datetime] = mapped_column("SellStartDate", DateTime)
modified_date: Mapped[datetime] = mapped_column(
"ModifiedDate", DateTime, server_default=func.getdate()
)
Tip
Microsoft SQL verwendet IDENTITY für automatisch inkrementierende Spalten.
SQLAlchemy mappt dies automatisch für ganzzahlige Primärschlüsselspalten. Das oben gezeigte explizite Identity() ist optional, es sei denn, du musst die Start- und Inkrementwerte festlegen.
CRUD-Vorgänge
Die folgenden Beispiele zeigen, wie man Zeilen mit der ORM-Sitzung einfügt, abfragt, aktualisiert und löscht. Jedes Beispiel verwendet new_id, das ProductID zurückgegeben wird, wenn man eine Zeile einfügt. Um alle vier Operationen gemeinsam auszuführen, siehe das vollständige Beispiel.
Erstellen Sie eine Sitzung
Erstellen Sie eine Sitzung, um Operationen innerhalb einer Transaktion auszuführen:
from sqlalchemy.orm import Session
with Session(engine) as session:
# Use session for queries and modifications
pass
Für Anwendungen, die viele Sitzungen erstellen, verwenden Sie sessionmaker:
from sqlalchemy.orm import sessionmaker
SessionLocal = sessionmaker(bind=engine)
Einfügen von Zeilen
Fügen Sie ein neues Produkt hinzu, schließen Sie die Sitzung ab und erfassen Sie das generierte ProductID für die folgenden Beispiele:
from datetime import datetime
with Session(engine) as session:
product = Product(
name="Classic Road Bike",
product_number="BK-C001",
color="Red",
list_price=Decimal("1299.99"),
standard_cost=Decimal("749.99"),
sell_start_date=datetime(2026, 1, 1),
product_category_id=6,
)
session.add(product)
session.commit()
new_id = product.product_id
print(f"Inserted ProductID: {new_id}")
Note
In SalesLT.Product haben sowohl Name als auch ProductNumber eindeutige Constraints. Wenn du diesen Insert mehrmals ausführst, ändere diese Werte oder lösche zuerst die frühere Zeile. Das vollständige Beispiel löscht die erstellte Zeile, sodass es wiederholt ausgeführt werden kann.
Abfragezeilen
Eine einzelne Zeile per Primärschlüssel abrufen oder für gefilterte Abfragen verwenden select() :
from sqlalchemy import select
with Session(engine) as session:
# Single row by primary key (new_id is from the insert example)
product = session.get(Product, new_id)
if product:
print(f"{product.name}: ${product.list_price}")
# Filtered query
stmt = select(Product).where(Product.list_price < 500).order_by(Product.name)
products = session.scalars(stmt).all()
for p in products:
print(f"{p.name}: ${p.list_price}")
Zeilen aktualisieren
Ändere ein Feld in einer bestehenden Zeile und commite:
with Session(engine) as session:
product = session.get(Product, new_id)
if product:
product.list_price = Decimal("1349.99")
session.commit()
Löschen von Zeilen
Entferne eine Zeile und führe einen Commit durch:
with Session(engine) as session:
product = session.get(Product, new_id)
if product:
session.delete(product)
session.commit()
Vollständiges Beispiel
Die vorherigen Abschnitte zeigten jedes Stück einzeln. Dieser Abschnitt vereint sie zu einem eigenständigen Skript, das du kopieren, ausführen und erneut ausführen kannst.
Erstellen Sie eine Datei mit dem Namen crud.py, und fügen Sie den folgenden Code hinzu. Ersetzen Sie die Verbindungsdetails in create_engine durch Ihre eigenen (siehe Verbindungs-URLs):
from datetime import datetime
from decimal import Decimal
from sqlalchemy import create_engine, Identity, String, Numeric, Integer, DateTime, func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
# Replace <password> and <database> with your connection details.
engine = create_engine(
"mssql+mssqlpython://dbuser:<password>@localhost:1433/<database>"
)
class Base(DeclarativeBase):
pass
class Product(Base):
__tablename__ = "Product"
__table_args__ = {"schema": "SalesLT"}
product_id: Mapped[int] = mapped_column(
"ProductID", Integer, Identity(), primary_key=True
)
name: Mapped[str] = mapped_column("Name", String(50))
product_number: Mapped[str] = mapped_column("ProductNumber", String(25))
color: Mapped[str | None] = mapped_column("Color", String(15))
list_price: Mapped[Decimal] = mapped_column("ListPrice", Numeric(19, 4))
standard_cost: Mapped[Decimal] = mapped_column("StandardCost", Numeric(19, 4))
size: Mapped[str | None] = mapped_column("Size", String(5))
product_category_id: Mapped[int | None] = mapped_column("ProductCategoryID", Integer)
sell_start_date: Mapped[datetime] = mapped_column("SellStartDate", DateTime)
modified_date: Mapped[datetime] = mapped_column(
"ModifiedDate", DateTime, server_default=func.getdate()
)
with Session(engine) as session:
# Create
product = Product(
name="Classic Road Bike",
product_number="BK-C001",
color="Red",
list_price=Decimal("1299.99"),
standard_cost=Decimal("749.99"),
sell_start_date=datetime(2026, 1, 1),
product_category_id=6,
)
session.add(product)
session.commit()
new_id = product.product_id
print(f"Inserted ProductID: {new_id}")
# Read
product = session.get(Product, new_id)
print(f"Read: {product.name} costs ${product.list_price}")
# Update
product.list_price = Decimal("1349.99")
session.commit()
print(f"Updated price to ${product.list_price}")
# Delete
session.delete(product)
session.commit()
print(f"Deleted ProductID: {new_id}")
Führen Sie das Skript aus:
python crud.py
Sie sehen eine Ausgabe ähnlich der folgenden:
Inserted ProductID: 1019
Read: Classic Road Bike costs $1299.9900
Updated price to $1349.9900
Deleted ProductID: 1019
Das Skript löscht die Zeile, die es erstellt, sodass die einzigartigen Einschränkungen bei Name und ProductNumber beim erneuten Ausführen nicht betroffen sind. Jeder Durchlauf fügt eine neue Zeile ein, sodass ProductID jedes Mal zunimmt.
Kernanfragen
SQLAlchemy Core bietet eine SQL-Ausdrucks-API auf niedrigerer Ebene. Du kannst Core mit derselben Engine und denselben Tabellendefinitionen verwenden, einschließlich ORM-zugeordneter Klassen.
from sqlalchemy import text
with engine.connect() as conn:
result = conn.execute(text("SELECT @@VERSION"))
print(result.scalar())
Verwenden Sie Tabellenkonstrukte für die typsichere SQL-Generierung:
from sqlalchemy import insert, select, update, delete
with engine.connect() as conn:
# Insert
conn.execute(
insert(Product).values(
name="Touring Bike",
product_number="BK-T002",
list_price=Decimal("999.99"),
standard_cost=Decimal("575.00"),
sell_start_date=datetime(2026, 1, 1)
)
)
conn.commit()
# Select
stmt = select(
Product.name.label("name"),
Product.list_price.label("list_price"),
).where(Product.list_price > 100)
for row in conn.execute(stmt):
print(row.name, row.list_price)
# Delete the inserted row so this example can run again
conn.execute(delete(Product).where(Product.product_number == "BK-T002"))
conn.commit()
Note
Wenn Sie einzelne zugeordnete Spalten auswählen, deren Datenbankname vom Attributnamen abweicht (zum Beispiel, wenn Product.name der Spalte Name zugeordnet ist), werden Core-Zeilen durch den Namen der Datenbankspalte identifiziert. Fügen Sie .label("name") hinzu, um auf den Wert als row.name statt als row.Name zuzugreifen.
Verbindungspooling
SQLAlchemy verwaltet standardmäßig einen Verbindungspool. Passen Sie die Pool-Einstellungen für Ihre Arbeitsbelastung an:
engine = create_engine(
"mssql+mssqlpython://dbuser:<password>@localhost/<database>",
pool_size=10,
max_overflow=20,
pool_timeout=30,
pool_recycle=3600,
)
| Parameter | Beschreibung |
|---|---|
pool_size |
Anzahl der Verbindungen, die offen bleiben müssen (Standard: 5). |
max_overflow |
Verbindungen über pool_size hinaus erlaubt (Standard: 10). |
pool_timeout |
Sekunden, um auf eine Verbindung zu warten, bevor ein Fehler ausgelöst wird (Standard: 30). |
pool_recycle |
Sekunden, danach wird eine Verbindung recycelt (Standard: -1, deaktiviert). Setze diesen Wert, falls deine Datenbank untätige Verbindungen schließt. |
Verwendung mit Web-Frameworks
SQLAlchemy wird häufig als Datenbankschicht für Flask und FastAPI verwendet. Der mssql-python-Dialekt funktioniert mit jedem Framework, das SQLAlchemy unterstützt.
Die folgenden Codeausschnitte zeigen das empfohlene Muster „eine Sitzung pro Anfrage“ für jedes Framework. Es sind veranschaulichende Fragmente, die das engine und Product Modell aus den vorherigen Abschnitten zugrunde legen, keine vollständigen Anwendungen. Für vollständige, betriebsfähige Anwendungen siehe die Artikel zur FastAPI-Integration und zur Flask-Integration .
FastAPI-Beispiel
Verwenden Sie eine Generatorabhängigkeit, um pro Anfrage eine Sitzung bereitzustellen:
from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.orm import Session, sessionmaker
from sqlalchemy import create_engine
engine = create_engine("mssql+mssqlpython://dbuser:<password>@<server>/<database>")
SessionLocal = sessionmaker(bind=engine)
app = FastAPI()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.get("/products/{product_id}")
def read_product(product_id: int, db: Session = Depends(get_db)):
product = db.get(Product, product_id)
if not product:
raise HTTPException(status_code=404, detail="Product not found")
return {"name": product.name, "price": float(product.list_price)}
Flask-Beispiel
Verwenden Sie einen Kontextmanager, um die Sitzung auf die Anfrage abzugrenzen:
from flask import Flask, jsonify
from sqlalchemy.orm import Session, sessionmaker
from sqlalchemy import create_engine
engine = create_engine("mssql+mssqlpython://dbuser:<password>@<server>/<database>")
SessionLocal = sessionmaker(bind=engine)
app = Flask(__name__)
@app.route("/products/<int:product_id>")
def read_product(product_id):
with SessionLocal() as session:
product = session.get(Product, product_id)
if not product:
return jsonify({"error": "Not found"}), 404
return jsonify({"name": product.name, "price": float(product.list_price)})
Alembische Wanderungen
Alembic übernimmt Schema-Migrationen für SQLAlchemy-Projekte und arbeitet mit dem mssql-python-Dialekt. Alembics Autogenerierungsfunktion vergleicht deine Modelle mit der Live-Datenbank, sodass ein paar zusätzliche Schritte verhindern, dass Änderungen an Tabellen vorgeschlagen werden, die du nicht verwaltest.
Aufbau von Alembic
Installiere Alembic und initialisiere ein Migrationsverzeichnis:
pip install alembic
alembic init migrations
In alembic.inisetzen Sie die Verbindungs-URL:
sqlalchemy.url = mssql+mssqlpython://dbuser:<password>@localhost/<database>
Zeigen Sie Alembic auf Ihre Modelle
Autogenerate benötigt die Metadaten deiner Modelle. Fügen Sie die Modelle, die Alembic verwaltet, in ein importierbares Modul ein, wie zum Beispiel models.py. Da Autogenerate vorschlägt, jede Spalte, die ein Modell weglässt, wegzulassen, sollte ein Modell definiert werden, das seine Tabelle vollständig besitzt, anstatt das vereinfachte Product Modell aus diesem Artikel wiederzuverwenden:
# models.py
from datetime import datetime
from sqlalchemy import Identity, String, Integer, DateTime, func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class ProductReview(Base):
__tablename__ = "ProductReview"
__table_args__ = {"schema": "SalesLT"}
review_id: Mapped[int] = mapped_column("ReviewID", Integer, Identity(), primary_key=True)
product_id: Mapped[int] = mapped_column("ProductID", Integer)
reviewer_name: Mapped[str] = mapped_column("ReviewerName", String(50))
rating: Mapped[int] = mapped_column("Rating", Integer)
comments: Mapped[str | None] = mapped_column("Comments", String(500))
modified_date: Mapped[datetime] = mapped_column("ModifiedDate", DateTime, server_default=func.getdate())
Caution
Standardmäßig behandelt Autogenerate jede Tabelle in der Datenbank, die sich nicht in target_metadata befindet, als entfernt und gibt dafür drop_table aus. Bei einer vorhandenen Datenbank wie AdventureWorksLT kann diese Aktion Dutzende von Tabellen löschen. Füge einen include_name Filter hinzu, damit Alembic nur die Tabellen verwaltet, die deine Modelle definieren, und überprüfe das generierte Skript immer, bevor du es anwendest.
In migrations/env.py ersetzen Sie target_metadata = None durch den folgenden Code. Es importiert deine Modelle und beschränkt die Autogenerierung auf die Schemata und Tabellen, die sie definieren:
from models import Base
target_metadata = Base.metadata
# Limit autogenerate to the tables your models define.
managed_schemas = {table.schema for table in target_metadata.tables.values()}
managed_tables = {table.name for table in target_metadata.tables.values()}
def include_name(name, type_, parent_names):
if type_ == "schema":
return name in managed_schemas
if type_ == "table":
return name in managed_tables
return True
Übergeben Sie include_name und include_schemas=True an context.configure in run_migrations_offline und run_migrations_online. Die Einstellung include_schemas=True erlaubt es Alembic, Tabellen in Nicht-Standardschemata zu sehen, wie zum Beispiel SalesLT:
context.configure(
connection=connection,
target_metadata=target_metadata,
include_name=include_name,
include_schemas=True,
)
Generiere und wende eine Migration an
Generiere eine Migration von deinen Modellen:
alembic revision --autogenerate -m "add product review table"
Alembic erkennt die neue Tabelle und schreibt ein Migrationsskript:
INFO [alembic.autogenerate.compare.tables] Detected added table 'SalesLT.ProductReview'
Generating .../versions/xxxx_add_product_review_table.py ... done
Das von upgrade() generierte Element erstellt die Tabelle, und downgrade() löscht sie:
def upgrade() -> None:
op.create_table(
"ProductReview",
sa.Column("ReviewID", sa.Integer(), sa.Identity(always=False), nullable=False),
sa.Column("ProductID", sa.Integer(), nullable=False),
sa.Column("ReviewerName", sa.String(length=50), nullable=False),
sa.Column("Rating", sa.Integer(), nullable=False),
sa.Column("Comments", sa.String(length=500), nullable=True),
sa.Column("ModifiedDate", sa.DateTime(), server_default=sa.text("getdate()"), nullable=False),
sa.PrimaryKeyConstraint("ReviewID"),
schema="SalesLT",
)
def downgrade() -> None:
op.drop_table("ProductReview", schema="SalesLT")
Überprüfen Sie das Skript und wenden Sie dann alle ausstehenden Migrationen an:
alembic upgrade head
Unterschiede zum Pyodbc-Dialekt
Wenn du von mssql+pyodbcmigrierst, ist der mssql-python-Dialekt ähnlich, weil beide Treiber auf demselben ODBC-Framework basieren. Wichtige Unterschiede:
| Thema | mssql+pyodbc |
mssql+mssqlpython |
|---|---|---|
| ODBC-Treiberinstallation | Benötigt einen separaten ODBC-Treiber (zum Beispiel ODBC Driver 18 für Microsoft SQL). | Der Treiber ist im Lieferumfang enthalten. Kein separater ODBC-Treiber nötig. |
| Verbindungs-URL | mssql+pyodbc://user:pass@host/db?driver=ODBC+Driver+18+for+SQL+Server |
mssql+mssqlpython://user:pass@host/db |
fast_executemany |
Unterstützt von create_engine(..., fast_executemany=True). |
Nicht zutreffend. Der Treiber verwaltet die Batch-Verarbeitung intern. |
| Availability | Stabil, seit Version 1.x in SQLAlchemy enthalten. | Vorabversion (SQLAlchemy 2.1.0b2+). |
Bekannte Einschränkungen
Der mssql-python-Dialekt für SQLAlchemy ist in der Vorabversion. Bevor Sie sie in der Produktion verwenden, sollten Sie diese Implikationen verstehen:
API-Änderungen: Methodensignaturen, Ausnahmetypen und Verhalten können sich vor der endgültigen stabilen Version ändern. Stecke deine SQLAlchemy-Version immer an einen bestimmten Pre-Release-Build (zum Beispiel )
sqlalchemy==2.1.0b2und teste Upgrades gründlich.Begrenzte Testung: Der Dialekt hat weniger Community-Tests als der stabile
mssql+pyodbcDialekt. Du könntest auf Randfälle oder fehlende Funktionen stoßen.Funktionslücken: Einige fortgeschrittene ORM- oder Core-Funktionen funktionieren möglicherweise nicht. Schau dir die SQLAlchemy MSSQL-Dialektdokumentation an und teste deine Anwendungsfälle, bevor du dich auf ein Projekt einlässt.
Keine Support-Garantie: Microsoft und SQLAlchemy bieten Best-Effort-Support, aber Probleme könnten vor der stabilen Version nicht behoben sein.
Wann sollte man die Vorabveröffentlichung verwenden:
- Entwicklungs- und Testumgebungen
- Proof-of-Concept-Projekte
- Migration von
mssql+pyodbc, wenn du die externe ODBC-Treiberabhängigkeit vermeiden möchtest - Projekte, bei denen man auf API-Änderungen reagieren und Regressionstests durchführen kann
Wann sollte man die Pre-Release NICHT verwenden:
- Produktionssysteme mit strengen Stabilitätsanforderungen
- Mehrjährige Legacy-Anwendungen, bei denen Abhängigkeitsupdates selten sind
- Kritische Geschäfts-Workloads, bis SQLAlchemy 2.1 stabile GA erreicht
Für den neuesten Dialektstatus vor der Veröffentlichung und bekannte Probleme siehe das mssql-python GitHub-Repository.
Problembehandlung
"Kein Modul namens 'sqlalchemy.dialects.mssql.mssqlpython'"
Dieser Fehler bedeutet, dass deine installierte SQLAlchemy-Version den mssql-python-Dialekt nicht enthält. Überprüfen Sie, dass Sie 2.1.0b2 oder höher haben:
pip install "sqlalchemy>=2.1.0b2"
Verbindungsfehler
Wenn create_engine es gelingt, aber Abfragen fehlschlagen, überprüfen Sie, ob Ihre Verbindungsparameter direkt mit mssql-python funktionieren:
import mssql_python
conn = mssql_python.connect(
"Server=localhost;Database=<database>;UID=dbuser;PWD=<password>;Encrypt=yes"
)
cursor = conn.cursor()
cursor.execute("SELECT 1")
print(cursor.fetchone())
conn.close()
Wenn die direkte Verbindung funktioniert, SQLAlchemy jedoch nicht, prüfe, ob Sonderzeichen in deinem Passwort oder Servernamen Probleme bei der URL-Codierung verursachen.