您好,欢迎访问一九零五行业门户网

PEAR:创建中间的数据库应用层2

创建|数据|数据库
function errormessage($dbcode)
返回db错误文本信息。
function &raiseerror($code = db_error, $mode = false, $level = false,$debuginfo = false, $nativecode = false)
抛出一个错误。这个函数由db来调用。
function setfetchmode($fetchmode)
设置缺省的fetch模式。
fetchmod有以下几种:
db_fetchmode_default :使用缺省的模式
db_fetchmode_ordered :每条记录的数据列使用数字索引,从0开始
db_fetchmode_assoc :每条记录的数据列使用字段名索引,同查询中的字段名一致
db_fetchmode_flipped:如果结果集是多维的,多条记录多个字段,一般来说返回一个2维数组,第一维是记录号,标明是第几条记录,第2维的数组则使用字段名或数字索引。db_fetchmode_flipped则会交换这个顺序,也就是说,第一层是字段名,第2维才是记录号.
function setoption($option, $value)
设置后端数据库选项。$options,$value分别是选项名和相应的值。
一般不用直接调用,在db_common及其子类的构建函数中会调用这个函数。
function getoption($option)
取得某个option的值
function prepare($query)
为execute()准备编译一个查询。对于某些后端数据库,这是通过仿真来实现的。返回编译后的查询句柄,出错则返回一个db_error对象。
function execute($stmt, $data = false)
执行编译后的查询。$stmt是由prepare返回的句柄。$data是参数数据,如果你使用的是参数查询,$data将要包含每个?参数的值
例子:
prepare($sql);
  if(db::iserror($qh)){
     return $qh;
  }
  $result = $db->execute($qh);
  return $result;
?>
function executeemulatequery($stmt, $data = false)
返回一个实际的查询字符串,供仿真prepare,execute的时候使用,内部函数。如果出错,则返回db_error对象
function executemultiple( $stmt, &$data )
在同一个查询句柄上执行多个查询。$data必需是一个从0开始的数组,这个函数将 依次使用数组中的每一行数据来调用execute。这个函数一般用于参数查询。你可执行一次 查询的编译,然后将不同的参数值放入$data数组,然后就可一次同时执行查询了。需要注意,如果中间某个查询出错,剩余的查询不会继续进行而是返回错误。
function modifyquery($query)
内部函数,用于后端数据库修正查询,后端数据库实现这个函数,然后返回进行优化和修正后查询串。例子:这是db_mysql的实现,
options['optimize'] == 'portability') {
            // delete from table gives 0 affected rows in mysql.
            // this little hack lets you know how many rows were deleted.
            if (preg_match('/^\s*delete\s+from\s+(\s+)\s*$/i', $query)) {
                $query = preg_replace('/^\s*delete\s+from\s+(\s+)\s*$/',
                                      'delete from \1 where 1=1', $query);
            }
        }
        return $query;
    }
