mysql_num_rows比较运算符

时间:2015-02-25 03:28:55

标签: mysql comparison mysql-num-rows


编辑注意:此比较运算符没有任何问题。我被要求解释,所以添加了下面的代码。事实证明,问题出在我用来创建唯一字符串的UniqueID函数中。

我正在尝试解决数据库保存中的间歇性问题。基本上,代码使用发布的数据进行早期查询。然后,我检查该查询中的行数,以确定是更新还是插入记录。

大约1%的时间,这不起作用,并且会覆盖不相关的记录。我想知道,我使用mysql_num_rows()的比较运算符是否有问题。

使用

是否有任何可能的奇怪影响
if(mysql_num_rows($Result) != 0)

后来添加:

mysql版本5.0.51a

我会尽力解释这里重要的事情。 这些表格涉及内部信贷申请。销售人员填写申请信用证的公司表格。然后,他们可以保存该申请以便稍后完成,或者发送到会计部门进行审批。会计可以保存记录以供日后使用,将其返回给销售人员或批准。在任何这些操作中,整个表单都插入(首次创建时)或在表记录中更新。

当将对表单的访问权限转移给销售人员或会计师的任何操作时,会向相应的一方发送电子邮件,其中包括指向该记录的链接。销售人员只能访问他们创建的记录。这是通过简单地检查他们在会话变量中保存的登录用户名来完成的,表中的字段也包含他们的用户名。

表单顶部是一个选择框,用于保存等待处理的记录。在该框中可供销售人员使用的是他/她已存储的记录或发送给他/她的记录以进行更正和重新提交。他们可以通过简单地选择一个来提取表格。他们还可以通过单击电子邮件链接来检索表单,在他们提交表单时发送给他们,或者管理员(会计师)将表单返回给他们。同样,会计师也可以通过两种方法对发送给他们的记录进行处理。

此过程中的每个事务都记录在“事务详细信息表”中。

有许多错误检查可防止记录被不适当地访问。 (请耐心等待,这一切都很重要)销售人员和会计师无法同时访问记录,并且一旦申请获得批准,除了查看之外都没有访问权限。

问题

所有内容都依赖于ID字段,这是CreditApp表中的自动增量mysql字段。该号码存储在“AppID”字段的日志文件中。在这些交易的大约1%中,无论是当销售人员将表单提交给管理员(会计师)还是会计师批准,而不是更新正确的记录,都会更新完全不相关的记录。每个覆盖的记录都是先前已处理的记录(意思是“由会计师”批准)。通常,但不一定,被覆盖的记录可能是一年或两年。

虽然我不确定记录是否在销售人员提交或管理员批准时被覆盖,但另一个特殊的事情是,当这种覆盖发生时,日志表中的条目由销售人员提交,没有将它们与表单记录相关联的AppID。这是空白的。

