用PHP和MySQL构建一个数据库驱动的网站

 
http://cn.codeof.com/articles/php/php-basic/
 
用PHP和MySQL构建一个数据库驱动的网站(六)
作者: 未知
日期:
摘要



  在这一章内我们会学习到如何在一个Web页面中向数据库中存储信息并显示它。



(2002-08-29 14:11:25)



--------------------------------------------------------------------------------

By Wing, 出处:Linuxaid





第四章: 用PHP访问MySQL数据库



  在这一章内我们会学习到如何在一个Web页面中向数据库中存储信息并显示它。之前我们已经安装了MySQL这个关系型数据库引擎以及PHP这个服务器端脚本语言,并学习了有关它们的基本知识。在学完这一章后,我们将明白如何综合利用这两个新的工具来构建一个数据库驱动的网站!



对前一部分的回顾



  在我们往下继续之前,回顾一下我们学习的目的应该是件有价值的事。现在有我们的系统中有了两个强有力的新的工具:脚本语言PHP和数据库引擎MySQL。搞清楚两者是如果协同工作是很重要的。



  数据库驱动的网站的实质就是允许站点的内容存在于一个数据库中,并且可以通过这个数据库来动态地产生Web页面来让我们的访问者通过标准的Web浏览器来显示它。所以在你的系统的一端是一个访问你的站点的浏览者,他通过访问http://www.yoursite.com/来获得一个标准的HTML格式的Web页面并在Web浏览器中显示它。在你的系统的另一端是通过一个或几个数据表存储在一个只理解如何响应SQL查询(命令)的MySQL数据库中的你的站点的内容。



  PHP脚本语言承担了两者之间的联络员的角色,使用PHP,你可以编写一个标准HTML的“模板”,这个“模板”决定了你的站点的外观(包括图画和页面设计)。这时内容是属于这个“模板”的,你可以使用一些PHP代码来连接MySQL数据库并且使用SQL查询来获得数据并在其相应位置显示它,这里的SQL查询是和我们在第二章中用来建立笑话数据表时一样的。



  现在对于访问者在访问你的数据库驱动的网站的一个页面时,到底会发生什么事,你应该有个明确的认识了:



  访问者的Web浏览器使用一个标准的URL请求这个页面。



  Web服务器软件(Apache、IIS或其他)认定被请求的页面是一个PHP脚本,因而在响应这个页面请求之前用它的PHP插件来解释它。



  一些PHP命令(我们还没学到)会连接MySQL数据库并向数据库请求属于这个Web页面的内容。



  MySQL数据库作出响应并且向PHP脚本发出被请求的内容。



  PHP脚本将内容存储到一个或几个PHP变量中,并使用我们熟悉的echo函数将其作为Web页面的一部分输出。



  PHP插件完成处理并将生成的HTML副本返回到Web服务器。



  Web服务器将这个HTML副本发送到Web浏览器,这将是一个标准的HTML文件,只不过它不是直接来自于一个HTML文件,而是来自于PHP插件提供的输出。



用PHP连接MySQL



  在我们从我们的MySQL数据库中获取我们的Web页面所包含的内容之前,我们首先必须知道如何建立与MySQL的连接。在第二章中,我们使用了一个叫mysql的程序来做这样的连接。PHP不需要这样的一个程序,对连接MySQL的支持是语言内置的。下面的这个函数用来建立这样的连接:



mysql_connect(<address>, <username>, <password>);





  在这里,<address>是MySQL服务软件在其上运行的计算机的IP地址或主机名(如果这与运行Web服务软件的计算机是同一台,你可以使用"localhost"),<username>和<password>就是你在第二章中用来连接到MySQL服务器的用户名及口令。



  你可能还记得PHP中的函数在被调用时往往会返回(输出)一个值。请不要担心我们没有提醒你,我们在最初接触一个函数时都会为你详细详细它。绝大多数的函数在被调用后,都会返回一个可以在存储在变量中的值以备下次使用。例如我们上面介绍的mysql_connect函数,会返回一个数字来标识已经建立的连接。因为我们会要使用这个连接,所以我们必须保存这个值。下面是一个关于如何连接我们的MySQL数据库的一个实例:



