A Microsoft SQL Serverhez készült PHP-illesztőprogramjainak hibaelhárítása

PHP-illesztőprogram letöltése

Diagnosztizáld és oldd meg a gyakori problémákat, amikor a Microsoft Drivers for PHP for SQL Server segítségével csatlakozol az SQL Server-hez, Azure SQL Database-hez, Azure SQL Managed Instance-hoz és SQL database-hez Microsoft Fabric.

Általános hiba- és figyelmeztetéskezelési mintákért lásd: Kezelési hibák és figyelmeztetések. Az illesztőprogram-oldali diagnosztikai adatok rögzítésével kapcsolatban lásd: Naplózási tevékenység.

Telepítési problémák

A kiterjesztés nincs betöltve

Tünetek:

  • phpinfo() nem sorol fel sqlsrv vagy pdo_sqlsrv szakaszt.
  • PDOException: could not find driver egy PDO létrehozásakor a sqlsrv: DSN használatával.
  • Fatal error: Uncaught Error: Call to undefined function sqlsrv_connect().

Lehetséges okok és megoldások:

  • A kiterjesztés nincs engedélyezve a php.ini fájlban. Ellenőrizd, hogy a extension=sqlsrv és a extension=pdo_sqlsrv egyaránt nincs kikommentelve. Windows-on használd a teljes fájlnevet (extension=php_sqlsrv_84_ts_x64.dll). Részletekért lásd: A driverek betöltése.
  • Rossz menetes biztonsági build. Az illesztőprogram bináris fájljának meg kell egyeznie a PHP-build szálbiztonsági beállításával (ts szálbiztoshoz, nts nem szálbiztoshoz). Futtassa php -i | grep "Thread Safety" az ellenőrzéshez. Töltsd le a megfelelő bináris fájlt a letöltési oldalról.
  • Microsoft ODBC drivere hiányzik. A PHP illesztőprogramok a Microsoft ODBC Driver for SQL Server köré épülnek. Linuxon és macOS-en telepíts msodbcsql18 (vagy msodbcsql17) a csomagkezelőddel, mielőtt betöltöd a bővítményeket. Windows-on telepítsd az ODBC illezőprogramot a letöltési oldalról.

Ellenőrizd a sikeres telepítést:

php -m | grep -i sqlsrv

A kimenetben mind a pdo_sqlsrv-nak, mind a sqlsrv-nek meg kell jelennie.

A PECL vagy PIE telepítés megbukik Linuxon vagy macOS-en

Tünetek:

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

Javítás:

Telepítsd az ODBC fejlesztői fejléceket az illesztőprogramok telepítése előtt:

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

Apple siliconon a fejlécek önmagukban nem elegendőek. A Homebrew az unixODBC-t a /opt/homebrew alá telepíti, ami nem része a fordító alapértelmezett keresési útvonalának, ezért a build ugyanazzal a hibával meghiúsul, még akkor is, ha a fejlécfájlok is jelen vannak. Állítsd be a fordító zászlókat, mielőtt újra próbálkozol:

export CPPFLAGS="-I/opt/homebrew/opt/unixodbc/include/"
export LDFLAGS="-L/opt/homebrew/lib/"

Majd próbálkozz újra PIE-vel:

pie install microsoft/sqlsrv
pie install microsoft/pdo_sqlsrv

Vagy a PECL-rel:

sudo pecl install sqlsrv
sudo pecl install pdo_sqlsrv

Ha a telepítés még mindig kudarcot vall a fejlécek telepítése után, az építőeszköz-lánc hiányos lehet. Telepítsd phpize, re2c, és egy C++ fordítót (build-essential Debianon és Ubuntun, gcc-c++ make Red Haten és Fedorán, build-base Alpine-on). A PIE felajánlja, hogy telepítheti a hiányzó build-eszközöket Linuxon és macOS-en.

A teljes telepítési útvonalért lásd a Linux és macOS telepítési útmutatóját.

Több PHP verzió telepítve

Tünetek:

phpinfo() a webszerveren egy adott PHP-verziót mutat, de php -v a parancssorban egy másikat, és az illesztőprogram csak az egyikben tűnik betöltöttnek.

Javítás:

Minden PHP verziónak megvan a maga php.ini és ext a könyvtára. Keresd meg a megfelelő konfigurációs fájlt php --ini abban a környezetben, ahol hiányzik az illesztőprogram, és add hozzá a extension= sorokat oda. Indítsd újra a webszervert (Apache, Nginx + PHP-FPM vagy IIS) bármilyen php.ini változás után.

Csatlakozási problémák

Nem tudok csatlakozni a szerverhez

Tünetek:

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

Lehetséges okok és megoldások:

  • A szerver nem elérhető. Ellenőrizd, hogy a szerver neve és a port helyes-e. A PHP hosztról teszteld a nyers TCP kapcsolatot.

    # Linux and macOS
    nc -vz <server>.database.windows.net 1433
    
    # Windows PowerShell
    Test-NetConnection -ComputerName <server>.database.windows.net -Port 1433
    
  • A tűzfal blokkolja a 1433-as kimenő vonalat. Vállalati tűzfalak és felhőalapú NSG-k gyakran blokkolják a 1433-as kimenő portot. Adj meg kivételt, vagy engedélyezd az Azure SQL Database IP tartományokat a régiódban.

  • Azure SQL server firewall. Csatolja az ügyfele nyilvános IP-címét a szerverszintű tűzfal szabályaihoz az Azure portálban.

  • Elnevezett példány. Elnevezett példány esetén ellenőrizd, hogy az SQL Server Browser szolgáltatás fut-e a kiszolgálón, és hogy az 1434-es UDP-port nyitva van-e. Vagy csatlakozzon port használatával példánynév helyett.

A bejelentkezés sikertelen

Tünetek:

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

Lehetséges okok és megoldások:

  • Az SQL hitelesítési mód letiltva. A helyi SQL Server példányok alapértelmezetten csak a Windows hitelesítést használják. Engedélyezze a vegyes módú hitelesítést az SQL Server Management Studio-ban a Server properties>Security alatt, majd indítsa újra az SQL Server szolgáltatást.
  • Azure SQL credentials format. Az Azure SQL-hez a teljes minősítésű felhasználónév (user@servername) szükséges, amikor olyan eszközökből csatlakozunk, amelyek nem csatolják automatikusan hozzá.
  • A felhasználó nincs adatbázishoz rendelve. Ellenőrizd, hogy a bejelentkezésnek van felhasználói leképezése a cél adatbázisban, és hogy a felhasználónak megvannak a szükséges jogosultságai.
  • Preferálom a Microsoft Entra ID-t. Azure SQL, Azure SQL Managed Instance és SQL database Fabric-ben használjunk Microsoft Entra hitelesítést (Authentication=ActiveDirectoryMsi, Authentication=ActiveDirectoryServicePrincipal, vagy access tokent) SQL bejelentkezések helyett. Lásd : Csatlakozás Microsoft Entra-hitelesítéssel.

Érvénytelen érték a kapcsolati karakterlánc attribútumához 'Authentication'

Tünetek:

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

Ok:

Az ODBC-illesztőprogram jelzi a hibát, de a valódi probléma az, hogy a PDO_SQLSRV melyik illesztőprogramhoz van kötve. Ha a DSN nem tartalmaz Driver= kulcsszót, és a hoszt telepítve van ODBC 17 és ODBC 18 is, akkor PDO_SQLSRV kapcsolódhat a régebbi verzióhoz. A régebbi ODBC 17.x kiadások nem ismerik az újabb Authentication értékeket, például a ActiveDirectoryServicePrincipal vagy a ActiveDirectoryDefault értéket, és még a ActiveDirectoryMsi is csak az ODBC 17.3.1.1-es vagy újabb verziótól érhető el.

Javítás:

Rögzítse az illesztőprogramot a DSN-ben:

<?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]);

A zárójeles alak ({ODBC Driver 18 for SQL Server}) kilép a meghajtó nevében lévő közközökből. Maga a hibaüzenet mindig megnevezi azt az illesztőprogramot, amely jelezte a hibát, így a hibaüzenetben szereplő [Microsoft][ODBC Driver 17 for SQL Server] előtag a leggyorsabb módja annak megerősítésére, hogy nem a megfelelő illesztőprogram kapcsolódott hozzá.

A DSN stringben az érvénytelen 'UID' kulcsszó volt megadva

Tünetek:

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