所以这里是一个非常简化的过程模拟(我相信有更多雄辩的方法可以做到这一点,但唉......):

    if($Process == "RegularSave") // Salesperson storing record for later
{
    $Status = "Store";
    $StoreTitle = $NewTitle;
    if(empty($StoreTitle)){$Error[] = "Title cannot be blank. Record was not saved!";}
    $Q = "SELECT ID, StoreTitle FROM CreditApp WHERE ID = '$ID' OR UniqueID = '$UniqueID'";  // UniqueID prevents double entry on refresh of new record
    $Result = mysql_query($Q);
    if(!$Result){$Error[] = "Database error in storage result!";}
}
elseif($Process == "RegularSubmit") //Sslesperson submitting record
{
    $Status = "Received";
    $StoreTitle = $NewTitle;
    if(empty($StoreTitle)){$Error[] = "Title cannot be blank. Record was not saved!";}
    $Q = "SELECT ID FROM CreditApp WHERE ID = '$ID' OR UniqueID = '$UniqueID'";  // UniqueID prevents double entry on refresh of new record
    $Result = mysql_query($Q);
    if(!$Result){$Error[] = "Database error in ID Check!";}
}
elseif($Process == "AdminProcess" || $Process == "AdminSave" || $Process == "AdminReturn")
{
     // Status variable set here as to "Revised", "Rejected", "Approved", etc.
     // THEN:
    $Q = "SELECT ID FROM CreditApp WHERE ID = '$ID'";
    $Result = mysql_query($Q);
    if(!$Result){$Error[] = "Database error in ID Check!";}
}
elseif($Process == "AdminSend")
{
    // Setup for e-mail from admin when returning record for corrections 
    $ReturnDate = dFormat($Time,41);
    $FromName    = $AdminName;
    $FromEmail  = $AdminAddress;
    $ReturnUser = $_SESSION['FullName'];
    $DetailMsg  = nl2br($Message);
    $NoteString = '======================='."\n".$ReturnUser.': '.$Today."\n".$Message."\n".'======================='."\n".$Notes;
    $R = mysql_query("UPDATE CreditApp SET Notes = '$NoteString', Status = 'Return', ReturnDate = '$ReturnDate', ReturnUser = '$ReturnUser', AdminID = '$_SESSION[User]' WHERE ID = '$ID'");
    $M = mysql_query("INSERT INTO CustAcctStatsDetail (AppID,Action,Detail,Form,TranUser) VALUES ('$ID','Return for Corrections','$DetailMsg','$FormName','$_SESSION[User]')");
    $HTMLData    = ('Your credit request for '.$AcctName.' has been returned for the following reasons:<br /><br />'.nl2br($Message).'<br /><br />
                        FormLink: You can access the record from <a href="'.$MainDir.'credit.php?iKey='.$ID.'&ret=1">this link</a>.<br />
                        You will also find it available in your stored records list at the top of the Credit Application Request form.
                        <br /><br />');
}
if(count($Error) == 0 && $Process != "AdminSend")
{
    if(mysql_num_rows($Result) != 0) // Indicates record already exists
    {
        #=====================================================#
        #  Update Existing Record                             #
        #=====================================================#
        $X = mysql_fetch_array($Result);
        $Q = "UPDATE CreditApp ... WHERE ID = '$X[ID]'"; // Standard Update set of fields
        $Result = mysql_query($Q);
        if(!$Result){$Error[] = "Database update error! (1) ApproveDate: ".$ApproveDate.' '.mysql_error();}
        else
        {
            // Here related tables are updated (simple one-to-many relationships for form data)
            // THEN:
            #=====================================================#
            #  Log any changes                                    #
            #=====================================================#
            $LQ = "UPDATE CustAcctStats SET StoreTitle = '$StoreTitle', Company = '$AcctName',";
            if($AppType == "New"){$ApprovalString = $Approval;}
            elseif($Approval == "Approved"){$ApprovalString = "Completed";} // Revised entry
            else{$ApprovalString = $Approval;}
            if($_SESSION[GVars][Approval] != $Approval || $AppType == "Revised")
            {
                $StatusString = $Status.'/Credit';
                $LQ .= " Status = '$StatusString', CreditApproval = '$ApprovalString', CreditDate = '$ThisDate',";
            }
            $TAction=array(); $TDetail=array();
            if($_SESSION[GVars][SubmitDate]  != $SubmitDate)
            {
                $TAction[] = 'Form Submitted';
                $TDetail[] = $AppType != "Revision" ? "Credit Application submitted for approval" : "Credit Revision Request submitted";
                $LQ .= " SubmitDate = '$SubmitDate'";
            }
            if($_SESSION[GVars][Approval] != $Approval || $_SESSION[GVars][SubmitDate] != $SubmitDate || $AppType == "Revised")
            {
                if(substr($LQ,-1) == ','){$LQ = substr($LQ,0,-1);}
                $LQ .= " WHERE AppID = '$ID'";
                $Result = mysql_query($LQ);
                if(!$Result){$Error[] = "Log File Error! [1] ".mysql_error();}
            }
            if($_SESSION[GVars][Approval] != $Approval || $AppType == "Revised")
            {
                if($AppType != "Revised")
                {
                    if($Approval == "Approved")
                    {
                        $TAction[] = '<span class="LogBlue">Credit Application Approved</span>'; $TDetail[] = 'This Credit Application has been approved for '.$CreditAmt;
                    }
                    elseif($Approval == "Declined")
                    {
                        $TAction[] = '<span class="LogRed">Credit Application Declined</span>'; $TDetail[] = 'This Credit Application has been declined';
                    }
                }
                else
                {
                    if($Approval == "Approved")
                    {
                        $TAction[] = '<span class="LogBlue">Credit Revision Approved</span>'; $TDetail[] = 'This submitted credit revision has been approved and completed.';
                    }
                    elseif($Approval == "Rejected")
                    {
                        $TAction[] = '<span class="LogRed">Credit Revision Rejected</span>'; $TDetail[] = 'This Credit Revision has been rejected';
                    }
                }
            }
            if($_SESSION[GVars][Status] != $Status)
            {
                $TAction[] = 'Status Change';
                if(!empty($_SESSION[GVars][Status]))
                {
                    $TDetail[] = 'Status change from '.$_SESSION[GVars][Status].' to '.$Status;
                }
                else
                {
                    $TDetail[] = 'Status change set to '.$Status;
                }
            }
            if($_SESSION[GVars][StoreTitle]  != $StoreTitle)
            {
                $TAction[] = 'Store Title Change';
                if(empty($_SESSION[GVars][StoreTitle]))
                {
                    $TDetail[] = 'Store Title created: '.$StoreTitle;
                }
                else
                {
                    $TDetail[] = 'Store Title change from '.$_SESSION[GVars][StoreTitle].' to '.$StoreTitle;
                }
            }
            $TranCount = count($TAction);
            for($a=0;$a<$TranCount;$a++)
            {
                $Q = "INSERT INTO CustAcctStatsDetail (AppID,Action,Detail,Form,TranUser) VALUES ('$ID','$TAction[$a]','$TDetail[$a]','$FormName','$_SESSION[FullName]')";
                $Result = mysql_query($Q);
                if(!$Result){$Error[] = "Log File Error! [2]";}
                if($Status == "Processed")
                {
                    $Q = "UPDATE CustAcctStats SET StoreTitle = '$StoreTitle', Company = '$AcctName', CreditDate = CURDATE(), Date = NOW(), AdminUser = '$_SESSION[User]' WHERE AppID = '$ID'";
                }
                else
                {
                    $Q = "UPDATE CustAcctStats SET StoreTitle = '$StoreTitle', Company = '$AcctName', Date = NOW() WHERE AppID = '$ID'";
                }
                $Result = mysql_query($Q);
            }
            switch($Process)
            {
                // Text is set here to display result and status to the user    
            }
        }
    }
    elseif(!$_SESSION['Admin']) // Record is new entry. Admin only deals with records in process
    {
        #=====================================================#
        #  Create New Record                                  #
        #=====================================================#
        $Q = "INSERT INTO CreditApp ...";  // Standard Insert set of fields
        $Result = mysql_query($Q);
        if(!$Result){$Error[] = "Error in database insert! (1) ".mysql_error($Conn);}
        else
        {
            // Here related tables are updated (simple one-to-many relationships for form data)
            // THEN:
            #=====================================================#
            #  Create new Log Entry                               #
            #=====================================================#
            $CreditApproval    = !empty($Approval) ? $Approval : "";
            if(!empty($ApproveDate)){$CreditDate = $ApproveDate;}
            if(!empty($DeclineDate)){$CreditDate = $DeclineDate;}
            if($Process == "RegularSave")
            {
                if($AppType != "Revision")
                {
                    $Action = "Record Created";
                    $Detail = "A new record was created but stored to submit at a later date.";
                    $StatusString = "Store/Credit";
                }
                else
                {
                    $CreditApproval = "Current";
                    $Action = "Credit Revision";
                    $Detail = "A Credit Revision was created but stored to submit at a later date.";
                    $StatusString = "Store/Credit";
                }
            }
            elseif($Process == "RegularSubmit")
            {
                if($AppType != "Revision")
                {
                    $Action = "Record Created";
                    $Detail = "A new record was created and sent to Administration for approval.";
                    $StatusString = "Received/Credit";
                }
                else
                {
                    $CreditApproval = "Current";
                    $Action = "Credit Revision";
                    $Detail = "A Credit Revision was sent to Administration.";
                    $StatusString = "Received/Credit";
                }
            }
            else
            {
                $Action = "Error!";
                if(empty($Process)) // "Detail text added 2/19/15 (Previously was blank)
                {
                    $Detail = "Process variable is empty";
                }
                else
                {
                    $Detail = $Process.' should equal RegularSave or RegularSubmit';
                }
            }
            if(empty($CreditDate)){$CreditDate = "0000-00-00";}
            if(empty($SubmitDate)){$SubmitDate = "0000-00-00";}
            $Result = mysql_query("INSERT INTO CustAcctStats (AppID,AppType,User,StoreTitle,Company,Status,CreditApproval,CreditDate,SubmitDate,Date)
                                          Values ('$ID','$AppType','$_SESSION[User]','$StoreTitle','$AcctName','$StatusString','$CreditApproval','$CreditDate','$SubmitDate',NOW())");
            if(!$Result){$Error[] = "Log File Error! [3] ".mysql_error();}
            else
            {
                $Result = mysql_query("INSERT INTO CustAcctStatsDetail (AppID,Action,Detail,Form,TranUser,TranDate) VALUES ('$ID','$Action','$Detail','$FormName','$_SESSION[FullName]',NOW())");
                if(!$Result){$Error[] = "Log File Error! [4]";}
            }
        }
    }
    elseif($_SESSION['Admin'])
    {
        $Error[] = "Record not found!<br />Please exit Admin mode if you want to save a new record!";
    }
}
if(($_POST['Submit'] == "Submit" || $Process == "AdminSend" || $Process == "AdminProcess") && count($Error) == 0)
{
     // Here the e-mail is generated
}    

2 个答案:

答案 0 :(得分:0)

你正在使用InnoDB,对吗?你有多个连接可能做这样的查询?但你没有BEGIN ... COMMIT围绕对(SELECT,INSERT / UPDATE)语句?

切换到INSERT ... ON DUPLICATE KEY UPDATE ...以便在单个原子操作中执行此过程。

如果你确实有BEGIN ... COMMIT,那么SELECT有FOR UPDATE吗?它应该 - 为了锁定需要UPDATE的记录或锁定新记录将被插入的位置。

答案 1 :(得分:0)

SELECT ID, StoreTitle FROM CreditApp WHERE ID = '$ID' OR UniqueID = '$UniqueID'

这可能表现得非常缓慢。检查EXPLAIN或计时。解决方法是将其变为UNION:

( SELECT ID, StoreTitle CreditApp WHERE ID = '$ID' )
UNION DISTINCT 
( SELECT ID, StoreTitle CreditApp WHERE UniqueID ='$UniqueID' )

我不知道$ R(INSERT?)或$ M(UPDATE?)的执行位置。 SELECT和INSERT / UPDATE之间需要多长时间?时间越长,另一个连接滑入的可能性就越大。

此外,如果OR很慢,你可以让多个SELECT排队,等待潜入。而没有OR的SELECT可以非常快地滑入。

根据我的理解,在INSERT / UPDATE之后的SELECT和UNLOCK TABLES之前,你真的需要LOCK TABLES WRITE ....否则,正如你所看到的,偶尔会发生一些事情。

或者,跳过LOCK / UNLOCK并将INSERT / UPDATE转换为INSERT ... ON DUPLICATE KEY UPDATE,因为它是原子的。 (即使保留了SELECT,即使它发生了蠢事,IODKU也会对其进行纠正。)