$dbcnx = mysql_connect("localhost", "root", "mypasswd");





  需要说明的是,对于你的MySQL服务器,上面这个函数中的三个参数的值可能是不同的。你应该注意到在这儿我们的mysql_connect 返回了一个值(我们称之为一个连接标识),这个值被我们存储在变量$dbcnx中。



  因为MySQL是一个完全分布式的软件,我们必须考虑到这些可能性:服务不可用、网络堵塞或者是我们的用户名及口令不匹配。在这些情况下,mysql_connect函数不能返回一个连接标识(因为连接未被建立)。这时,会返回一个逻辑假。这使得我们可以用一个if语句来处理连接的情况: $dbcnx = @mysql_connect("localhost", "root", "mypasswd");





if (!$dbcnx) {

  echo( "<P>Unable to connect to the " .

        "database server at this time.</P>" );

  exit();

}







  在上面的代码段中出现了三个新的东西,首先,我们在mysql_connect函数前加了一个@符号。包括mysql_connect在内的许多函数会在失败后显示难看的错误信息。在函数名前加一个@符号可以告诉这个函数当执行失败时,允许我们显示我们自己友好的出错信息。



  其次,在我们的if语句的条件中,$dbcnx变量前面加了一个惊叹号。这个惊叹号是PHP中的“否运算符”。也就是说将逻辑真变为逻辑假,将逻辑假变为逻辑真。这样,如果这个连接是失败的,mysql_connect会返回一个逻辑假,!$dbcnx将等于逻辑真,这样我们的if语句将被执行。相反,如果这个连接是成功的,存储在$dbcnx 中的连接标识将等于逻辑真(在PHP中,任何非零的数字都被认为是逻辑真),所以!$dbcnx会等于逻辑假,if语句将不会被执行。



  最后一个是exit函数,这是我们遇到的第一个没有参数的函数。这个函数的全部作用就是导致PHP停止对本页的阅读。如果数据库连接失败这是一个很好的响应,因为绝大多数情况下,如果不能连接到数据库,这一页不会显示任何有用的信息。



  和我们在第二章做过的一样,连接被建立后下一步就是选择工作的数据库。我们将要在第二章中所建立的笑话数据库中工作。这个数据库被命名为jokes。在PHP中用来选择数据库的另外一个函数:



mysql_select_db("jokes", $dbcnx);





  请注意我们在这儿使用了$dbcnx变量来指出了这个函数所使用的连接标识。这个参数实际上是可省略的。当省略这个参数时,函数会自动使用最后开启的那一个连接。这个函数成功后返回逻辑真,失败后返回逻辑假。为了谨慎起见,我们也用了一个if语句来处理错误:





if (! @mysql_select_db("jokes") ) {

  echo( "<P>Unable to locate the joke " .

        "database at this time.</P>" );

  exit();

}







  当建立了连接并选择了数据库之后,我们可以开始使用存储在数据库中的数据了。



在PHP中执行SQL查询



  在第二章中,我们使用一个叫mysql的程序来连接到MySQL数据库服务器,在这个程序中,我们可以输入SQL查询(命令)并立即显示查询结果。在PHP中,有着类似的机制:mysql_query函数。



mysql_query(<query>, <connection id>);





  在这儿,<query>是一个包含将执行的SQL命令的字符串。和mysql_select_db一样,连接标识这个参数也是可选的。



  这个函数的返回决定于发出的查询的类型。对于绝大多数的SQL命令来说,mysql_query返回逻辑真或逻辑假来标明执行是否成功。请参看下面这个例子,这是用来建立我们在第二章中建立的Jokes数据表的:





$sql = "CREATE TABLE Jokes ( " .

       "ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, " .

       "JokeText TEXT, " .

       "JokeDate DATE NOT NULL " .

       ")";

if ( mysql_query($sql) ) {

  echo("<P>Jokes table successfully created!</P>");

} else {

  echo("<P>Error creating Jokes table: " .

       mysql_error() . "</P>");

}







  这儿使用的mysql_error将以字符串的形式返回MySQL服务器最后发出的错误信息。



  对于DELETE、 INSERT以及UPDATE(用来修改存储的数据),MySQL可以知道有多少数据行被这个查询影响。参看下面的SQL命令,这个命令我们曾在第二章中用来设置所有包含单词“chicken”的笑话的日期:





$sql = "UPDATE Jokes SET JokeDate='1990-04-01' " .

       "WHERE JokeText LIKE '%chicken%'";

    当我们执行这个查询时,我们可以使用mysql_affected_rows函数来显示这个修改所影响的数据行的数目:

if ( mysql_query($sql) ) {

  echo("<P>Update affected " .

        mysql_affected_rows() . " rows.</P>");

} else {

  echo("<P>Error performing update: " .

       mysql_error() . "</P>");

}







  SELECT命令会有一些不同,因为它会得到许多信息,而PHP必须提供方法来处理这些信息。