Ok:

A PDO_SQLSRV csak az engedélyezett DSN-kulcsszavakat fogadja el, és nem fogadja el a DSN-ben a UID vagy a PWD elemet. A PDO a második és harmadik konstruktorargumentumot erre a célra fenntartja, a PDO_SQLSRV pedig ezeket belsőleg ODBC UID/PWD értékekre fordítja.

Javítás:

Mozgasd át a felhasználónevet (és jelszót az SQL hitelesítéshez) a PDO konstruktorba:

<?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);

Az SQLSRV eljárásalapú illesztőprogram ezzel szemben elfogadja a sqlsrv_connect() függvénynek átadott kapcsolódási beállításokat tartalmazó tömbben a UID és PWD elemeket.

PDO_SQLSRV csendben figyelmen kívül hagyja az AccessToken-t az opciók tömbjében

Tünet:

Van egy Microsoft Entra hozzáférési tokened (például , az account get-access-token --resource https://database.windows.net/ManagedIdentityCredential, vagy ClientSecretCredential), és azt továbbítod PDO_SQLSRV-nek, mint ['AccessToken' => $token] a negyedik konstruktor érvelésben. A kapcsolódási kísérlet egy félreérthető hibaüzenettel, például Windows logins are not supported in this version of SQL Server vagy Login failed for user '' üzenettel meghiúsul, mintha nem adtak volna meg hitelesítő adatokat.

Ok:

A PDO negyedik konstruktorparamétere az illesztőprogram-specifikus attribútumkonstansok számára van fenntartva (egész szám típusú kulcsok, például PDO::ATTR_ERRMODE). A PDO csendben dobja el a string-kulcsos bejegyzéseket, mint AccessTokenpéldául , így PDO_SQLSRV soha nem látja a tokent. A kapcsolat ezután visszakerül a Windows integrált hitelesítésre, amit a szerver elutasít.

Javítás:

Helyezze át a(z) AccessToken elemet a DSN-karakterláncba. Tartsd fenn az opciótömböt a PDO::ATTR_* konstansok számára.

<?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,
]);

További Microsoft Entra hitelesítési példákért, beleértve a DSN űrlapot PDO_SQLSRV lásd: Kapcsolódj Microsoft Entra hitelesítés segítségével.

Az SQLSRV procedurális API esetén a AccessToken a sqlsrv_connect() függvénynek átadott kapcsolatinformációs tömbbe tartozik, amely helyetted a nyers JWT-t SQL_COPT_SS_ACCESS_TOKEN-be ágyazza be:

<?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 tanúsítvány hibák

Tünetek:

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

Megoldások:

Inkább megbízható tanúsítványt preferálok. TrustServerCertificate=true Csak helyi fejlesztésre használd egy olyan szerver ellen, amit te irányítasz.

Önként aláírt tanúsítvány elleni fejlesztéshez:

<?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,
]);

Figyelmeztetés

TrustServerCertificate=true Letiltja a szerver tanúsítvány ellenőrzését. Soha ne vigye ezt a környezetet a gyártásba, a színpadi vagy megosztott környezetbe.

Ha az éles hosztnév nem egyezik meg a tanúsítvány Common Name (CN) mezőjével (például ha figyelőn keresztül csatlakozik), adja meg a tanúsítvány tényleges alanyát:

<?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,
]);

Kapcsolati időkorlát

Tünetek:

SQLSTATE[HYT00]: Login timeout expired

Lehetséges okok és megoldások:

  • LoginTimeout Nem állítva vagy túl alacsonyan a hideg failoverhez. Állíts be egy explicit LoginTimeout értéket (másodpercben) a DSN-ben az Azure SQL-hez való csatlakozáskor. A feladatátvételi csoportok feladatátvétele és a hidegen indított adatbázisok több időt vehetnek igénybe, mint amennyit egy rövid ügyféloldali időtúllépés lehetővé tesz. Az opció hivatkozásáért lásd a Csatlakozási opciókat .
  • Alapjárati újrakapcsolás költségvetése lerövidítve. Ha beállítod ConnectRetryCount és ConnectRetryInterval, győződj meg LoginTimeout >= ConnectRetryCount * ConnectRetryIntervalróla. Ellenkező esetben a bejelentkezési időkorlát korán véget vet a visszakapcsolási ciklusnak. Lásd: Tétlen kapcsolati rezisztens.
