Поставщик предоставляет базу данных MS SQL только для чтения, с которой мы взаимодействуем с помощью PHP.
Эта база данных обновляет свои данные в 6:30 и 12:30 по нашему времени. Это приводит к тому, что база данных находится в автономном режиме менее одной минуты, но этого достаточно для запуска cronjobs, а иногда и для конечных пользователей, чтобы подключиться к автономной базе данных.
Журналы показывают, что ошибка связана с:
Cannot open user default database. Login failed. (severity 11)
General SQL Server error: Check messages from the SQL Server (severity 11)
Login failed for user 'USER'. (severity 14)
General SQL Server error: Check messages from the SQL Server (severity 14)
Unable to connect to server: SERVER
Если сервер выходит из строя в середине операции, а не соединения с базой данных, журналы показывают эти ошибки:
The SELECT permission was denied on the object 'TABLE', database 'DATABASE', schema 'dbo'. (severity 14)
General SQL Server error: Check messages from the SQL Server (severity 14)
Query failed
Какой лучший способ справиться с этим? Запросы и соединения соединяются с обработкой остановки «или умереть». Было бы лучше бросить sleep (60), чтобы приостановить выполнение на минуту и повторить запрос / соединение? Вот текущий пример. Соединение происходит из общего включения require_once в начале страницы, поэтому перед запросом обычно выполняются некоторые другие операции.
$mslink = mssql_connect('SERVER', 'USER', 'PASS');
if (!$mslink || !mssql_select_db('TABLE', $mslink)) {
die('Unable to connect or select database!');
}
$strSQL = "SELECT X,Y,Z FROM TABLE WHERE FOO = 'BAR'";
$objQuery = mssql_query($strSQL) or die("Error Query [" . $strSQL . "]");
Я решил определить время и отложить его до соединения (что должно означать, что запрос будет в порядке), или позволить ему потерпеть неудачу, а затем перевести его в спящий режим и повторить попытку (что кажется худшей идеей), поскольку это привело бы к записям журнала. ).
Будет ли это хорошим местом для try / catch вместо использования функциональности if true? Я ничего не делал с try / catch раньше.
Я надеюсь, что решение с подключением будет самым простым, поскольку оно будет охватывать кодовую базу одним изменением по сравнению с выполнением его для каждого запроса. Здесь нет фреймворка или чего-то еще, это простой PHP (и процедурный, я знаю, пожалуйста, будьте осторожны). План состоит в том, чтобы в будущем когда-нибудь перейти от ext \ mssql к PDO.
Я придумал ответ, которым был доволен. Зная, что сервер находится в автономном режиме до минуты каждые шесть часов, я улавливаю сбой соединения, затем засыпаю на несколько секунд, пока не будет произведена повторная попытка, с верхним пределом ожидания 60 секунд. Это отлично сработало и стало давать лучшие данные о том, как долго другой сервер недоступен во время обновления.
Я также переключился с MSSQL (не рекомендуется в PHP7) на PDO и SQLSRV. Приведенный ниже код предназначен для SQLSRV, так как он является ближайшей заменой моего первоначального вопроса.
Этот код хранится вместе с деталями соединения, поэтому его не нужно указывать при каждой попытке запроса, просто в главном включении при подключении.
$mslink = sqlsrv_connect($serverName, $connectionOptions);
if (!$mslink) {
$ms_sql_errors = sqlsrv_errors();
if ($ms_sql_errors[0]['SQLSTATE'] == 42000) { // This is the database update error
error_log("Cannot open database at $serverName", 0);
} elseif ($ms_sql_errors[0]['SQLSTATE'] == "HYT00") {
error_log("Timeout - is the address $serverName correct?", 0);
} elseif ($ms_sql_errors[0]['SQLSTATE'] == 28000) {
error_log("Login Failed!", 0);
} elseif ($ms_sql_errors[0]['SQLSTATE'] == "08001") {
error_log("Network error connecting to $serverName", 0);
} else {
error_log($ms_sql_errors[0]['SQLSTATE'], 0);
}
while (!$mslink && $failcount < 6) {
$failcount++;
sleep(10); // Attempt to reconnect after $serverName disappears
$mslink = sqlsrv_connect($serverName, $connectionOptions);
if (!$mslink) {
error_log("$serverName retry $failcount failed to connect after a 10 second sleep!, will wait 10 seconds and try again...", 0);
if ($failcount >= 6) {
error_log("$serverName connection FAILED AFTER $failcount 10 second sleeps, stopping", 0);
}
} else {
error_log("DW connection worked after $failcount 10 second sleep(s)", 0);
}
}
}
Я надеюсь, что это поможет всем, кто не хочет делать так много работы, справиться с известным и ожидаемым коротким кратким доступом к службам SQL.
Других решений пока нет …