处理SELECT结果集



  对于绝大多数的SQL查询来说,mysql_query函数仅仅返回逻辑真或逻辑假。而对于SELECT查询来说,仅仅这样显然是不够的。你应该还记得SELECT查询是用来显示数据库中存储的数据的。除了指出查询成功还是失败之外,PHP还必须得到查询的结果。作为一个结果,当我们执行一个SELECT查询的时候,mysql_query会返回一个标识“结果集”的数字,这将包含了这个查询返回的所有行的列表。如果查询失败,函数仍然是返回一个逻辑假。





$result = mysql_query("SELECT JokeText FROM Jokes");

if (!$result) {

  echo("<P>Error performing query: " .

       mysql_error() . "</P>");

  exit();

}







  假定在执行查询时没有遇到错误,上面的代码会定位一个有关存储在笑话库中所有笑话的正文的结果集,这个定位被存储在变量$result中。因为数据库中的笑话的数目是没有限制的,这个结果集可能非常庞大。



  我们之前曾经提到过while循环对于处理大量的数据来说是一个非常有用的控制语句,这是我们逐个处理结果集中数据行的代码的基本格式:





while ( $row = mysql_fetch_array($result) ) {

  // process the row...

}







  在这个while循环中的条件可能看上去与我们曾经使用过的有所不同,所以我们有必要在这里解释它的工作机理。你可以先把这个条件看成一个独立的语句:



$row = mysql_fetch_array($result);





  mysql_fetch_array函数以一个参数(对于这个例子来说是存储在$result变量中)接受到一个结果集,并以一个数据的形式返回结果集中的下一行。如果你还不熟悉数组的概念,不要担心,我们会在下面详细讨论它。如果在这个结果集中不再有其它数据行时,mysql_fetch_array返回逻辑假。



  现在,我们上面的语句定义了一个值到$row变量中,与此同时,整个语句也获得了同样的值。这就是我们在while循环的条件中使用这个语句的原因,因为while循环会一直执行循环直到条件等于逻辑假,结果集有几行,这个循环就会执行几次,每一次$row都会得到一个下一行的值,现在剩下的就是如何在循环中从$row变量中获得相应的值了。



  结果集中的行被描述成一个数组。数组是一个特殊类型的变量,这个变量可以包含多个值,如果你把一个变量看成是值的容器,你可以把数组看成是有间隔的容器,在每一个间隔中可以存储一个单独的值。对于我们的数据行来说,这个间隔是以数据表的列名命名的。如果$row是我们结果集中的一行,那么$row["JokeText"]就是这一行中JokeText列的值。所以如果我们想要显示我们的数据库中所在笑话的正文,while循环应该是这样的:





while ( $row = mysql_fetch_array($result) ) {

  echo("<P>" . $row["JokeText"] . "</P>");

}







  最后,作为一个总结,这是一段完整的PHP的Web页面的代码,它用来连接我们的数据库,取出数据库中所有笑话的正文,并将其在HTML中显示出来:





<HTML>

<HEAD>

<TITLE> Our List of Jokes </TITLE>

</HEAD>

<BODY>

<?php



  // Connect to the database server

  $dbcnx = @mysql_connect("localhost",

           "root", "mypasswd");

  if (!$dbcnx) {

    echo( "<P>Unable to connect to the " .

          "database server at this time.</P>" );

    exit();

  }



  // Select the jokes database

  if (! @mysql_select_db("jokes") ) {

    echo( "<P>Unable to locate the joke " .

          "database at this time.</P>" );

    exit();

  }



?>

<P> Here are all the jokes in our database: </P>

<BLOCKQUOTE>



<?php

    // Request the text of all the jokes

  $result = mysql_query(

            "SELECT JokeText FROM Jokes");

  if (!$result) {

    echo("<P>Error performing query: " .

         mysql_error() . "</P>");

    exit();

  }



  // Display the text of each joke in a paragraph

  while ( $row = mysql_fetch_array($result) ) {

    echo("<P>" . $row["JokeText"] . "</P>");

  }

?>

</BLOCKQUOTE>

</BODY>

</HTML>







向数据库中插入数据



  在这一节里,我们会看到我们会如何综合利用这些工具来让我们站点的访问者向数据库中添加他们自己的笑话。如果你喜欢挑战,你可以试试在向下看之前想想大致上应该怎么做。在这一节里只有很少新的东西。对于我们学过的东西来说,这只是一个简单的应用。



  如果我们想要让访问者能够输入新的笑话,我们首先需要一个表单,这儿是这个表单的代码:





