亲历在linux + oracle9i,多台数据库服务器中遇到的2个典型问题, 至今未在谷鸽/百度检索到解决/解释类似问题的有用信息,有兴趣的大虾小虾来拍几砖运行环境均为:linux + oracle9i,多台数据库服务器
clsDB.php为Oracle 数据库连接的类
问题一:在限定条件相同下,使用绑定变量的SQL同未使用绑定变量的SQL检索的数据有出入,按原始设计的意图是两者检索出的信息应该是相同的,即测试SQL_1检索出的total_num=测试SQL_2检索出的值。但是在用户统计数据的某一天,突然出现了偏差,使用绑定变量的SQL取出的数据是本月1号到当前使用时间条件终止时间的数据(即:$str_app_stime = '2008-10-01 00:00:00';$str_app_etime = '2008-10-07 23:59:59';$int_log_type = 2;),而不是使用下面公用条件得到的数据/*******测试问题一演示START*******///公用条件
$str_app_stime = '2008-10-07 00:00:00';
$str_app_etime = '2008-10-07 23:59:59';
$int_log_type = 2;//测试SQL_1(使用绑定变量/时间使用>==<).
$str_sql_sel_1 = "SELECT SUM(a.trans_amount) AS total_sum FROM Table_a a";
$str_sql_sel_1 .= " WHERE 1=1";
$str_sql_sel_1 .= " AND a.op_time >= TO_DATE(:op_time_start,'YYYY-MM-DD HH24:MI:SS')";
$str_sql_sel_1 .= " AND a.op_time <= TO_DATE(:op_time_end,'YYYY-MM-DD HH24:MI:SS')";
$str_sql_sel_1 .= " AND a.op_type=:opt_type";
$obj_db->PreparedExecute($str_sql_sel_1);
$obj_db->BindByName(":opt_type",$int_log_type);
$obj_db->BindByName(":op_time_start",$str_app_stime);
$obj_db->BindByName(":op_time_end",$str_app_etime);
$obj_db->Execute();
$obj_db->next_record();
$dbl_total_1 = $obj_db->f("total_sum");//测试SQL_2(未使用绑定变量/时间使用BETWEEN AND).
$str_sql_sel_2 = "SELECT SUM(a.trans_amount) AS total_sum FROM Table_a a";
$str_sql_sel_2 .= " WHERE 1=1";
$str_sql_sel_2 .= " AND a.op_time BETWEEN TO_DATE('".$str_app_stime."','YYYY-MM-DD HH24:MI:SS')";
$str_sql_sel_2 .= " AND TO_DATE('".$str_app_etime."','YYYY-MM-DD HH24:MI:SS')";
$str_sql_sel_2 .= " AND a.op_type=:opt_type";
$obj_db->query($str_sql_sel_2);
$arr_total_2 = $obj_db->fetchArray();
$dbl_total_2 = $arr_total_2[0]['total_sum'];//测试SQL_3(使用绑定变量/时间使用BETWEEN AND).
$str_sql_sel_3 = "SELECT SUM(a.trans_amount) AS total_sum FROM Table_a a";
$str_sql_sel_3 .= " WHERE 1=1";
$str_sql_sel_3 .= " AND a.op_time BETWEEN TO_DATE(:op_time_start,'YYYY-MM-DD HH24:MI:SS')";
$str_sql_sel_3 .= " AND TO_DATE(:op_time_end,'YYYY-MM-DD HH24:MI:SS')";
$str_sql_sel_3 .= " AND a.op_type=:opt_type";
$obj_db->PreparedExecute($str_sql_sel_3);
$obj_db->BindByName(":opt_type",$int_log_type);
$obj_db->BindByName(":op_time_start",$str_app_stime);
$obj_db->BindByName(":op_time_end",$str_app_etime);
$obj_db->Execute();
$obj_db->next_record();
$dbl_total_3 = $obj_db->f("total_sum");//测试结果
$dbl_total_1 != $dbl_total_2 ;
$dbl_total_2 == $dbl_total_3 ;//说明:
刷新一次可能出现正常的期望结果,即 $dbl_total_1 == $dbl_total_2 == $dbl_total_3;[正常]
但再刷新一次$dbl_total_1的结果又是2008-10-01 00:00:01至2008-10-07 23:59:59这段时间的数据;[异常]//最终解决
使用测试SQL_3(使用绑定变量/时间使用BETWEEN AND),完成//疑问
至今不知道原因,而且现在再次测试这3个测试SQL获得的值却都是相同的正常数据,唯一担心的是不知道什么时候又不正常/*******测试问题一演示END*******/
问题二:同一页面,oracle多事务提交
/*******测试问题二演示START*******///由于包含的此公用文件mall.init.php已经$obj_db = new clsDb();并且将自动提交置为true,即$obj_db->autoCommit = true;
include_once("mall.init.php");
//手动置为false
$obj_db->autoCommit = false;//第一次SQL[select 操作],获取balance并锁定此数据 
$str_sql_sel_1 = " SELECT b.balance FROM Table_b b WHERE b.id=:id FOR UPDATE";
$obj_db->preparedExecute($str_sql_sel_1);
$obj_db->bindbyname(":id",1);
$obj_db->execute();
$arr_balance_1 = $obj_db->fetchArray();
$dbl_balance_1 = $arr_balance_1[0]['balance'];
//假设此时$dbl_balance_1的数据为 15 ;
//第二次SQL[update 操作],更新此条数据的balance
$str_sql_set_2 = " UPDATE Table_b SET balance=balance+30 WHERE id=:id";
$obj_db->preparedExecute($str_sql_set_2);
$obj_db->bindbyname(":id",1);
$obj_db->execute();//
$obj_db->commit();
//第二次new新DB [注意,第二次的命名同第一次new DB的名称相同,同为" $obj_db "]
$obj_db = new clsDB();//第三次SQL[select 操作],获取balance此时数据 
$str_sql_sel_3 = " SELECT b.balance FROM Table_b b WHERE b.id=1";
$obj_db->preparedExecute($str_sql_sel_3);
$obj_db->bindbyname(":id",1);
$obj_db->execute();
$arr_balance_3 = $obj_db->fetchArray();
$dbl_balance_3 = $arr_balance_3[0]['balance'];//问题出现
按上面流程此时的id=1 的这条数据的balance应该为 15+30 = 45 ;
但是本次获取的$dbl_balance_3的数据竟然还是 15 ;//第四次SQL[update 操作],更新balance的数据
$str_sql_set_4 = " UPDATE Table_b SET balance=balance-15 WHERE id=:id";
$obj_db->preparedExecute($str_sql_set_4);
$obj_db->bindbyname(":id",1);
$obj_db->execute();//
$obj_db->commit();
//测试结果
如果按照第三次的异常结果,那么第四次的更新后balance 可能是 0 ;但是,当再次检索此条数据的balance数据,竟然最后得到的balance是 30 ;//最终解决[尝试]
将第二次new新DB这一步删掉,不要二次new//疑问
至今不知道原因,而且现在不知道注释掉二次new DB后 问题会不会被解决,测试没有还原出这种错误,已经添加跟踪日志,看能否最终找到问题/*******测试问题二演示END*******/强烈欢迎拍砖

解决方案 »

  1.   

    php+oracle+linux环境下出现的这两问题,
    不是同一时期的问题,今天特意整理发上来
    不知道有没有遇到过相同或类似问题的XDJM 
    心得经验贴上来,交流下 参考下
      

  2.   

    应该是邦定之后的SQL和自行转换的SQL结果不同。
    检测一下搜索结果,果到底有哪些地方不同。
      

  3.   

    问题一
    关于检索到结果不同 好像还是跟between and 同 >==<的问题,你可以看我的注释说明,
    问题解决的方法是改变了这个地方//最终解决 
    使用测试SQL_3(使用绑定变量/时间使用BETWEEN AND),完成