<?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,
]);

Lekérdezés végrehajtási problémái

Csendes hibák a PDO használata során

Tünet:

A PDO::exec() vagy PDOStatement::execute() hívás false értéket ad vissza, de nem dob kivételt.

Javítás:

A PHP 8.0-s és újabb verziókban az alapértelmezett PDO hibamód a PDO::ERRMODE_EXCEPTION. Ha egy hívás visszatér false küldés nélkül, az alkalmazás megváltoztatja a módot vagy PDO::ERRMODE_SILENTPDO::ERRMODE_WARNING-re. Állítsuk vissza kivételmódba, hogy a hibák kivételt váltsanak ki:

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

Ha nem tudod globálisan megváltoztatni a módot, ellenőrizd $conn->errorInfo() (vagy $stmt->errorInfo()) minden hívás után. A tömb tartalmazza [SQLSTATE, driver code, driver message].

Érvénytelen objektumnév

Tünetek:

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

Lehetséges okok és megoldások:

  • Rossz adatbázis kontextus. Ellenőrizd egy gyors lekérdezéssel:

    <?php
    $stmt = $conn->query("SELECT DB_NAME()");
    echo $stmt->fetchColumn();
    
  • Hiányzik a séma kvalifikátor. Használj teljesen minősített neveket, hogy ne a hívó alapértelmezett sémájától függj:

    SELECT * FROM dbo.Products;
    
  • Kiszámíthatóság érzékenysége. A kis- és nagybetűket megkülönböztető rendezéssel létrehozott adatbázisok a(z) products és Products elemeket különböző objektumokként kezelik. Egyeztess pontosan a táblázat definíciójában szereplő esetet.

Rossz számú paraméter

Tünetek:

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

Javítás:

PDO_SQLSRV esetén a ? helykitöltők számának egyeznie kell a execute() számára átadott értékek számával, és minden ? egyetlen skalár értéket köt hozzá (nem tömböt). A nevelt paraméterekhez az SQL-ben minden :name szereplőnek meg kell jelennie a tömbben, és fordítva.

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

SQLSRV esetén adja át a paramétertömböt a(z) sqlsrv_query() vagy sqlsrv_prepare() függvénynek:

<?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));
}

A paraméterkötés szélesebb körű bevezetéséért lásd: Paraméterezett lekérdezések végrehajtása.

A PDO emulált előkészíti a maszkhibákat

Tünetek:

Egy utasítás sikeresen lefut az egyik kapcsolatban, de egy másik, ugyanazt a lekérdezésszöveget használó kapcsolatban szintaktikai hibát eredményez.

Ok:

PDO_SQLSRV támogatja mind az emulált, mind a natív előkészített állításokat. Az emulált előkészített utasítások (PDO::ATTR_EMULATE_PREPARES = true) kliensoldalon interpolálják a paramétereket. A natív előkészíti (false) a lekérdezést és a paramétereket külön elküldi a szervernek. A viselkedés eltér a TOP (?), a táblázatértékű paraméterek és a típuskonverzió egyes szélső esetei esetében.

Javítás:

Előnyben részesítem a termelés során lévő őshonos készítményeket. A csatlakozási időre állítsuk PDO::ATTR_EMULATE_PREPARES => false be, hogy a viselkedés konzisztens legyen a környezetek között:

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

Az egyes módok használatának részleteiről lásd: PDO::prepare.

Adattípus-problémák

Unicode karakterek úgy jelennek meg, mint ? vagy zavaros módon

Tünetek:

A PHP által írt sorok kérdőjeleket vagy helyettesítő karaktereket tartalmaznak az eredeti nem ASCII karakterek helyett. Az olvasási műveletek értelmezhetetlen szöveget eredményeznek.