<FORM ACTION="<?php echo($PHP_SELF); ?>" METHOD=POST>

<P>Type your joke here:<BR>

<TEXTAREA NAME="joketext" ROWS=10 COLS=40 WRAP></TEXTAREA><BR>

<INPUT TYPE=SUBMIT NAME="submitjoke" VALUE="SUBMIT">

</FORM>







  正如我们上面看到的那样,这个表单在提交时会载入同一个页面(因为我们在表单的ACTION属性中使用了$PHP_SELF变量),但是在再次载入时请求中包含了两个变量,首先是$joketext,这是在text域中输入的笑话的正文,另一个是$submitjoke,这个变量的值将始终是"SUBMIT",这用来标志笑话已被提交。



   要将已提交的笑话添加到数据库中,我们需要用mysql_query来运行一个INSERT查询,这个查询中将包含已经提交的$joketext变量的值:





if ("SUBMIT" == $submitjoke) {

  $sql = "INSERT INTO Jokes SET " .

         "JokeText='$joketext', " .

         "JokeDate=CURDATE()";

  if (mysql_query($sql)) {

    echo("<P>Your joke has been added.</P>");

  } else {

    echo("<P>Error adding submitted joke: " .

         mysql_error() . "</P>");

  }

}







  在全部的内容中只有SQL代码中出现了一个新的东西。在这里我们使用了一个MySQL函数CURDATE()来将新插入数据库的笑话的JokeDate列的值置为当前日期。事实上,MySQL有很多这样的函数,但是我们只会在使用到他们时才会介绍他们,要得到一个完整的函数的说明,你可以参看MySQL参考手册。
 
 
用PHP和MySQL构建一个数据库驱动的网站(7)
作者: 未知
日期:
 
Buy & Sell Ads
AdBrite is the Internet's Ad Marketplace
 
现在我们已经有了允许用户输入一个笑话并将其加入到我们的数据库中的程序代码。现在剩下的就是将其加入到我们已做好的笑话显示页面。因为绝大多数的用户只会想要看看笑话,所以我们不想对我们的页面做大的更改,除非用户表示想要添加一个新的笑话。因为这个原因,我们的应用程序应该是一个多功能的页面。下面是程序的代码:
 
 
 
 
 
<HTML>
 
...
 
<BODY>
 
<?php
 
 // If the user wants to add a joke
 
 if (isset($addjoke)):
 
?>
 
<FORM ACTION="<?php echo($PHP_SELF); ?>" METHOD=POST>
 
<P>Type your joke here:<BR>
 
<TEXTAREA NAME="joketext" ROWS=10 COLS=40 WRAP></TEXTAREA><BR>
 
<INPUT TYPE=SUBMIT NAME="submitjoke" VALUE="SUBMIT">
 
</FORM>
 
 
 
<?php
 
 else:
 
 
 
    // Connect to the database server
 
    $dbcnx = @mysql_connect("localhost",
 
             "root", "mypasswd");
 
    if (!$dbcnx) {
 
      echo( "<P>Unable to connect to the " .
 
            "database server at this time.</P>" );
 
      exit();
 
    }
 
 
 
    // Select the jokes database
 
    if (! @mysql_select_db("jokes") ) {
 
      echo( "<P>Unable to locate the joke " .
 
            "database at this time.</P>" );
 
      exit();
 
    }
 
 
 
    // If a joke has been submitted,
 
    // add it to the database.
 
    if ("SUBMIT" == $submitjoke) {
 
      $sql = "INSERT INTO Jokes SET " .
 
             "JokeText='$joketext', " .
 
             "JokeDate=CURDATE()";
 
       if (mysql_query($sql)) {
 
        echo("<P>Your joke has been added.</P>");
 
      } else {
 
        echo("<P>Error adding submitted joke: " .
 
             mysql_error() . "</P>");
 
      }
 
    }
 
      echo("<P> Here are all the jokes " .
 
         "in our database: </P>");
 
      // Request the text of all the jokes
 
    $result = mysql_query(
 
              "SELECT JokeText FROM Jokes");
 
    if (!$result) {
 
      echo("<P>Error performing query: " .
 
           mysql_error() . "</P>");
 
      exit();
 
    }
 
      // Display the text of each joke in a paragraph
 
    while ( $row = mysql_fetch_array($result) ) {
 
      echo("<P>" . $row["JokeText"] . "</P>");
 
    }
 
    // When clicked, this link will load this page
 
    // with the joke submission form displayed.
 
    echo("<P><A HREF='$PHP_SELF?addjoke=1'>" .
 
         "Add a Joke!</A></P>");
 
    endif;
 
 ?>
 
