Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bağlantı dayanıklılığı, sunucu ve oturum durumu kurtarmayı desteklediğinde Microsoft ODBC Driver for SQL Server'ın bozulmuş bir boşta bağlantıyı geri yüklemesini sağlar. PHP uzantıları ConnectRetryCount ve ConnectRetryInterval değerlerini ODBC'ye iletir; yeniden bağlantı protokolünü uygulamıyorlar. ODBC dokümantasyonu, SQL Server 2014 ve sonraki sürümleri, Azure SQL Veritabanı ve Microsoft Fabric'teki SQL veritabanı desteğini listeler. Fabric'te SQL veritabanı desteğinden Warehouse desteği olduğu çıkarımını yapmayın.
| Keyword | Değerler | Varsayılan | Description |
|---|---|---|---|
ConnectRetryCount |
0 ile 255 arasında tamsayı (dahil) | 1 | Vazgeçmeden önce bozuk bir bağlantıyı yeniden kurmaya yönelik en fazla deneme sayısı.
0 değeri yeniden bağlanmayı devre dışı bırakır. |
ConnectRetryInterval |
1 ile 60 arasında tamsayı (dahil) | 10 | Denemeler arasında beklenecek saniye sayısı. Eğer ConnectRetryCount ise 0 yoksayılır. |
Komutun sorgu zaman aşımı, ODBC'nin yürütme sırasında boştaki bir bağlantıyı yeniden kurmak için ne kadar zaman harcayabileceğini sınırlar. SQLSRV deyim seçeneklerinde QueryTimeout veya PDO_SQLSRV için PDO::SQLSRV_ATTR_QUERY_TIMEOUT ayarlayın.
LoginTimeout bağlantı kurmayı kontrol eder; artırmak, ifadenin kurtarma bütçesini uzatmaz.
Aynı yeniden deneme anahtar sözcüklerini, örneğin ["ConnectRetryCount" => 2, "ConnectRetryInterval" => 5], SQLSRV bağlantı seçenekleri dizisinde veya PDO_SQLSRV veri kaynağı adında (DSN), örneğin ConnectRetryCount=2;ConnectRetryInterval=5, ayarlayın. Bu ayarlar başarısız bir işlemi tekrar oynatmaz veya uygulamanın ilk bağlantı çağrısını yeniden denemez
Bir sorgu yürütülürken ortaya çıkan geçici hataların uygulama düzeyinde yeniden denenmesi için (boşta bağlantı dayanıklılığı bunu kapsamaz), Microsoft Drivers for PHP for SQL Server içindeki yeniden deneme desenine bakınız.
Kurtarma ilkesini seçin
Boşta bağlantı kurtarma, uygulamanın PHP bağlantı tanıtıcısını kullanmaya devam edebilmesi için geri alınabilir bir oturumu korur. Bir komutu tekrar çalıştırmak genel bir talimat değildir.
| Failure | Boştaki bağlantı dayanıklılığı bunun üstesinden gelir mi? | Uygulama işlemi |
|---|---|---|
| İlk bağlantı kurulamıyor | No. Geri yüklenecek belirlenmiş bir oturum yok. | Bağlantı hatasını inceleyin. Yalnızca geçici bir hatayı sınırlı bir ilkeyle yeniden deneyin. |
| Etkin olmayan, kurtarılabilir bir bağlantı kesiliyor | ODBC, bağlantı tekrar kullanıldığında kurtarma girişiminde bulunabilir. | Hedeflenen kurtarma denemeleri için yeterli statement zaman aşımı tanı; yine de nihai bir başarısızlığı yönetin. |
| Bir deyim yürütme sırasında başarısız olur | Kurtarma veya tekrar oynatma varsayımında bulunmayın. | Hatayı inceleyin ve işlemin tamamlanıp tamamlanmadığını belirleyin. Yalnızca yinelemenin uygulamanız için kabul edilebilir olduğu durumlarda okumayı yeniden deneyin. |
| Bir işlem sırasında bağlantı kesilir | İşlemin devam edebileceğini varsaymayın. | Bozuk oturumu bırakın ve işlemi gerçekleştirip yapmadığınızı belirleyin, sonra başka bir denemeye karar verin. |
| İstemci açıkça PHP bağlantısını kapatır | No. Bir tutamacı kapatmak uygulama temizliğidir, boşta bir bağlantı kesmesi değil. | Daha fazla iş gerekirse yeni bir bağlantı açın. |
İyileşme aralıklarını ve sorgu zaman aşımı sürelerini tutarlı tutun. Örneğin, programlar 5 saniyelik aralık ve 30 saniyelik bir ifade zaman aşımıyla iki yeniden bağlantı girişimi kullanır. Bağlantı girişimleri de zaman alır; sayıyı aralıkla çarpmak garanti edilen toplam toparlanma süresi değildir. Nihai bir zaman aşımı durumunda da hata işleme gerekir.
Açıklamalar
Bağlantı dayanıklılığı yalnızca bağlantı boş olduğunda geçerlidir. İşlem sırasında bir arıza yeniden bağlantıyı tetiklemez. Aşağıdaki oturum durumları da yeniden bağlanmayı engeller:
- Geçici masalar.
- Küresel ve yerel imleçler.
- İşlem bağlamı ve oturum düzeyinde işlem kilitleri.
- Uygulama kilitleri.
-
EXECUTE AS/REVERTGüvenlik bağlamı. - Object Linking and Embedding (OLE) otomasyon handles.
- Hazırlanmış Genişletilebilir İşaretleme Dili (XML) tanıtıcıları.
- İzleme bayrakları.
Example
Her program, bir test SQL Server örneğine iki bağlantı açar. İkinci bağlantı, ilk oturumu KILL ile sonlandırır. İlk bağlantıda yapılan sonraki bir sorgu, ODBC'nin boşta bağlantı kurtarmasını test eder. Sorgu, satır içi satırlar kullanır, bu yüzden tablo kurulumu gerekmez. Programlar, bağlantıyı kesmeden önce her bir ifadeyi serbest bırakır ve hem geri alınan sorgunun değerlerini hem de değişen sunucu oturum açma zamanını doğrular. Sadece bir oturum kimliği kurtarma kanıtı değildir çünkü SQL Server onu tekrar kullanabilir.
Caution
Bu örneği yalnızca bir test örneğinde çalıştırın. Oturumu KILL ile sonlandırmak için oturum açma hesabının izne sahip olması gerekir. Kod sadece yeni açtığı oturumu sonlandırıyor. Başka bir uygulamanın oturum kimliğini kullanmayın.
Süreç ortamında SQL_DATABASE, SQL_USER, SQL_PASSWORD ve SQL_SERVER ayarlayın. Adı SQL_SERVER ile eşleşen güvenilir bir sunucu sertifikası yapılandırın. Bu örnek, bir test SQL Server örneğine bağlanmak için SQL kimlik doğrulamasını kullanır. Bu bir Fabric veya yönetilen kimlik doğrulama örneği değildir.
Gerçek veritabanı adı, kullanıcı adı ve şifreyi ortam değişkenlerinde sakla. Her bir program, PHP sürücüsünün ODBC tarzı bağlantı işleme yöntemi için, kapanış küme parantezlerini iki katına çıkararak ve her değeri küme parantezleri içine alarak bu değerleri bir kez escape eder. Her iki bağlantı da kaçışlı değerleri tekrar kullanır.
SQLSRV
Programı recover-sqlsrv.php olarak kaydedin ve php recover-sqlsrv.php çalıştırın. Yardımcı işlev, SQLSRV başarısız olursa hata fırlatır; hiçbir uygulama ifadesini tekrar denemez
<?php
function requireSqlsrv($result)
{
if ($result === false) {
throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
return $result;
}
$config = [];
foreach (['SQL_SERVER', 'SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$value = getenv($name);
if ($value === false || $value === '') {
throw new RuntimeException("Set $name before running this example.");
}
$config[$name] = $value;
}
foreach (['SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$config[$name] = '{' . str_replace('}', '}}', $config[$name]) . '}';
}
$connectionInfo = [
'Database' => $config['SQL_DATABASE'],
'UID' => $config['SQL_USER'],
'PWD' => $config['SQL_PASSWORD'],
'Encrypt' => true,
'TrustServerCertificate' => false,
'LoginTimeout' => 30,
'ConnectRetryCount' => 2,
'ConnectRetryInterval' => 5,
];
$conn = requireSqlsrv(sqlsrv_connect($config['SQL_SERVER'], $connectionInfo));
$breaker = null;
try {
$breaker = requireSqlsrv(sqlsrv_connect($config['SQL_SERVER'], $connectionInfo));
$sessionQuery = "SELECT @@SPID AS SessionId, "
. "CONVERT(varchar(33), login_time, 126) AS LoginTime "
. "FROM sys.dm_exec_sessions WHERE session_id = @@SPID";
$idStatement = requireSqlsrv(sqlsrv_query($conn, $sessionQuery));
$before = requireSqlsrv(sqlsrv_fetch_array($idStatement, SQLSRV_FETCH_ASSOC));
sqlsrv_free_stmt($idStatement);
if (!is_array($before) || !is_int($before['SessionId']) || $before['SessionId'] <= 0) {
throw new RuntimeException('Expected the current session identity.');
}
$spid = $before['SessionId'];
$query = 'SELECT id FROM (VALUES (1), (2), (3)) AS Demo(id) ORDER BY id';
$options = ['Scrollable' => SQLSRV_CURSOR_CLIENT_BUFFERED, 'QueryTimeout' => 30];
$stmt = requireSqlsrv(sqlsrv_query($conn, $query, [], $options));
if (requireSqlsrv(sqlsrv_num_rows($stmt)) !== 3) {
throw new RuntimeException('Expected three rows before the disconnect.');
}
sqlsrv_free_stmt($stmt);
// KILL doesn't accept a parameter marker; $spid is a checked server-returned integer.
$kill = requireSqlsrv(sqlsrv_query($breaker, 'KILL ' . $spid));
sqlsrv_free_stmt($kill);
// Allow the simulated disconnect to reach the client before the next query.
sleep(1);
$stmt = requireSqlsrv(sqlsrv_query($conn, $query, [], $options));
$ids = [];
while (($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) !== null) {
$row = requireSqlsrv($row);
$ids[] = $row['id'];
}
if ($ids !== [1, 2, 3]) {
throw new RuntimeException('Unexpected recovered rows or PHP types.');
}
sqlsrv_free_stmt($stmt);
$idStatement = requireSqlsrv(sqlsrv_query($conn, $sessionQuery));
$after = requireSqlsrv(sqlsrv_fetch_array($idStatement, SQLSRV_FETCH_ASSOC));
sqlsrv_free_stmt($idStatement);
if (!is_array($after) || $after['LoginTime'] === $before['LoginTime']) {
throw new RuntimeException('Expected a new physical session.');
}
echo "Recovered connection: 3 matching rows; login time changed.\n";
} finally {
if (is_resource($breaker)) {
sqlsrv_close($breaker);
}
sqlsrv_close($conn);
}
PDO_SQLSRV
Bu ayrı programı recover-pdo.php olarak kaydedin ve php recover-pdo.php öğesini aynı ortam ve izinlerle çalıştırın. Sayısal veri getirmeyi açıkça ayarlıyor, böylece tam sayı doğrulamaları SQLSRV programıyla eşleşiyor. PDO'da sqlsrv_errors() çağrısı yoktur; istisna modunda işlem hataları PDOException fırlatır.
<?php
$config = [];
foreach (['SQL_SERVER', 'SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$value = getenv($name);
if ($value === false || $value === '') {
throw new RuntimeException("Set $name before running this example.");
}
$config[$name] = $value;
}
foreach (['SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
$config[$name] = '{' . str_replace('}', '}}', $config[$name]) . '}';
}
$server = $config['SQL_SERVER'];
$database = $config['SQL_DATABASE'];
$dsn = "sqlsrv:Server=$server;Database=$database;Encrypt=true;"
. "TrustServerCertificate=false;LoginTimeout=30;"
. "ConnectRetryCount=2;ConnectRetryInterval=5";
$attributes = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE => true,
PDO::SQLSRV_ATTR_QUERY_TIMEOUT => 30,
];
$pdo = new PDO($dsn, $config['SQL_USER'], $config['SQL_PASSWORD'], $attributes);
$breaker = null;
$stmt = null;
try {
$breaker = new PDO($dsn, $config['SQL_USER'], $config['SQL_PASSWORD'], $attributes);
$sessionQuery = "SELECT @@SPID AS SessionId, "
. "CONVERT(varchar(33), login_time, 126) AS LoginTime "
. "FROM sys.dm_exec_sessions WHERE session_id = @@SPID";
$stmt = $pdo->query($sessionQuery);
$before = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt = null;
if (!is_array($before) || !is_int($before['SessionId']) || $before['SessionId'] <= 0) {
throw new RuntimeException('Expected the current session identity.');
}
$spid = $before['SessionId'];
$query = 'SELECT id FROM (VALUES (1), (2), (3)) AS Demo(id) ORDER BY id';
$stmt = $pdo->query($query);
if ($stmt->fetchAll(PDO::FETCH_COLUMN) !== [1, 2, 3]) {
throw new RuntimeException('Unexpected initial rows or PHP types.');
}
$stmt = null;
// KILL requires a checked integer, not a parameter marker.
$stmt = $breaker->query('KILL ' . $spid);
$stmt = null;
sleep(1);
$stmt = $pdo->query($query);
if ($stmt->fetchAll(PDO::FETCH_COLUMN) !== [1, 2, 3]) {
throw new RuntimeException('Unexpected recovered rows or PHP types.');
}
$stmt = null;
$stmt = $pdo->query($sessionQuery);
$after = $stmt->fetch(PDO::FETCH_ASSOC);
if (!is_array($after) || $after['LoginTime'] === $before['LoginTime']) {
throw new RuntimeException('Expected a new physical session.');
}
echo "Recovered connection: 3 matching rows; login time changed.\n";
} finally {
$stmt = null;
$breaker = null;
$pdo = null;
}
ODBC bağlantıyı geri getirdiğinde her iki programdan da beklenen çıktı:
Recovered connection: 3 matching rows; login time changed.
Test, kasıtlı olarak boşta kalan bir oturumu sonlandırır. Ağ bölümü, hizmet devrelemesi, aktif işlem kurtarma, yazma tekrarı veya Azure throttling test etmez. Başarılı bir sonucu, kesintiye uğrayan her uygulama işleminin güvenle tekrarlanabileceğinin kanıtı olarak yorumlamayın.
Başarısız bir kurtarmayı tanılama
| Belirti | Denetle |
|---|---|
KILL reddedildi |
İzinli test kimliği kullanın veya yöneticiden kontrollü testi yapmasını isteyin. Başka bir oturum kimliğiyle değiştirmeyin. |
| İlk sorgu zaten başarısız | Kurtarma testi yapmadan önce bağlantıyı, sertifikayı, sorguyu ve izinleri düzeltin. |
KILL sonrasındaki sorgu başarısız oldu |
Kontrol ConnectRetryCountedin, sorgu zaman aşımı, ODBC tanılamaları ve oturum durumunun kurtarılabilir olup olmadığı. Hatayı koşulsuz tekrar denemeyle gizlemeyin. |
| Yeni bir bağlantı açıldıktan sonra geçici bir tablo kaybolur | Uygulama tarafından oluşturulan bir yedek bağlantı eski oturum değildir. Otomatik durum yeniden yaratımı varsaymak yerine oturuma bağlı çalışmayı yeniden tasarlamak. |
| Bir yazma işlemi bağlantı hatası döndürür | Tekrar denemeden önce sonucunu doğrulayın. Sadece istemci hatası sunucunun bunu geri aldığını kanıtlamaz. |
Tanılama verilerini korumalı günlüklerde tutun. SQLSRV, birden fazla kayıt içeren hata koleksiyonunu ortaya çıkarır; PDO, istisna aracılığıyla SQLSTATE ve sürücü detaylarını sağlar. İşlemi ve zaman aşımına ait ayarları şifre veya token kaydetmeden kaydedin. Daha fazla bilgi için Kayıt faaliyetleri bölümünü inceleyebilirsiniz.
Hedefe uygulanabilirlik
ODBC ve SQL hedefi otomatik yeniden bağlantı gerçekleştirir. PHP ayarları geçer ve başarı veya başarısızlık raporu verir. Geçici nesneleri yeniden oluşturmaz, uygulamanızın değişkenlerini geri yüklemez veya bir işlemi tekrar oynatmaz.
Kontrol edilen programlar SQL Server kullanır ve kendi test oturumlarını ikinci bir bağlantı üzerinden sonlandırmak için izin gerektirir. Azure SQL Veritabanı ve Fabric'teki SQL veritabanı kendi hizmet izinleri ve kimlik doğrulama gereksinimlerine sahiptir. Bu programları Azure SQL Yönetilen Örneği, Azure Synapse Analytics veya Warehouse in Fabric için drop-in testleri olarak görmeyin veya sıradan bir bağlantının başarılı olmasından kurtarma desteği olduğu sonucunu çıkarmayın. Seçilen servisin kurtarma desteğine güvenmeden önce kontrol edin. Fabric'teki depo ve SQL veritabanı ayrı hedefler olarak kalır.