Lehetséges okok és megoldások:

  • Az oszlop típusa VARCHAR, nem NVARCHAR. a varchar oszlopok kódlapot használnak, nem Unicode-ot. Használd a nvarchart nemzetköziített szöveghez.

  • Hiányzik az UTF-8 kódolási tipp PDO_SQLSRV-n. Ha az SQL Server oszlopod nvarchar, és a PHP adataid UTF-8, mondd meg a drivernek, hogy konvertáljon UTF-8 (kliens) és UTF-16 (szerver) között:

    <?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 illesztőprogram: az UTF-8 explicit kérése. SQLSRV_ENC_CHAR az alapértelmezett 8 bites rendszerkód oldal, nem az UTF-8. UTF-8 SQLSRV használatakor állítsd be a(z) "CharacterSet" => "UTF-8" értéket a kapcsolaton, és lekéréskor vagy kötéskor add át a(z) 'UTF-8' literált a(z) SQLSRV_PHPTYPE_STRING számára. Lásd: UTF-8 adatok küldése és letöltése.

Dátumidő-átalakítási hibák

Tünetek:

SQLSTATE[22007]: Invalid character value for cast specification

Javítás:

A PDO_SQLSRV esetében ne kössön nyers DateTime objektumot. A PDO a kötött értékeket a kötés előtt karakterlánccá alakítja, a PHP DateTime pedig nem rendelkezik __toString() metódussal, ezért a execute([new DateTime(...)])Object of class DateTime could not be converted to string kivételt dob. Először formázd az értéket, vagy adj át egy ISO 8601 stringet (YYYY-MM-DD HH:MM:SS[.fff]), ne egy helyi formátumú stringet.

<?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")]);

Ha a datetime oszlopokat a PDO_SQLSRV-ben karakterláncok helyett DateTime objektumként szeretné lekérni, állítsa be a következő utasításattribútumot:

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

Részletekért lásd: Dátumidő objektumok (PDO_SQLSRV) lekérése.

Tizedes formázási problémák

Tünetek:

Az -1 és 1 közötti értékekből hiányzik egy vezető nulla, vagy a pénz és a kis pénz értékek váratlan számú tizedesszámot mutatnak.

Javítás:

PDO_SQLSRV mindig tizedes és numerikus értékeket hoz be láncsorként, pontosan a pontossággal és skálával. Állítsuk PDO::SQLSRV_ATTR_FORMAT_DECIMALS be úgy, hogy vezető nullát adjunk hozzá -1 és 1 közötti értékekhez:

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

PDO::SQLSRV_ATTR_DECIMAL_PLACES csak a pénzre és a kis pénz értékekre vonatkozik. A megjelenített skálát 0-tól 4-ig állítja be, és lehet, hogy a megjelenített értéket kerekíti. Nem befolyásolja a tizedes vagy numerikus értékeket.

Részletekért lásd: Tizedesjegyek és pénzösszegek formázása (PDO_SQLSRV) vagy Tizedesjegyek és pénzösszegek formázása (SQLSRV).

Tranzakciós problémák

Az adatváltozások nem maradnak fenn

Tünetek:

A PHP-ben beszúrt vagy frissített sorok nem jelennek meg, amikor egy másik munkamenetből lekérdezi őket.

Ok:

PDO::beginTransaction() egy explicit tranzakciót nyit meg, amely explicit commit() megkövetel. Ha a PHP szkript hívás commit()nélkül végződik, a PDO visszahúzza a tranzakciót a kapcsolat tisztítása során.

Javítás:

Mindig együtt használd a(z) beginTransaction() és commit() elemeket, és hiba esetén a try/catch használatával végezz visszagörgetést:

<?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;
}

SQLSRV esetén használd sqlsrv_begin_transaction, sqlsrv_commit, és sqlsrv_rollback.

Holtzárhibák

Tünetek:

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

Javítás:

Kezeld az átmeneti deadlock hibákat újrapróbálkozás logikával. Csomagold be az egész tranzakciót (nem csak a hibás utasítást), hogy a korábbi utasítások újra lejátszódjanak az új tranzakción. A termelésorientált újrapróbálási mintához lásd a PHP driver landing oldalán található mintát.

Az ismétlődő holtpontok tervezési problémára utalnak. Rögzítsük a holtpontgráfot, és elemezzük, mely utasítások és zárolástípusok érintettek. Gyakori megoldások közé tartozik az átrendezési műveletek, hogy a versengő tranzakciók ugyanabban a sorrendben szerezzenek zárokat, a tranzakciós kör csökkentése, valamint indexek hozzáadása a zár időtartamának csökkentése érdekében. A teljes végigjátszásért lásd a Deadlocks útmutatót.