</BODY>
 
</HTML>
 
 
 
 
 
 
 
  现在我们有了一个单独的文件,这个文件包含不太多的PHP代码,通过这个文件,我们可以显示我们的MySQL数据库中的笑话并能向我们的MySQL数据库中添加笑话。
 
 
 
一个挑战
 
 
 
  作为家庭作业,你可以看看你是不是能解决这么一个问题:在页面上显示的每一个笑话后面放置一个叫“Delete this Joke”的超连接,当单击这个连接时,会从数据库中删除这个笑话并显示更改过以后的笑话列表。下面是对你的一些提示:
 
 
 
  你可以还在一个多功能页面完成全部的功能。
 
 
 
  你需要使用SQL的DELETE命令,这个命令我们曾在第二章中学习过。
 
 
 
  这是一个关键的问题。要删除一个指定的数据库,你需要能够唯一地标识它。Jokes表中的ID可以完成这个功能。你必须将要被删除的笑话的ID传递到删除笑话的请求中。将这个值放到“Delete this Joke”连接的查询字符串中是比较合适的。
 
 
 
  如果你觉得你已经有了答案,或者你只想知道解决方案,那就去看看下一页。祝你好运!
 
 
 
结语
 
 
 
  在这一章中,我们学习了一些新的用来实现与MySQL数据库服务接口的PHP函数。使用这些函数,我们建立了我们的第一个数据库驱动的网站,我们的这个网站可以在线地发布我们数据库中笑话并允许访问者向其中添加他们自己的笑话。
 
 
 
  在第五章中,我们会回到MySQL命令行去学习如何使用关系型数据库的原理以及其他一些更高级的SQL查询去描述更为复杂的信息,并给予访问者对他们自己添加的笑话以特别的权限!
 
 
 
挑战的解决
 
 
 
  这是我们上面提出的“家庭作业”的解决方案。要在每一个笑话后面添加一个“Delete this Joke”连接,必须作下面的改动:
 
 
 
  之前,我们曾经在我们的页面的底端的“Add a Joke!”连接中传递过一个$addjoke变量,通过这个变量来通知我们的脚本不再显示通常的笑话列表,而是显示一个录入笑话的表单。与此相类似,我们在我们的“Delete this Joke”连接中传递一个$deletejoke变量来表示我们想要删除一个笑话。
 
 
 
  在获得每一个笑话的JokeText列的同时,我们还获得了ID列的值,所以我们获得了与数据库中每一个笑话关联的ID。
 
 
 
  我们将要删除的笑话的ID值赋予$deletejoke变量。这是通过将从数据库中获得的ID值插入到每一个笑话的“Delete this Joke”连接中来实现的。
 
 
 
  使用了一个if 语句,如果在载入这一页时,我们的$deletejoke被赋予了一个值(使用isset函数),我们会在一个SQLDELETE语句中使用这个值(将被删除的笑话的ID)来删除指定的笑话。
 
 
 
  这儿是全部的源代码:
 
 
 
 
 
<HTML>
 
...
 
<BODY>
 
<?php
 
 // If the user wants to add a joke
 
 if (isset($addjoke)):
 
?>
 
 
 
<FORM ACTION="<?php echo($PHP_SELF); ?>" METHOD=POST>
 
<P>Type your joke here:<BR>
 
<TEXTAREA NAME="joketext" ROWS=10 COLS=40 WRAP></TEXTAREA><BR>
 
<INPUT TYPE=SUBMIT NAME="submitjoke" VALUE="SUBMIT">
 
</FORM>
 
