技术开发 频道

程序员最易犯的五个PHP数据库问题及解释

     问题 4:不使用关系

    关系数据库不同于编程语言,它们不具有数组类型。相反,它们使用表之间的关系来创建对象之间的一到多结构,这与数组具有相同的效果。我在应用程序中看到的一个问题是,工程师试图将数据库当作编程语言来使用,即通过使用具有逗号分隔的标识符的文本字符串来创建数组。请看下面的模式。

    清单 10. Bad.sql

    DROP TABLE IF EXISTS files;
    CREATE TABLE files (
     id MEDIUMINT,
     name TEXT,
     path TEXT
    );

    DROP TABLE IF EXISTS users;
    CREATE TABLE users (
     id MEDIUMINT,
     login TEXT,
     password TEXT,
     files TEXT
    );

    INSERT INTO files VALUES ( 1, 'test1.jpg', 'media/test1.jpg' );
    INSERT INTO files VALUES ( 2, 'test1.jpg', 'media/test1.jpg' );
    INSERT INTO users VALUES ( 1, 'jack', 'pass', '1,2' );

    系统中的一个用户可以具有多个文件。在编程语言中,应该使用数组来表示与一个用户相关联的文件。在本例中,程序员选择创建一个 files 字段,其中包含一个由逗号分隔的文件 id 列表。要得到一个特定用户的所有文件的列表,程序员必须首先从用户表中读取行,然后解析文件的文本,并为每个文件运行一个单独的 SELECT 语句。该代码如下所示。

    清单 11. Get.php

    <?php
    require_once("DB.php");

    function get_files( $name )
    {
     $dsn = 'mysql://root:password@localhost/bad_norel';
     $db =& DB::Connect( $dsn, array() );
     if (PEAR::isError($db)) { die($db->getMessage()); }

     $res = $db->query( "SELECT files FROM users WHERE login=?",array( $name ) );
     $files = null;
     while( $res->fetchInto( $row ) ) { $files = $row[0]; }

     $rows = array();

     foreach( split( ',',$files ) as $file )
     {
    $res = $db->query( "SELECT * FROM files WHERE id=?",
    array( $file ) );
    while( $res->fetchInto( $row ) ) { $rows[] = $row; }
     }

     return $rows;
    }

    $files = get_files( 'jack' );

    var_dump( $files );
    ?>

    该技术很慢,难以维护,且没有很好地利用数据库。惟一的解决方案是重新架构模式,以将其转换回到传统的关系形式,如下所示。

    清单 12. Good.sql

    DROP TABLE IF EXISTS files;
    CREATE TABLE files (
     id MEDIUMINT,
     user_id MEDIUMINT,
     name TEXT,
     path TEXT
    );

    DROP TABLE IF EXISTS users;
    CREATE TABLE users (
     id MEDIUMINT,
     login TEXT,
     password TEXT
    );

    INSERT INTO users VALUES ( 1, 'jack', 'pass' );
    INSERT INTO files VALUES ( 1, 1, 'test1.jpg', 'media/test1.jpg' );
    INSERT INTO files VALUES ( 2, 1, 'test1.jpg', 'media/test1.jpg' );

    这里,每个文件都通过 user_id 函数与文件表中的用户相关。这可能与任何将多个文件看成数组的人的思想相反。当然,数组不引用其包含的对象 —— 事实上,反之亦然。但是在关系数据库中,工作原理就是这样的,并且查询也因此要快速且简单得多。清单 13 展示了相应的 PHP 代码。

    清单 13. Get_good.php

    <?php
    require_once("DB.php");

    function get_files( $name )
    {
     $dsn = 'mysql://root:password@localhost/good_rel';
     $db =& DB::Connect( $dsn, array() );
     if (PEAR::isError($db)) { die($db->getMessage()); }

     $rows = array();
     $res = $db->query("SELECT files.* FROM users,files WHERE users.login=?
    AND users.id=files.user_id",array( $name ) );
     while( $res->fetchInto( $row ) ) { $rows[] = $row; }
     return $rows;
    }

    $files = get_files( 'jack' );

    var_dump( $files );
    ?>

    这里,我们对数据库进行一次查询,以获得所有的行。代码不复杂,并且它将数据库作为其原有的用途使用。

0
相关文章