JS XMLHttpRequest到PHP页面以执行MSSQL查询

时间:2018-08-08 12:56:58

标签: javascript php sql-server internet-explorer

我在处理XMLHttpRequest时遇到问题。基本上,HTML按钮会调用deleteItem函数,然后再调用另一个函数。这两个函数的每一个都使XHR成为php页面,以便从两个不同的数据库表中删除元组。

这是代码(变量重命名为泛型):

JS:

//remove first item from first table
function deleteItem() {
    var conn = new XMLHttpRequest();
    var query = "DELETE FROM MyTable WHERE ID = " + arrayOfObjects[i][0] + ";";
    conn.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            deleteWorkflowProcess(arrayOfObjects[i][1], conn.responseText);
        }
    }

    conn.open("GET","../../db_query/sql.php?q=" + query + "&p=DELETE", true);
    conn.send();

}

//remove other items from other table
function deleteWorkflowProcess(s, r) {
    var conn = new XMLHttpRequest();
    var query = "DELETE FROM MyOtherTable WHERE FOREIGN_KEY = '" + s + "';";

    if (r == "Deletion succeeded.") {
        conn.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var response = conn.responseText;
                alert(response);
                window.location.replace("thissamepage.php");
            }
        }

        conn.open("GET","../../db_query/sql.php?q=" + query + "&p=DELETE", true);
        conn.send();
    } else {
        alert(r);
    }
}

这是PHP页面,它需要两次调用:

//set up connection
$serverName = "SERVER\MSSQLINSTANCE";
$connectionInfo = array("Database"=>"DATABASE");

if (isset($_REQUEST['q'])) {

    //establish connection
    $conn = sqlsrv_connect($serverName, $connectionInfo);

    if ($conn) {

        //delete data
        if ($_REQUEST['p'] == "DELETE") {
            $result = sqlsrv_query($conn, $_REQUEST['q']);
            if ($result) {
                echo "Deletion succeeded.";
            } else {
                echo "Deletion failed: " . explode("]",sqlsrv_errors()[0]['message'])[3];
            }
        }

        //do some other stuff based on 'p' value
        //e.g. insert, update, etc.
    }

    sqlsrv_close($conn);
}

这是我确定的东西:

  • 查询的措词正确,没有语法错误。
  • 查询正在调用正确的表。
  • 第一个函数通过从第一个表中删除正确的元组来正常工作。
  • 第二个函数无法从第二个表中删除任何内容

我的问题是:为什么第一个功能可以正常工作,而第二个功能却不能正常工作?

编辑: $ _REQUEST ['q']等于SQL查询,在这种情况下为“从MyOtherTable中删除,其中FOREIGN_KEY ='asdf';”

$ _ REQUEST ['p']是我正在使用的SQL命令,在本例中为“ DELETE”。

sqlsrv_errors()不返回任何内容,因为它从未被调用。据我所知,查询成功执行了,只是没有任何反应。我怎么知道的:

  • 我知道XHR成功通过了,因为IE开发人员工具的“网络”选项卡显示以下内容: sql.php?q = SELECT * FROM MyOtherTable WHERE FOREIGN_KEY ='asdf';&p = SELECT
  • 上面的GET给出了状态码200。
  • 如果失败,JS将弹出一个警告,提示“删除失败”,然后给出错误消息。相反,它会弹出一个警报,提示“删除成功”,只有在查询成功后才会发生,因此不会调用sqlsrv_errors()。

在Zhorov的建议下,我放入了sqlsrv_rows_affected()来确定正在发生的事情。似乎每次报告的受影响的行数都是相同的,无论有多少行与SQL语句中的条件匹配,或者即使有任何行要受影响。仅在Internet Explorer中会发生此行为。在Chrome中,这两个功能均应正常运行。

主要修改: 看来此问题的范围已更改。通过暂时禁用IE中的缓存,我已经能够按预期运行两个文件,而没有任何错误。我不确定为什么IE决定缓存它,但是现在的问题已经变成该程序在禁用或解决IE中的缓存方面可以做什么?我几乎不能指望每个用户都可以这样做这本身。

1 个答案:

答案 0 :(得分:0)

我会建议一些可能对您有所帮助的东西。您的DELETE语句将执行,但不会删除行,因为没有匹配WHERE条件的行。 尚不清楚您的表定义是什么,实际数据是什么(我想'asdf'只是一个例子),但是我有类似的测试用例,这是一个解决方案。

检查由sqlsrv_rows_affected()执行的最后一条语句修改的行数。 只需在脚本中添加一行:

...
$result = sqlsrv_query($conn, $_REQUEST['q']);
if ($result) {
    echo 'Rows affected: '.sqlsrv_rows_affected($result).'</br>';
    echo "Deletion succeeded.";
} else {
    echo "Deletion failed: " . explode("]",sqlsrv_errors()[0]['message'])[3];
}
...

因此,如果执行该语句时没有错误并且受影响的行为0,则可能的一个原因可能是事实,即FOREIGN_KEY列的类型似乎为varchar / nvarchar / text。 如果FOREIGN_KEY列中的值包含任何特殊字符,则在传递此DELETE语句时必须考虑编码问题。

这也将解释一个事实,第一个功能正常工作,而第二个功能失败。 第一个函数删除基于数字列值的WHERE条件的记录,而第二个函数删除基于文本列值的WHERE条件的记录。

如何测试该语句:

使用SQL Server Management Studio并查看结果和受影响的行。

使用您的代码,只需将INSERT语句放在DELETE语句之前,然后再次检查sqlsrv_rows_affected()

...
$sql = "INSERT MyOtherTable (FOREIGN_KEY) VALUES ('asdf');"; 
$sql = $sql + $_REQUEST['q'];
$result = sqlsrv_query($conn, $sql);
if ($result) {
    echo 'Rows affected: '.sqlsrv_rows_affected($result).'</br>';
    echo "Deletion succeeded.";
} else {
    echo "Deletion failed: " . explode("]",sqlsrv_errors()[0]['message'])[3];
}
...

有关sqlsrv_rows_affected()的信息可以在here中找到。

更新

来自php.net的用户信息:

如果sql包含INSERT,UPDATE或DELETE语句,则必须消耗受影响的行数。 sqlsrv_query返回一个SQL游标,如果结果为非false,则必须读取该游标以完成事务。 这对于s​​qlsrv_execute有效。在这种情况下,还必须使用准备好的语句句柄来读取游标。

...
$result = sqlsrv_query($conn, $_REQUEST['q']);
if ($result) {
    while ($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) {
    }
    echo 'Rows affected: '.sqlsrv_rows_affected($result).'</br>';
    echo "Deletion succeeded.";
} else {
    echo "Deletion failed: " . explode("]",sqlsrv_errors()[0]['message'])[3];
}
...

另一种解决方案是将SET NOCOUNT ON置于sqlsrv语句以及所有调用的过程,函数和触发器的顶部。

...
$sql = "SET NOCOUNT ON;"; 
$sql = $sql + $_REQUEST['q'];
$result = sqlsrv_query($conn, $sql);
if ($result) {
    echo 'Rows affected: '.sqlsrv_rows_affected($result).'</br>';
    echo "Deletion succeeded.";
} else {
    echo "Deletion failed: " . explode("]",sqlsrv_errors()[0]['message'])[3];
}
...