<?php
 
 else:
 
 
 
    // Connect to the database server
 
    $dbcnx = @mysql_connect(
 
               "localhost", "root", "mypasswd");
 
    if (!$dbcnx) {
 
      echo( "<P>Unable to connect to the " .
 
            "database server at this time.</P>" );
 
      exit();
 
    }
 
 
 
    // Select the jokes database
 
    if (! @mysql_select_db("jokes") ) {
 
      echo( "<P>Unable to locate the joke " .
 
            "database at this time.</P>" );
 
      exit();
 
    }
 
    // If a joke has been submitted,
 
    // add it to the database.
 
    if ("SUBMIT" == $submitjoke) {
 
      $sql = "INSERT INTO Jokes SET " .
 
             "JokeText='$joketext', " .
 
             "JokeDate=CURDATE()";
 
      if (mysql_query($sql)) {
 
        echo("<P>Your joke has been added.</P>");
 
      } else {
 
        echo("<P>Error adding submitted joke: " .
 
             mysql_error() . "</P>");
 
      }
 
    }
 
 
 
    // If a joke has been deleted,
 
    // remove it from the database.
 
    if (isset($deletejoke)) {
 
      $sql = "DELETE FROM Jokes " .
 
             "WHERE ID=$deletejoke";
 
      if (mysql_query($sql)) {
 
        echo("<P>The joke has been deleted.</P>");
 
      } else {
 
        echo("<P>Error deleting joke: " .
 
             mysql_error() . "</P>");
 
      }
 
    }
 
      echo("<P> Here are all the jokes " .
 
         "in our database: </P>");
 
      // Request the ID and text of all the jokes
 
    $result = mysql_query(
 
                "SELECT ID, JokeText FROM Jokes");
 
    if (!$result) {
 
      echo("<P>Error performing query: " .
 
           mysql_error() . "</P>");
 
      exit();
 
    }
 
    // Display the text of each joke in a paragraph
 
    // with a "Delete this Joke" link next to each.
 
   while ( $row = mysql_fetch_array($result) ) {
 
      $jokeid = $row["ID"];
 
      $joketext = $row["JokeText"];
 
      echo("<P>$joketext " .
 
           "<A HREF='$PHP_SELF?deletejoke=$jokeid'>" .
 
           "Delete this Joke</A></P>");
 
    }
 
    // When clicked, this link will load this page
 
    // with the joke submission form displayed.
 
    echo("<P><A HREF='$PHP_SELF?addjoke=1'>" .
 
         "Add a Joke!</A></P>");
 
    endif;
 
 ?>
 
</BODY>
 
</HTML>
 
 
用PHP和MySQL构建一个数据库驱动的网站(八)
在这一章中,我们会对我们的例子进行扩充,学习一些有关MySQL的新知识,并试图理解并掌握关系型数据库所能提供的功能。
 
 
 
(2002-08-29 14:11:39)
 
 
 
--------------------------------------------------------------------------------
 
By Wing, 出处:Linuxaid
 
 
 
 
 
第五章:关系型数据库设计
 
 
 
  在这篇文章的第二章中,我们已经建立了一个供我们使用的非常简单的笑话数据库,这个库中只包括了一个名叫Jokes的数据表。这作为我们使用MySQL数据库的入门已经是足够了,但是在关系型数据库的设计中还有很多其它的东西。在这一章中,我们会对我们的例子进行扩充,学习一些有关MySQL的新知识,并试图理解并掌握关系型数据库所能提供的功能。
 
 
 
  首先,我们得说明我们对许多问题的解决只是不正规的(也就是说非正式的)。正如你在许多计算机科学专业中了解的那样,数据库设计是一个严肃的领域,数据库设计必须包括对它的测试并会涉及到一些数学的原理。但这些可能是超过我们这篇文章的范围了。要得到更多的信息,你可以停下来到http://www.datamodel.org/去看看,在那儿你可以看到许多好的书籍,并得到一些关于这个问题的有用的资源。
 
 
 
给予应有的权限
 
 
 
  在开始之前,让我们回忆一下我们的Jokes数据表的结构,这个表包含三个列:ID、JokeText和 JokeDate。这些列可以使我们标识笑话(ID),明了他们的内容(JokeText)以及他们被加入的时间(JokeDate)。
 
 
 
  现在我们想要保存我们的笑话中的其它一些信息:提交者的姓名。这看上去很自然,我们需要在我们的Jokes数据表中添加一个新的列。SQL的ALTER命令(我们在之前没看到过这个命令)可以帮助我们完成这件事。使用mysql命令行程序登录到MySQL服务器,选择你的数据库(如果你使用我们在第二章中的命名,数据库名应该是joke),然后输入下面的命令:
 
 
 
mysql>
 
ALTER TABLE Jokes ADD COLUMN
 
    -> AuthorName VARCHAR(100);
 
 
 
 
 
 
 
  这将会在我们的数据表中增加一个叫AuthorName的列。其数据类型是一个可变长度的字符串,其最大长度是100个字符(这对于最复杂的名字应该也是足够了)。让我们再添加一列用来保存作者的e-mail地址:
 
 
 
 
 