Kapcsolódási ellenállósági problémák

A visszakapcsolás nem történik meg

Tünetek:

Egy ürtelen kapcsolat hibás marad egy Azure SQL Database failover után, még akkor is, ha beállítod ConnectRetryCount és ConnectRetryInterval.

Lehetséges okok és megoldások:

  • Aktív szerveroldali kurzor. Az üresjárati kapcsolatok helyreállítása csak a tétlen kapcsolatokat csatlakoztatja újra. Egy nyitott szerveroldali kurzor vagy függőben lévő tranzakció aktívan tartja a kapcsolatot. Szabadítsa fel a szerveroldali kurzorokat a sqlsrv_free_stmt() vagy $stmt = null; (PDO) használatával a feladatátvételi időszak előtt, vagy váltson kliensoldali pufferelt kurzorra. Lásd: Tétlen kapcsolati rezisztens.
  • Nem helyreállítható munkamenetállapot. Bizonyos sessionállapotok nem állíthatók vissza, például ideiglenes táblák, globális és helyi kurzorok, tranzakciós kontextus, alkalmazászárak, EXECUTE AS/REVERTOLE automatizálási handlek, előkészített XML handle és trace flagok. Ezek közül bármelyik ülésállapot megakadályozza az automatikus újracsatlakozást.
  • LoginTimeout túl kicsi. Ha ConnectRetryCount * ConnectRetryInterval > LoginTimeout, a meghajtó felhagy az újrapróbálkozással, amikor eléri a(z) LoginTimeout értéket. Növeld LoginTimeout értékét a teljes újrapróbálkozási költségvetés fedezéséhez.

Teljesítményproblémák

A lassú lekérdezések, hidegindítások, nagy eredménykészletek és tömeges beillesztések diagnosztizálásáért és helyreállításáért lásd: Teljesítmény hangolás.

Illesztőprogram-diagnosztika engedélyezése

Ha az alkalmazásszintű error_log() hívások nem adnak elegendő információt, kapcsold be a vezetőoldali naplózást. Naplózza az illesztőprogram által végrehajtott minden ODBC-hívást.

PDO_SQLSRV

Állítsa be a(z) pdo_sqlsrv.log_severity elemet a(z) php.ini helyen, majd indítsa újra a webkiszolgálót. Ez a beállítás csak inicializációkor olvasható:

[pdo_sqlsrv]
pdo_sqlsrv.log_severity = 1

Az értékek: 0 (kikapcsolva, az alapértelmezett), -1 (hibák, figyelmeztetések és értesítések), 1 (hibák), 2 (figyelmeztetések) és 4 (értesítések).

SQLSRV

Engedélyezd a naplózást futásidőben a következőkkel: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);

A naplóbejegyzések az php.ini fájlba kerülnek, amelyet a(z) error_log állít be. Az alrendszerek és súlyosságok teljes listájáért lásd: Logolási tevékenység.

Konténer- és CI problémák

Hiányzó rendszerkönyvtárak Linuxon

Tünetek:

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

Javítás:

Telepítse a futtatókörnyezeti függőségeket, mielőtt telepítené a PHP-illesztőprogramot:

Disztribúció Parancs telepítése
Ubuntu és Debian sudo apt-get install unixodbc libgssapi-krb5-2
Red Hat és Fedora sudo dnf install unixODBC krb5-libs
Alpine apk add unixodbc gcompat

Ezután telepítsd msodbcsql18 a Microsoft csomagtárolóból. A disztribúcióspecifikus csomagtárakkal és verziókkal kapcsolatban lásd az ODBC illesztőprogram telepítési útmutatóját.

Docker képek építése sikeres, de a kapcsolatok futásidőben hibásodnak

Tünetek:

A kép beépül, és a PHP elindul, de PDO::__construct() ODBC driver-not-found hibát dob.

Javítás:

Ellenőrizd, hogy az ODBC illesztőprogram a futásidejű képben van telepítve, nem csak az építési szakaszban. Telepítsd msodbcsql18 be, unixodbc-dev és ugyanabban a szakaszban, ami a gyártásba kerül. Többfokozatú buildben a végső szakaszba szereld be őket. Egy egyfázisú Debian-alapú telepítés így néz ki:

# 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/*