Fehlerbehebung der Microsoft-Treiber für PHP für SQL Server

PHP-Treiber herunterladen

Diagnostizieren und beheben Sie häufige Probleme, wenn Sie die Microsoft-Treiber für PHP für SQL Server verwenden, um sich mit SQL Server, Azure SQL-Datenbank, Azure SQL Managed Instance und SQL Database zu verbinden Microsoft Fabric.

Allgemeine Fehler- und Warnmuster finden Sie unter Handhabung von Fehlern und Warnungen. Für die Erfassung der Diagnostik auf der Fahrerseite siehe Logging von Aktivitäten.

Installationsprobleme

Erweiterung nicht geladen

Symptome:

  • phpinfo() Listet keinen A sqlsrv - oder pdo_sqlsrv Abschnitt auf.
  • PDOException: could not find driver beim Aufbau PDO eines mit dem sqlsrv: DSN.
  • Fatal error: Uncaught Error: Call to undefined function sqlsrv_connect().

Mögliche Ursachen und Lösungen:

  • Erweiterung in php.ininicht aktiviert . Überprüfen Sie, dass sowohl als auch extension=sqlsrvextension=pdo_sqlsrv nicht kommentiert sind. Unter Windows verwenden Sie den vollständigen Dateinamen (extension=php_sqlsrv_84_ts_x64.dll). Details finden Sie unter Laden der Treiber.
  • Falscher Gewindesicherungsbau. Die Treiber-Binärform muss mit der Thread-Sicherheit deines PHP-Builds übereinstimmen (ts für threadsicher, nts für nicht-threadsicher). Führen Sie php -i | grep "Thread Safety" zum Prüfen aus. Laden Sie die passende Binärdatei von der Download-Seite herunter.
  • Microsoft ODBC-Treiber fehlt. Die PHP-Treiber umschließen den Microsoft ODBC Driver für SQL Server. Unter Linux und macOS installiere msodbcsql18 (oder msodbcsql17) mit deinem Paketmanager, bevor du die Erweiterungen lädst. Installiere unter Windows den ODBC-Treiber von der Download-Seite.

Überprüfen Sie eine erfolgreiche Installation:

php -m | grep -i sqlsrv

Du solltest sowohl als auch pdo_sqlsrvsqlsrv im Ausgang sehen.

PECL-Installation schlägt auf Linux oder macOS fehl

Symptome:

error: ‘SQL_HANDLE_DBC’ undeclared (first use in this function)
fatal error: 'sql.h' file not found

Korrektur:

Installieren Sie die ODBC-Entwicklungsheader vor dem Ausführen pecl installvon :

  • Ubuntu und Debian: sudo apt-get install unixodbc-dev
  • Red Hat, Fedora und CentOS:sudo dnf install unixODBC-devel
  • Alpine: apk add unixodbc-dev
  • macOS:brew install unixodbc

Versuchen Sie es dann noch einmal:

sudo pecl install sqlsrv
sudo pecl install pdo_sqlsrv

Wenn pecl es nach der Installation der Header trotzdem fehlschlägt, könnte die Build-Toolchain unvollständig sein. Installiere phpize, re2c, und einen C++-Compiler (build-essential auf Debian und Ubuntu, gcc-c++ make auf Red Hat und Fedora, build-base auf Alpine).

Für den vollständigen Installationspfad siehe Installationsanleitung für Linux und macOS.

Mehrere PHP-Versionen installiert

Symptome:

phpinfo() auf deinem Webserver wird eine PHP-Version angezeigt, aber php -v in der Kommandozeile eine andere, und der Treiber wird nur in einer davon geladen.

Korrektur:

Jede PHP-Version hat ihr eigenes php.ini Verzeichnis ext . Finde die richtige Konfigurationsdatei php --ini aus der Umgebung, der der Treiber fehlt, und füge dort die extension= Zeilen hinzu. Neustarte den Webserver (Apache, Nginx + PHP-FPM oder IIS) nach jeder php.ini Änderung.