mysql> ALTER TABLE Jokes ADD COLUMN
 
    -> AuthorEMail VARCHAR(100);
 
 
 
 
 
 
 
  要得到更多的有关ALTER命令的信息,请参看MySQL参考手册。要确认我们是不是正确地添加了两列,你可以要求MySQL为我们对这个表进行描述:
 
 
 
 
 
mysql> DESCRIBE Jokes;
 
+-------------+--------------+------+-----+-- - -
 
| Field | Type | Null | Key | Def...
 
+-------------+--------------+------+-----+-- - -
 
| ID | int(11) | | PRI | ...
 
| JokeText | text | YES | | ...
 
| JokeDate | date | | | ...
 
| AuthorName | varchar(100) | YES | | ...
 
| AuthorEMail | varchar(100) | YES | | ...
 
+-------------+--------------+------+-----+-- - -
 
5 rows in set (0.01 sec)
 
 
 
 
 
 
 
  看上去很不错。明显地,我们需要对我们在第四章中建立的添加新笑话的HTML以及PHP格式的代码进行调整,但是我们会把这留给你作为一个练习。使用UPDATE查询,你现在可以对表中的所有笑话添加作者的详细资料。然而,在你开始接受这个数据结构之前,我们必须考虑一下我们在这儿选择的设计是否确当。在这种情况下,我们会发现一些我们还没有做到的事情。
 
 
 
一个基本的规则:保持事物的分离
 
 
 
  在你建立数据库驱动的网站的过程中,你已经觉得仅仅是有一个笑话列表是不够的。事实上,除了你自己的笑话以外,你开始接收其他人提交的笑话。你决定做一个让全世界人都可以共享笑话的网站。你有没有听说过Internet电影数据库(IMDB)?实际上你现在做的是Internet笑话数据库(IJDB)!对每一个笑话添加作者的姓名和e-mail地址肯定是最容易想到的办法,但是这种方法会导致一些潜在的问题:
 
 
 
  如果一个经常投稿的名叫Joan Smith的人改变了她的e-mail地址将会发生什么什么情况呢?她会开始使用新地址来提交新的笑话,但是对于所有的旧笑话,你所能看到的还是旧的地址。从你的数据库来看,你也许只能认为有两人名字都叫Joan Smith的人在向你的数据库中提交笑话。如果她是特别体贴的,她也许会通知你改变地址,你可以将所有的旧笑话改成新的地址,但是如果你遗漏了一个,那就意味着你的数据库中存储了错误的信息。数据库设计专家将这种类型的问题称之为一个“更正异常”。
 
 
 
  很自然地你会想到从你的数据库中得到所有曾经向你的站点提交过笑话的人的列表。实际上,你可以使用下面的查询很容易地得到这样的列表:
 
 
 
mysql> SELECT DISTINCT AuthorName, AuthorEMail -> FROM Jokes;
 
 
 
 
 
  上面查询中DISTINCT是告诉MySQL不输出重复的结果行。例如,如果Joan Smith向我们的站点提交过20个笑话,如果我们使用了DISTINCT选项,她的名字和e-mail地址将会只在列表中出现一次,否则会出现20次。
 
 
 
  如果因为某种原因,你决定要从数据库中删除某个特定的作者所提交的所有笑话,但是,与此同时,你将不能再通过e-mail与他们联系!而你的e-mail清单可能是你的网站的收入的主要来源,所以你并不想只因为你不喜欢他们提交的笑话,就删除他们的e-mail地址。数据库设计专家将这称之为“删除异常”。
 
 
 
  你并不能保证不会出现这样的情况:Joan Smith输入的姓名一会儿是“Joan Smith”,一会儿是“J. Smith”,一会儿又是“Smith, Joan”。这将使得你要确定一个特定的作者变得非常困难(特别是Joan Smith又经常使用几个不同的email地址的时候)。
 
 
 
  这些问题的解决其实很简单。只要你不再将作者的信息存储到Jokes数据表中,而是建立一个新的数据表来存储作者列表。因为我们在Jokes数据表中使用了一个叫ID的列来用一个数据标识每个笑话,所以我们在新的数据表中使用了同样名字的列来标识我们的作者。我们可以在我们的Jokes表中使用“author ID's”来建立笑话和他的作者之间的关联。全部的数据库设计应该是这样的:
 
 
 
  上面的两个表包含了三个笑话和两个作者。Jokes表的AID列(“Author ID”的缩写)提供了两个表之间的关联(指出Kevin Yank 提交了笑话1和笑话2,Joan Smith提交了笑话3)。在这里,你还需要注意到每一个作者只会在数据库中出现一次,而且他们是独立于他们提交的笑话而存在的,因此我们已经解决了我们上面提出的那些问题。
 
 
 
  这个数据库设计的最重要的特征是,因为我们要存储两种类型的事物(笑话和作者),所以我们设计两个表。这是我们在数据库设计中要遵守的一个基本规则:对于每一个要存储其信息的实体(或事物),我们都应该给他一个自己的表。
 
 
 
  重新生成上面的数据是非常简单的(只要使用两个CREATE TABLE 查询就行了),但是因为我们想要在做这些变动时不会有破坏性的效果(也就是说不会丢失我们已经存入的笑话),所以我们需要再次使用ALTER命令。 首先,我们删除Jokes表中有关作者的列:
 
 
 
 
 