?>
function &query($query)
执行一个查询,查询成功,如果是有结果集的查询,则回一个db_result对象,如果没有结果集的查询则返回db_ok。
出错则返回db_error对象。
function &getone($query, $params = array())
执行查询,并返回结果集中第一行第一列的数据。$params是参数值,如果后端数据库支持,将调用prepare/execute来使用这些参数。
例子:
getone($sql);
if(db::iserror($last)){
   echo 出错:.db::errormessage($last);
}
echo id:.$last;
?>
function &getrow($query, $fetchmode = db_fetchmode_default, $params = array())
执行查询,请返回结果集的第一条记录。
$fetchmod 指定fetch模式,如果省略,使用缺省模式。
例子:
getrow($sql);
if(db::iserror($row)){
   echo 出错:.db::errormessage($row);
}
for($i=0;$i   echo
$row[$i] ;
}
?>
function &getcol($query, $col = 0, $params = array())
执行查询,并返回包含结果集中指定字段列的值的数组。
$col是要返回的列的索引,可以是整数,或者是关键字段名。
例子:
getcol($sql,1);
if(db::iserror($row)){
   echo 出错:.db::errormessage($row);
}
for($i=0;$i   echo $row[$i]
;
}
?>
function &getassoc($query, $force_array = false, $params = array())
执行查询,并返回一个关联数组。
$force_arry 强制返回数组。如果true,那么即使你的结果集里只有2个字段,那么关键字段对应的值也是一个只有一个元素的
数组。如果false,那么关键字段对应的值是一个标量了。
注意,这个关联数组有些特别:
如果你查询的是select userid,name,reg_date from user,记录集是:
userid     name       reg_date
test       testor     2001-07-05
test2      teest2     2001-07-06
那么返回的数组是这样的:
array( 'test' => array('testor','2001-0705'),
       'test2'=> array('teest2','2001-07-06'
     )
例子:
getassoc($sql);
if(db::iserror($userinfo)){
    die 错误!.db::errormessage($userinfo);
}
if(empty($userinfo)){
   echo warning:no users!;
   return;
}
/*现在,userinfo里面保存有用户的信息*/
function getuserinfo($user_id=''){
  $info = $userinfo[$user_id];
  if (empty($info){
     echo 没有这个用户信息!;
  }
  return $info;
}
?>
function &getall($query, $fetchmode = db_fetchmode_default, $params = array())
返回包含结果集中全部记录的数组。注意,如果你的结果集很大,不要使用这个函数。
例子:
getall($sql);
  if(db::iserror($list)){
     die 数据库错误:.db::errormessage($list);
  }
  for ($i=0;$i       $user = $list[$i];
       echo ;
       for($j=0;$j           echo .$user[$j]. ;
       }
       echo
;
  }
?>
function autocommit($onoff=false)
指定是否自动提交事务。有的后端数据库不支持。
function commit()
提交当前事务
function rollback()
回滚当前事务
function numrows($result)
返回结果集中的记录数
function affectedrows()
返回上一次查询操作的记录数
function nextid($seq_name, $ondemand = true)
返回指定的sequence的下一个值
function createsequence($seq_name)
创建一个sequence
function dropsequence($seq_name)
删除一个sequence
五、 更进一步,创建你自己的中间数据库应用层
到此,我们对于db类的功能已经有了更深的了解。我们可以基于db类来创建你自己的数据库应用层了。也许你会问,我为什么还要创建新的类,直接在我的应用程序中使用db不好么?答案是,当然可以,但是我不推荐。
首先,虽然db的功能很强大,但是仍然是过于底层的,你的类应该是面向应用的。你的这个数据库层应该屏蔽不需要使用的功能和函数,同时,也要提供一些更'高级'的方法,比如,你的应用程序不应该去联接数据库,释放资源,这些应该是透明的。那么这些工作就要由你的这个类来完成了。
其次,db仍有一些缺陷,一旦找到比它更好的,你可以迅速地升级。你所要改的只是这个类的方法如何实现,你的应用程序的其他模块不会为此受到影响。
在你设计自己的类的时候,希望能够一些准则:
提供基本的自由的查询接口。包括query,execute.分别对应有结果集和无结果集的查询。
不要使用特定数据库的某些特性,即使因为放弃使用这些特征会给你增加不少的代码量。
尽量屏蔽一些数据库的操作细节,比如连接数据库,释放资源等等。
六、 db的不足
上面我们讨论了db的优点和一些使用的方法与技巧。但是,任何事物都不是十全十美的,db类更是如此,由于db乃至pear的开发时间并不长,因此db并没有最终全部完成,其中也或多或少地存在一些bug或者设计上的问题,需要我们在使用中去发现和修正。
mysql的问题
问题1:前段我在开发一个项目中,发现db的mysql类有一个问题,那就是当你connect的时候,mysql类自动将当前数据库设置为$dsn中的数据库名。以后使用query的时候,都是使用当前数据库。下面是原来connect的代码:
  if ($dsninfo[database]) {
            if (!mysql_select_db($dsninfo[database], $conn)) {
                return $this->raiseerror(); // xxx errormsg
            }
        }
这导致了一个后来令我费解的问题:
我的项目需要我连接2个数据,假设分别是user和test。test是我的主要数据库,但是我要从第一个数据库中user中取得用户信息,同时test中保存用户的权限信息。我为此做了一个中间的类cv_db,用来实现我的数据库层。在cv_db的创建函数中,我连接到指定的数据库,从而我可以这样使用:
$db1 = new cv(user);
$db2 = new cv(test);
后面当我执行,查询某个用户的信息的时候,出现了该表不存在的db错误。但实际上这个表是存在的。最后,我发现原来是db/mysql.php的问题,因为它的查询使用的是,mysql_query,而不是mysql_db_query,当我连接到第2个数据库的时候,mysql的当前数据库变成了第2个,这时我再执行针对第一个数据库的查询,当然会出错。
解决方式有2个,在创建cv的时候不连接到数据库,查询的时候连接,查询完毕后断开。或者,修改db/mysql.php。我选择后者,我将上面几行注释,然后将simplequery中的mysql_query 替换成mysql_db_query.
问题2:mysql没有execute,因此它继承使用了db_common中模拟方式,但是不幸地是,这带来了新的问题,在一些更新查询中,所要更新的数据有? &这2个特殊字符的时候,会出现问题,因为prepare认为这是参数查询的字符,将进行分析,导致无法更新数据。
解决方式也有2个:替换?和&,但是这样要考虑的事情很多。或者:直接使用simplequery或者query。
我选择后者,由于我的其他类只和cv――我这个中间数据库应用类打交道,于是,我在cv的execute方法中做了判断,如果是后端数据库是mysql,那么我直接调用simplequery,否则,调用后端数据库的prepare和execute。这样,实际的后端数据库对于我项目中的其他应用类是透明的,我可以简单地做相应的调整,这也是我设计数据库应用层的初衷。
db的开发状态
db目前仍在不断地开发当中,在db/下面有一个文件status,它描述了db类的功能和各个后端数据库的实现情况,下面是php4.0.6这个发布中的开发情况:
x - 已经实现,但尚未测试implemented, but without tests
t - 已经实现,但是一个或多个测试没有通过implemented, but one or more tests fail
t - 实现并通过全部测试implemented, passing all tests
e - 仿真实现,没有测试emulated, without tests
e - 仿真实现,通过全部测试emulated, passing all tests
n - 返回 not capable,没有这个能力提供该项功能
- - 没有实现
                   fbsql      ifx      mssql      oci8     pgsql
feature              |  ibase  |  msql   |   mysql |   odbc  |  sybase
simplequery          x    x    x    x    x    t    t    x    t    x
numcols              x    x    x    x    x    t    t    x    t    x
numrows              x    n    n    x    x    t    e    n    t    n
errornative          x    n    x    n    n    t    x    x    t    n
prepare/execute      e    x    e    e    e    e    t    e    e    e
sequences            e    n    n    n    n    e    t    n    t    n
affectedrows         x    n    x    n    n    t    t    n    t    n
fetch modes          x    x    x    x    x    t    t    x    t    x
fetch absolute rows  x    n    x    x    x    x    n    x    x    x
transactions         x    x    n    n    n    n    x    x    x    n
auto-commit          x    x    n    n    n    n    x    x    x    n
error mapping        x    -    e    -    -    t    t    x    e    -
tableinfo            x    n    n    n    n    t    n    n    n    n
七、参考资源
adodb另一个非常好操纵数据库的php程序,db的绝好的替代者
关于作者
潘凡(night sailer):北京赛迪数据有限公司工程师。主要研究兴趣是perl,php与xml的应用,php的mvc开发模式,perl-gtk的使用。您可以通过 e-mail:nightsailer@hotmail.com 跟他联系。
其它类似信息

推荐信息