供应商提供了一个只读的MS SQL数据库,我们使用PHP与之交互。
此数据库在我们的时间630AM和1230AM更新它的数据。这会导致数据库脱机不到一分钟,但这足以让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
处理此问题的最佳方法是什么?查询和连接与“或死”停止处理配对。抛出一个睡眠(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 . "]");
我考虑过在连接之前检测时间并延迟它(这应该意味着查询会没问题),或让它失败然后再次睡觉并再次尝试(这似乎是一个更糟糕的想法 - 因为它导致记录条目。)
这是尝试/捕获的好地方,而不是使用if true功能吗?我以前没有用try / catch做过任何事情。
我希望连接的解决方案最简单,因为只需更改一次就可以覆盖代码库,而不是在每个查询上执行此操作。没有框架或任何东西,这是直接的PHP(和程序,我知道,请温柔)。计划是将来某个时候从ext \ mssql转移到PDO。
答案 0 :(得分:0)
我想出了一个我满意的答案。知道服务器每六个小时离线最多一分钟,我在连接上遇到故障然后再睡几秒钟直到重试,上限等待60秒。这很有效,并开始返回更新数据,了解更新期间其他服务器不可用的时间。
我也从MSSQL(在PHP7中弃用)切换到PDO和SQLSRV。下面的代码是针对SQLSRV的,因为它是我最初问题的最接近的代替。
此代码与连接详细信息一起存储,因此不需要与每次查询尝试一起存储,只需在连接时包含在main中。
$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服务。