mysql> ALTER TABLE Jokes DROP COLUMN AuthorName;
 
Query OK, 0 rows affected (0.00 sec)
 
Records: 0 Duplicates: 0 Warnings: 0
 
mysql> ALTER TABLE Jokes DROP COLUMN AuthorEMail;
 
Query OK, 0 rows affected (0.00 sec)
 
Records: 0 Duplicates: 0 Warnings: 0
 
    现在我们建立我们的新的数据表:
 
mysql> CREATE TABLE Authors (
 
    -> ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
 
    -> Name VARCHAR(100),
 
    -> EMail VARCHAR(100)
 
    -> );
 
    最后,我们在我们的Jokes表中添加AID列:
 
mysql> ALTER TABLE Jokes ADD COLUMN AID INT;
 
 
 
 
 
 
 
  现在剩下来的就是向新的表中添加一些作者,并通过填充AID列来对数据库中已经存在的笑话指定作者。
 
 
 
处理多个表
 
 
 
  现在我们的数据被分布在两个表当中,要从其中获得数据看上去变得更加复杂了。例如,我们最初的目标是:显示一个笑话的列表并在每一个笑话后面显示作者的姓名和e-mail地址。在我们的单表结构中,要获得所有的信息,只需要在我们的PHP代码中使用一个SELECT语句就行了:
 
 
 
 
 
$jokelist = mysql_query(
 
 "SELECT JokeText, AuthorName, AuthorEMail ".
 
 "FROM Jokes");
 
 
 
while ($joke = mysql_fetch_array($jokelist)) {
 
 $joketext = $joke["JokeText"];
 
 $name = $joke["AuthorName"];
 
 $email = $joke["AuthorEMail"];
 
 
 
 // Display the joke with author information
 
 echo( "<P>$joketext<BR>" .
 
        "(by <HREF='mailto:$email'>$name)</P>" );
 
}
 
 
 
 
 
 
 
  在我们的新系统中,这样做初看起来是不可能了。因为有关每个笑话的作者的详细资料不是存储在Jokes表中,我们可能想到的一个解决方案是我们对于我们想要显示的笑话单独地获得这些资料。代码将是这样的:
 
 
 
 
 
// Get the list of jokes
 
$jokelist = mysql_query(
 
 "SELECT JokeText, AID FROM Jokes");
 
 
 
while ($joke = mysql_fetch_array($jokelist)) {
 
 
 
 // Get the text and Author ID for the joke
 
 $joketext = $joke["JokeText"];
 
 $aid = $joke["AID"];
 
 // Get the author details for the joke
 
 $authordetails = mysql_query(
 
    "SELECT Name, Email FROM Authors WHERE ID=$aid");
 
 $author = mysql_fetch_array($authordetails);
 
 $name = $author["Name"];
 
 $email = $author["EMail"];
 
 
 
 // Display the joke with author information
 
 echo( "<P>$joketext<BR>" .
 
        "(by <A HREF='mailto:$email'>$name)</P>" );
 
}
 
 
 
 
 
 
 
  很混乱,而且对于每一个显示的笑话都包含了一个对数据库的查询,这将会我们的页面的显示非常缓慢。现在看来,“老方法”可能是更好的解决方案,尽管它有其自身的弱点。
 
 
 
  幸运的是,关系型数据库可以很容易地处理多个表中的数据!在SELECT语句中使用一个新的被称之为“join”的格式,我们可以找到两全其美的办法。连接可以使我们象对存储在单个表中的数据那样对待多个表中的关联数据。一个连接的格式应该是这样的:
 
 
 
 
 
mysql> SELECT <columns> FROM <tables>
 
    -> WHERE <condition(s) for data to be related>
 
 
 
 
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页