Verbindungsprobleme

Keine Verbindung zum Server möglich

Symptome:

SQLSTATE[08001]: [Microsoft][ODBC Driver 18 for SQL Server]TCP Provider: A connection attempt failed
SQLSTATE[HYT00]: [Microsoft][ODBC Driver 18 for SQL Server]Login timeout expired

Mögliche Ursachen und Lösungen:

  • Der Server ist nicht erreichbar. Überprüfen Sie, ob Servername und Port korrekt sind. Vom PHP-Host aus testen Sie die rohe TCP-Konnektivität.

    # Linux and macOS
    nc -vz <server>.database.windows.net 1433
    
    # Windows PowerShell
    Test-NetConnection -ComputerName <server>.database.windows.net -Port 1433
    
  • Firewall blockiert ausgehende 1433. Unternehmensfirewalls und Cloud-NSGs blockieren häufig den ausgehenden Port 1433. Füge eine Ausnahme hinzu oder erlaube die Azure SQL-Datenbank-IP-Bereiche für deine Region.

  • Azure SQL Server Firewall. Füge die öffentliche IP deines Kunden zu den Server-Firewall-Regeln im Azure-Portal hinzu.

  • Benannte Instanz. Für eine benannte Instanz überprüfen Sie, ob der SQL Server Browser-Dienst auf dem Server läuft und dass UDP 1434 offen ist. Oder verbinden Sie sich per Port statt nach Instanznamen.

Fehler bei der Anmeldung

Symptome:

SQLSTATE[28000]: [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Login failed for user '<user_id>'.

Mögliche Ursachen und Lösungen:

  • SQL-Authentifizierungsmodus deaktiviert. Lokale SQL Server-Instanzen verwenden standardmäßig nur Windows-Authentifizierung. Aktivieren Sie die Authentifizierung im gemischten Modus im SQL Server Management Studio unter Server Properties>Security und starten Sie dann den SQL Server-Dienst neu.
  • Azure SQL credentials format. Azure SQL benötigt den vollständig qualifizierten Benutzernamen (user@servername) beim Verbinden mit Tools, die es nicht automatisch anhängen.
  • Benutzer nicht der Datenbank zugeordnet. Überprüfen Sie, dass der Login eine Benutzerzuordnung in der Zieldatenbank enthält und der Benutzer die erforderlichen Berechtigungen hat.
  • Bevorzuge Microsoft Entra ID. Für Azure SQL, Azure SQL Managed Instance und SQL-Datenbank in Fabric verwenden Sie Microsoft Entra-Authentifizierung (Authentication=ActiveDirectoryMsi, Authentication=ActiveDirectoryServicePrincipal, oder ein Zugriffstoken) anstelle von SQL-Logins. Siehe Verbinden mit der Microsoft Entra-Authentifizierung.

Ungültiger Wert angegeben für das Verbindungszeichenfolge-Attribut 'Authentication'

Symptome:

SQLSTATE[08001]: [Microsoft][ODBC Driver 17 for SQL Server]Invalid value specified for connection string attribute 'Authentication'

Ursache:

Der ODBC-Treiber meldet den Fehler, aber das eigentliche Problem ist, an welchen Treiber PDO_SQLSRV gebunden ist. Wenn das DSN kein Driver= Schlüsselwort enthält und der Host sowohl ODBC 17 als auch ODBC 18 installiert hat, kann PDO_SQLSRV auf die ältere Version binden. Ältere ODBC 17.x-Builds kennen keine neueren Authentication Werte wie ActiveDirectoryServicePrincipal oder ActiveDirectoryDefault, und benötigen sogar ActiveDirectoryMsi ODBC 17.3.1.1 oder eine neuere Version.

Korrektur:

Pinne den Treiber im DSN:

<?php
$dsn = "sqlsrv:Driver={ODBC Driver 18 for SQL Server};Server=$server;Database=$db;" .
       "Encrypt=true;Authentication=ActiveDirectoryMsi";
$conn = new PDO($dsn, null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);

Die in Klammern gesetzte Form ({ODBC Driver 18 for SQL Server}) entfällt den Leerzeichen im Fahrernamen. Die Fehlermeldung selbst nennt immer den gemeldeten Treiber, sodass das Präfix [Microsoft][ODBC Driver 17 for SQL Server] im Fehler der schnellste Weg ist, die falsche Treiberbindung zu bestätigen.

Das ungültige Schlüsselwort 'UID' wurde im DSN-String angegeben

Symptome:

SQLSTATE[IMSSP]: An invalid keyword 'UID' was specified in the DSN string.

Ursache:

PDO_SQLSRV erzwingt eine Erlaubnisliste mit DSN-Schlüsselwörtern und akzeptiert UID das DSN PWD nicht. PDO reserviert das zweite und dritte Konstruktorargument für diese und übersetzt sie PDO_SQLSRV intern in ODBC UID/PWD .

Korrektur:

Übertragen Sie den Benutzernamen (und das Passwort für SQL-Authentifizierung) in den PDO-Konstruktor:

<?php
// SQL authentication.
$dsn = "sqlsrv:Driver={ODBC Driver 18 for SQL Server};Server=$server;Database=$db;Encrypt=true";
$conn = new PDO($dsn, $user, $password);

// User-assigned managed identity. Pass the identity's client ID as $username.
$dsn = "sqlsrv:Driver={ODBC Driver 18 for SQL Server};Server=$server;Database=$db;" .
       "Encrypt=true;Authentication=ActiveDirectoryMsi";
$conn = new PDO($dsn, $clientId, null);

Der SQLSRV-prozedurale Treiber hingegen akzeptiert UID und PWD im Verbindungsoptions-Array wird an sqlsrv_connect()übergeben.

PDO_SQLSRV ignoriert AccessToken im Options-Array stillschweigend

Symptom:

Du hast ein Microsoft Entra Zugriffstoken (zum Beispiel von az account get-access-token --resource https://database.windows.net/, , oder ClientSecretCredential), und gibst es wie im vierten Konstruktor-Argument an PDO_SQLSRV ['AccessToken' => $token]ManagedIdentityCredentialweiter. Der Verbindungsversuch scheitert mit einem verwirrenden Fehler wie Windows logins are not supported in this version of SQL Server oder Login failed for user '', als ob keine Zugangsdaten angegeben worden wären.

Ursache:

Das vierte Konstruktorargument von PDO ist für treiberspezifische Attributkonstanten (ganzzahlige Schlüssel wie PDO::ATTR_ERRMODE) reserviert. PDO lässt lautlos String-Key-Einträge wie AccessToken, sodass PDO_SQLSRV das Token nie sieht. Die Verbindung fällt dann auf Windows Integrated Authentication zurück, die der Server ablehnt.

Korrektur:

Wechsel AccessToken in den DSN-String. Reserviere das Options-Array für PDO::ATTR_* Konstanten.

<?php
$server = '<server>.database.windows.net';
$token  = getenv('SQL_ACCESS_TOKEN');   // raw JWT, no "Bearer " prefix

$dsn = "sqlsrv:Server=$server;Database=<database>;Encrypt=true;AccessToken=$token";
$conn = new PDO($dsn, null, null, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

Für weitere Beispiele Microsoft Entra Authentifizierung, einschließlich des DSN-Formulars für PDO_SQLSRV, siehe Verbinden mit Microsoft Entra Authentifizierung.

Für das SQLSRV-Prozedural gehört in das connection-info-Array, AccessToken das an übergeben wird sqlsrv_connect(), was das rohe JWT für dich in SQL_COPT_SS_ACCESS_TOKEN wrappt:

<?php
$server = '<server>.database.windows.net';
$token  = getenv('SQL_ACCESS_TOKEN');   // raw JWT, no "Bearer " prefix

$connectionInfo = [
    'Database'               => '<database>',
    'AccessToken'            => $token,
    'Encrypt'                => true,
    'TrustServerCertificate' => false,
    'Driver'                 => '{ODBC Driver 18 for SQL Server}',
];

$conn = sqlsrv_connect($server, $connectionInfo);
if ($conn === false) {
    print_r(sqlsrv_errors());
    exit(1);
}

TLS-Zertifikatsfehler

Symptome:

SQLSTATE[08001]: SSL Provider: The certificate chain was issued by an authority that is not trusted
SQLSTATE[08001]: SSL Provider: The target principal name is incorrect

Lösungen:

Bevorzuge ein vertrauenswürdiges Zertifikat. Verwenden Sie TrustServerCertificate=true es nur für lokale Entwicklung gegen einen Server, den Sie steuern.

Für die Entwicklung anhand eines selbstunterschriebenen Zertifikats:

<?php
$server   = 'localhost';
$database = '<database>';
$user     = '<user_id>';
$password = '<password>';

$dsn = "sqlsrv:Server=$server;Database=$database;Encrypt=true;TrustServerCertificate=true";
$conn = new PDO($dsn, $user, $password, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

Caution

TrustServerCertificate=true Deaktivieren Sie die Validierung von Serverzertifikaten. Nimm dieses Setting niemals in Produktion, Inszenierung oder gemeinsame Umgebungen mit.

Für einen Produktions-Hostnamen, der nicht mit dem Common Name des Zertifikats übereinstimmt (zum Beispiel beim Verbinden über einen Listener), geben Sie den tatsächlichen Zertifikatssubjekt an:

<?php
$dsn = "sqlsrv:Server=<listener>;Database=<database>;Encrypt=true;HostNameInCertificate=*.database.windows.net;Authentication=ActiveDirectoryMsi";
$conn = new PDO($dsn, null, null, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

Verbindungstimeout

Symptome:

SQLSTATE[HYT00]: Login timeout expired

Mögliche Ursachen und Lösungen:

  • LoginTimeout Nicht eingestellt oder zu niedrig für Cold Failover. Setzen Sie eine explizite LoginTimeout (in Sekunden) im DSN beim Verbinden mit Azure SQL. Failover-Group-Failovers und Cold-Start-Datenbanken können länger dauern, als es eine kurze clientseitige Auszeit erlaubt. Siehe Verbindungsoptionen für die Optionsreferenz.
  • Das Budget für den Leerlauf-Wiederanschluss wurde verkürzt. Wenn du setzt ConnectRetryCount und ConnectRetryInterval, stelle sicher, dass LoginTimeout >= ConnectRetryCount * ConnectRetryInterval. Andernfalls beendet die Login-Timeout die Wiederverbindungsschleife vorzeitig. Siehe Inaktiv-Verbindungs-Resilienz.
<?php
$dsn = "sqlsrv:Driver={ODBC Driver 18 for SQL Server};Server=<server>.database.windows.net;Database=<database>;" .
       "Encrypt=true;LoginTimeout=90;ConnectRetryCount=5;ConnectRetryInterval=15;" .
       "Authentication=ActiveDirectoryMsi";
$conn = new PDO($dsn, null, null, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

Abfrageausführungsprobleme

Stille Ausfälle mit PDO

Symptom:

A PDO::exec() oder PDOStatement::execute() Call kehrt zurück, false wirft aber keine Ausnahme.

Korrektur:

Mit PHP 8.0 und neueren Versionen ist der Standard-PDO-Fehlermodus .PDO::ERRMODE_EXCEPTION Wenn ein Aufruf ohne Wurf zurückkehrt false , änderte die Anwendung den Modus zu PDO::ERRMODE_SILENT oder PDO::ERRMODE_WARNING. Setze es zurück in den Ausnahmemodus, damit Fehler Ausnahmen auslösen:

<?php
$conn = new PDO($dsn, $user, $password, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

Wenn du den Modus global nicht ändern kannst, überprüfe $conn->errorInfo() (oder $stmt->errorInfo()) nach jedem Anruf. Das Array enthält [SQLSTATE, driver code, driver message].

Ungültiger Objektname

Symptome:

SQLSTATE[42S02]: [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Invalid object name 'Products'.

Mögliche Ursachen und Lösungen:

  • Falscher Datenbankkontext. Überprüfen Sie dies mit einer kurzen Frage:

    <?php
    $stmt = $conn->query("SELECT DB_NAME()");
    echo $stmt->fetchColumn();
    
  • Fehlende Schema-Qualifikation. Verwenden Sie vollständig qualifizierte Namen, um nicht auf das Standardschema des Anrufers zu vertrauen:

    SELECT * FROM dbo.Products;
    
  • Unterscheidung nach Groß-/Kleinschreibung. Datenbanken, die mit einer fallabhängigen Sortierung erstellt werden, behandeln products und Products als verschiedene Objekte. Entspricht dem genauen Fall in der Tabellendefinition.

Falsche Anzahl von Parametern

Symptome:

SQLSTATE[HY093]: Invalid parameter number
SQLSTATE[07002]: COUNT field incorrect or syntax error

Korrektur:

Für PDO_SQLSRV muss die Anzahl der ? Platzhalter mit der Anzahl der Werte übereinstimmen, an die du übergebe execute(), und jeder ? bindet einen einzelnen Skalar (kein Array). Für benannte Parameter muss jeder :name im SQL im Array erscheinen und umgekehrt.

<?php
$stmt = $conn->prepare(
    "SELECT * FROM dbo.Products WHERE CategoryID = ? AND ListPrice > ?"
);
$stmt->execute([1, 50.0]);
foreach ($stmt as $row) {
    // ...
}

Für SQLSRV übergeben Sie das Parameterarray an sqlsrv_query() oder sqlsrv_prepare():

<?php
$stmt = sqlsrv_query(
    $conn,
    "SELECT * FROM dbo.Products WHERE CategoryID = ? AND ListPrice > ?",
    [1, 50.0]
);
if ($stmt === false) {
    die(print_r(sqlsrv_errors(), true));
}

Für eine umfassendere Einführung in die Parameterbindung siehe Parametrisierte Abfragen ausführen.

PDO emuliert bereitet Maskenfehler vor

Symptome:

Eine Anweisung läuft erfolgreich auf einer Verbindung, wirft aber einen Syntaxfehler bei einer anderen Verbindung, die denselben Abfragetext verwendet.

Ursache:

PDO_SQLSRV unterstützt sowohl emulierte als auch native vorbereitete Anweisungen. Emuliert bereitet (PDO::ATTR_EMULATE_PREPARES = true) clientseitige Parameter vor. Native bereitet (false) vor, sendet die Abfrage und die Parameter separat an den Server. Das Verhalten unterscheidet sich bei TOP (?)tabellenwertigen Parametern und einigen Randfällen bei der Typ-Bedingung.

Korrektur:

Ich bevorzuge in der Produktion einheimische Zubereitungen. Zur Verbindungszeit eingestellt PDO::ATTR_EMULATE_PREPARES => false , damit das Verhalten über verschiedene Umgebungen hinweg konsistent ist:

<?php
$conn = new PDO($dsn, null, null, [
    PDO::ATTR_ERRMODE          => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
]);

Details dazu, wann jeder Modus verwendet werden sollte, finden Sie unter PDO::p repare.

Datentypprobleme

Unicode-Zeichen erscheinen als ? oder verzerrt

Symptome:

Zeilen, die PHP schreibt, enthalten Fragezeichen oder Ersatzzeichen anstelle der ursprünglichen nicht-ASCII-Zeichen. Die Lesungen geben verzerrten Text zurück.

Mögliche Ursachen und Lösungen:

  • Der Spaltentyp ist VARCHAR, nicht NVARCHAR. Varchar-Spalten verwenden eine Codepage, nicht Unicode. Verwenden Sie nvarchar für internationalisierten Text.

  • Fehlt der Hinweis zur UTF-8-Codierung auf PDO_SQLSRV. Wenn deine SQL Server-Spalte nvarchar ist und deine PHP-Daten UTF-8, sag dem Treiber, er soll zwischen UTF-8 (Client) und UTF-16 (Server) konvertieren:

    <?php
    $conn = new PDO(
        "sqlsrv:Server=<server>;Database=<database>;Encrypt=true",
        $user,
        $password,
        [
            PDO::ATTR_ERRMODE                    => PDO::ERRMODE_EXCEPTION,
            PDO::SQLSRV_ATTR_ENCODING            => PDO::SQLSRV_ENCODING_UTF8,
        ]
    );
    
  • SQLSRV-Treiber: Fordern Sie explizit UTF-8 an. SQLSRV_ENC_CHAR ist die Standard-8-Bit-Systemcodepage, nicht UTF-8. Für UTF-8 mit SQLSRV setzen "CharacterSet" => "UTF-8" Sie auf die Verbindung und geben Sie das Literal 'UTF-8' an SQLSRV_PHPTYPE_STRING beim Fetch oder Binden weiter. Siehe Senden und abrufen von UTF-8-Daten.

Fehler bei Date-Time-Umrechnungen

Symptome:

SQLSTATE[22007]: Invalid character value for cast specification

Korrektur:

Binde PDO_SQLSRV kein rohes DateTime Objekt. PDO stringifiziert gebundene Werte vor der Bindung, und PHP DateTime hat keine Methode __toString() , daher execute([new DateTime(...)]) erhöht Object of class DateTime could not be converted to string. Formatiere zuerst den Wert oder übergebe eine ISO-8601-Zeichenkette (YYYY-MM-DD HH:MM:SS[.fff]), nicht eine lokalformatierte Zeichenkette.

<?php
$stmt = $conn->prepare("INSERT INTO dbo.Events (EventDate) VALUES (?)");
$stmt->execute([(new DateTime("2026-03-15 10:00:00"))->format("Y-m-d H:i:s.u")]);

Um Datetime-Spalten als DateTime Objekte statt Strings auf PDO_SQLSRV abzurufen, setzen Sie das Statement-Attribut:

<?php
$stmt = $conn->prepare("SELECT EventDate FROM dbo.Events");
$stmt->setAttribute(PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE, true);
$stmt->execute();

Details finden Sie unter Datetime-Objekte abrufen (PDO_SQLSRV).

Dezimalformatierungsprobleme

Symptome:

Werte zwischen -1 und 1 fehlen eine führende Null, oder Geld- und Smallmoney-Werte zeigen eine unerwartete Anzahl von Dezimalstellen.

Korrektur:

PDO_SQLSRV holt immer Dezimal - und Zahlenwerte als Zeichenketten mit ihrer exakten Präzision und Skala. Setzen Sie PDO::SQLSRV_ATTR_FORMAT_DECIMALS so ein, dass eine führende Null zu Werten zwischen -1 und 1 hinzugefügt wird:

<?php
$conn->setAttribute(PDO::SQLSRV_ATTR_FORMAT_DECIMALS, true);

PDO::SQLSRV_ATTR_DECIMAL_PLACES gilt nur für Geld- und Kleingeldwerte . Es setzt die angezeigte Skala von 0 bis 4 und kann den angezeigten Wert abrunden. Sie beeinflusst keine Dezimal - oder Zahlenwerte .

Für Details siehe Format Decimals and money (PDO_SQLSRV) oder Format decimals and money (SQLSRV).

Transaktionsprobleme

Datenänderungen bleiben nicht bestehen

Symptome:

Zeilen, die du in PHP einfügst oder aktualisierst, erscheinen nicht, wenn du aus einer anderen Sitzung abfragst.

Ursache:

PDO::beginTransaction() öffnet eine explizite Transaktion, die eine explizite commit()Transaktion erfordert. Wenn das PHP-Skript ohne Aufruf commit()endet, rollt PDO die Transaktion während der Verbindungsreinigung zurück.

Korrektur:

Immer mit koppeln beginTransaction() und bei Fehler zurückrollencatchtry/:commit()

<?php
try {
    $conn->beginTransaction();
    $conn->exec("INSERT INTO dbo.Orders (CustomerID, Total) VALUES (1, 100)");
    $conn->exec("UPDATE dbo.Inventory SET Stock = Stock - 1 WHERE ProductID = 5");
    $conn->commit();
} catch (PDOException $e) {
    $conn->rollBack();
    throw $e;
}

Für SQLSRV verwenden sqlsrv_begin_transactionSie , sqlsrv_commit, und sqlsrv_rollback.

Deadlock-Fehler

Symptome:

SQLSTATE[40001]: [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Transaction (Process ID 62) was deadlocked

Korrektur:

Behandle vorübergehende Deadlock-Fehler mit Retry-Logik. Wrappe die gesamte Transaktion (nicht nur die fehlerhafte Anweisung), damit frühere Anweisungen auf der frischen Transaktion abgespielt werden. Für ein produktionsorientiertes Wiederholungsmuster siehe das Beispiel auf der PHP-Treiber-Landingpage.

Wiederholende Deadlocks deuten auf ein Designproblem hin. Erfassen Sie den Deadlock-Graphen und analysieren, welche Anweisungen und Sperrtypen beteiligt sind. Gängige Lösungen umfassen die Umordnung von Operationen, sodass konkurrierende Transaktionen Sperren in derselben Reihenfolge erhalten, die Verringerung des Transaktionsumfangs sowie das Hinzufügen von Indizes zur Verkürzung der Sperrdauer. Für eine vollständige Anleitung siehe Deadlocks-Leitfaden.

Probleme der Verbindungsresilienz

Eine Wiederverbindung passiert nicht

Symptome:

Eine Idle-Verbindung bleibt nach einem Failover der Azure SQL-Datenbank unterbrochen, obwohl du und gesetzt ConnectRetryCount hastConnectRetryInterval.

Mögliche Ursachen und Lösungen:

  • Aktiver serverseitiger Cursor. Die Widerstandsfähigkeit der Leerlaufverbindung stellt nur wieder Verbindungsverbindungen für Leerlaufverbindungen her. Ein offener serverseitiger Cursor oder eine ausstehende Transaktion hält die Verbindung aktiv. Freie serverseitige Cursor durch Verwendung sqlsrv_free_stmt() von oder $stmt = null; (PDO) vor dem Failover-Fenster oder durch Wechsel zu einem clientsseitigen gepufferten Cursor. Siehe Inaktiv-Verbindungs-Resilienz.
  • Zustand der nicht wiederherstellbaren Sitzung. Einige Sitzungszustände können nicht wiederhergestellt werden, einschließlich temporärer Tabellen, globalen und lokalen Cursors, Transaktionskontext, Anwendungssperren, EXECUTE AS/REVERTOLE-Automatisierungshandles, vorbereiteten XML-Handles und Trace-Flags. Jeder dieser Sitzungszustände verhindert eine automatische Wiederverbindung.
  • LoginTimeout zu klein. Wenn ConnectRetryCount * ConnectRetryInterval > LoginTimeout, hört der Treiber auf, es erneut zu versuchen, wenn LoginTimeout erreicht ist. Erhöhen Sie die Erhöhung LoginTimeout , um das gesamte Budget für Wiederversuche zu decken.

Leistungsprobleme

Für Diagnose und Behebung von langsamen Abfragen, Kaltstarts, großen Ergebnissets und Bulk-Inserts siehe Performance tuning.

Treiberdiagnostik aktivieren

Wenn Anrufe auf Anwendungsebene error_log() nicht genügend Informationen liefern, aktivieren Sie die Fahrerseiten-Protokollierung. Es meldet jeden ODBC-Anruf, den der Fahrer tätigt.

PDO_SQLSRV

Setze pdo_sqlsrv.log_severity den Webserver ein php.ini und starte ihn neu. Diese Einstellung ist nur bei der Initialisierung lesbar:

[pdo_sqlsrv]
pdo_sqlsrv.log_severity = 1

Die Werte sind 0 (ausgeschaltet, der Standard), -1 (Fehler, Warnungen und Hinweise), 1 (Fehler), (Warnungen 2 ) und 4 (Hinweise).

SQLSRV

Aktiviere das Logging zur Laufzeit mit sqlsrv_configure():

<?php
sqlsrv_configure("LogSubsystems", SQLSRV_LOG_SYSTEM_CONN | SQLSRV_LOG_SYSTEM_STMT);
sqlsrv_configure("LogSeverity", SQLSRV_LOG_SEVERITY_ERROR | SQLSRV_LOG_SEVERITY_WARNING);

Logeinträge gehen in die von in php.inikonfigurierte error_log Datei. Für die vollständige Liste der Teilsysteme und Schweregrade siehe Logging von Aktivitäten.

Container- und CI-Probleme

Fehlende Systembibliotheken unter Linux

Symptome:

error while loading shared libraries: libodbc.so.2: cannot open shared object file
error while loading shared libraries: libssl.so.1.1: cannot open shared object file

Korrektur:

Installiere die Laufzeitabhängigkeiten, bevor du den PHP-Treiber installierst:

Verteilung Installationsbefehl
Ubuntu und Debian sudo apt-get install unixodbc libgssapi-krb5-2
Red Hat und Fedora sudo dnf install unixODBC krb5-libs
Alpine apk add unixodbc gcompat

Dann installiere msodbcsql18 es aus dem Microsoft-Paket-Repository. Für distribution-spezifische Paket-Repositories und Versionen siehe die ODBC-Treiberinstallationsanleitung.

Docker-Image-Builds sind erfolgreich, aber die Verbindungen scheitern zur Laufzeit

Symptome:

Das Image wird erstellt und PHP startet, wirft PDO::__construct() aber einen ODBC-Treiber-nicht-gefunden-Fehler.

Korrektur:

Überprüfen Sie, ob der ODBC-Treiber im Laufzeit-Image installiert ist, nicht nur in der Build-Phase. Installiert msodbcsql18 und unixodbc-dev befindet sich in derselben Phase, die in die Produktion geht. Bei einem mehrstufigen Bau installieren Sie sie in der Endstufe. Eine einstufige Debian-basierte Installation sieht so aus:

# Pin to a specific PHP minor version in production, for example php:8.4.11-cli.
FROM php:8.4-cli
RUN apt-get update && apt-get install -y --no-install-recommends \
        curl gnupg2 apt-transport-https ca-certificates \
    && curl -sSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /usr/share/keyrings/microsoft.gpg \
    && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft.gpg] https://packages.microsoft.com/debian/12/prod bookworm main" > /etc/apt/sources.list.d/mssql-release.list \
    && apt-get update \
    && ACCEPT_EULA=Y apt-get install -y --no-install-recommends msodbcsql18 unixodbc-dev \
    # $PHPIZE_DEPS ships in the official php image and includes gcc, make, autoconf, and re2c.
    && apt-get install -y --no-install-recommends $PHPIZE_DEPS \
    && pecl install sqlsrv pdo_sqlsrv \
    && docker-php-ext-enable sqlsrv pdo_sqlsrv \
    && apt-get purge -y --auto-remove $PHPIZE_DEPS \
    && rm -rf /var/lib/apt/lists/*