一个PHP与php连接数据库库的问题

php+mysql 问题 百度一个星期 竟无人解决
[问题点数:100分,结帖人aiwojue]
php+mysql 问题 百度一个星期 竟无人解决
[问题点数:100分,结帖人aiwojue]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
相关帖子推荐:
2010年6月 PHP大版内专家分月排行榜第二
2010年8月 PHP大版内专家分月排行榜第三
2010年11月 PHP大版内专家分月排行榜第二2010年10月 PHP大版内专家分月排行榜第二2010年7月 PHP大版内专家分月排行榜第二2009年8月 PHP大版内专家分月排行榜第二
2010年2月 PHP大版内专家分月排行榜第二
2009年4月 PHP大版内专家分月排行榜第三
2010年8月 PHP大版内专家分月排行榜第二
2010年7月 PHP大版内专家分月排行榜第三
2010年2月 PHP大版内专家分月排行榜第二
2009年4月 PHP大版内专家分月排行榜第三
2013年5月 总版技术专家分月排行榜第一
2014年8月 总版技术专家分月排行榜第二2014年7月 总版技术专家分月排行榜第二2013年6月 总版技术专家分月排行榜第二
2010年2月 PHP大版内专家分月排行榜第二
2009年4月 PHP大版内专家分月排行榜第三
2010年11月 PHP大版内专家分月排行榜第二2010年10月 PHP大版内专家分月排行榜第二2010年7月 PHP大版内专家分月排行榜第二2009年8月 PHP大版内专家分月排行榜第二
2010年4月 PHP大版内专家分月排行榜第三2010年1月 PHP大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。帮我写一个php的数据库搜索页面。_百度知道
帮我写一个php的数据库搜索页面。
(php+mysql) 数据库只有一个表keywords,三个字段:word
add_time请高手帮我写一个简单的搜索,输入关键字,在word字段中搜索,如包含该关键字则在搜索结果页面按count降序列出搜索结果。谢谢,分不多,是个心意。可以在我的小站帮您做个广告作为酬谢。
问题已解决,谢谢各位朋友的关心!!!
提问者采纳
HI我,我帮你。
提问者评价
非常热心的说!太感谢你了!!!
其他类似问题
php的相关知识
其他3条回答
order by count desc
select * from keywords where word like '%关键字%' order by count desc这个是基本的sql语句
获得结果集以后 怎么遍历 输出到页面 那就是你的事了 你既然有自己的站点 这些应该难不住你的
search.html //前台网页编写&html&&head&&meta http-equiv=&Content-Type&content=&text/charset=gb2312&&&title&搜索&/title&&/head&&body&&form name=&form& action=&search.php& method=&post&&&input type=&text& name=&search_text& size=&20&&&input type=&submit& value=&搜索&&&/form&&/body&&/html&search.php//后台处理文件&?php
$word=$_POST[&search_text&]; $link=mysql_connect(&localhost&,&root&,&password&) or die(&无法连接&);
//localhost、root和password需要根据自己的实际情况来使用。
$db_selected=mysql_select_db(&db_keywords&,$link);
//db_keywords为要打开的数据库。
$sql=&select * from keywords where word like '%$word%' order by count desc&;
//keywords为要打开查询的表
$result=mysql_query($sql,$link);
while($row=mysql_fetch_row($result))
for($i=0;$i&mysql_num_fields($result);$i++)
echo &$row[$i]&.&
echo &&br&&;
}?& 这是最简单也是具有最基本功能的搜索页面,其他的需要自己修改和处理了。 希望对你有所帮助。
您可能关注的推广
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁揭露PHP应用程序中出现的五个常见数据库问题&&包括数据库模式设计、数据库访问和使用数据库的业务逻辑代码&&以及它们的解决方案。如果只有一种方式使用数据库是正确的&&您可以用很多的方式创建数据库设计、数据库访问和基于数据库的PHP业务逻辑代码,但最终一般以错误告终。本文说明了数据库设计和访问数据库的PHP代码中出现的五个常见问题,以及在遇到这些问题时如何修复它们。问题1:直接使用MySQL一个常见问题是较老的PHP代码直接使用mysql_函数来访问数据库。清单1展示了如何直接访问数据库。清单1.Access/get.php
<?phpfunctionget_user_id($name){ $db=mysql_connect('localhost','root','password'); mysql_select_db('users'); $res=mysql_query(&SELECTidFROMusersWHERElogin='&.$name.&'&); while($row=mysql_fetch_array($res)){$id=$row[0];} return$}var_dump(get_user_id('jack'));?>注意使用了mysql_connect函数来访问数据库。还要注意查询,其中使用字符串连接来向查询添加$name参数。该技术有两个很好的替代方案:PEARDB模块和PHPDataObjects(PDO)类。两者都从特定数据库选择提供抽象。因此,您的代码无需太多调整就可以在IBM?DB2?、MySQL、PostgreSQL或者您想要连接到的任何其他数据库上运行。使用PEARDB模块和PDO抽象层的另一个价值在于您可以在SQL语句中使用?操作符。这样做可使SQL更加易于维护,且可使您的应用程序免受SQL注入攻击。使用PEARDB的替代代码如下所示。清单2.Access/get_good.php
<?phprequire_once(&DB.php&);functionget_user_id($name){ $dsn='mysql://root:password@localhost/users'; $db=&DB::Connect($dsn,array()); if(PEAR::isError($db)){die($db->getMessage());} $res=$db->query('SELECTidFROMusersWHERElogin=?',array($name)); $id= while($res->fetchInto($row)){$id=$row[0];} return$}var_dump(get_user_id('jack'));?>注意,所有直接用到MySQL的地方都消除了,只有$dsn中的数据库连接字符串除外。此外,我们通过?操作符在SQL中使用$name变量。然后,查询的数据通过query()方法末尾的array被发送进来。问题2:不使用自动增量功能与大多数现代数据库一样,MySQL能够在每记录的基础上创建自动增量惟一标识符。除此之外,我们仍然会看到这样的代码,即首先运行一个SELECT语句来找到最大的id,然后将该id增1,并找到一个新记录。清单3展示了一个示例坏模式。清单3.Badid.sql
DROPTABLEIFEXISTSCREATETABLEusers(idMEDIUMINT,loginTEXT,passwordTEXT);INSERTINTOusersVALUES(1,'jack','pass');INSERTINTOusersVALUES(2,'joan','pass');INSERTINTOusersVALUES(1,'jane','pass');这里的id字段被简单地指定为整数。所以,尽管它应该是惟一的,我们还是可以添加任何值,如CREATE语句后面的几个INSERT语句中所示。清单4展示了将用户添加到这种类型的模式的PHP代码。清单4.Add_user.php
<?phprequire_once(&DB.php&);functionadd_user($name,$pass){ $rows=array(); $dsn='mysql://root:password@localhost/bad_badid'; $db=&DB::Connect($dsn,array()); if(PEAR::isError($db)){die($db->getMessage());} $res=$db->query(&SELECTmax(id)FROMusers&); $id= while($res->fetchInto($row)){$id=$row[0];} $id+=1; $sth=$db->prepare(&INSERTINTOusersVALUES(?,?,?)&); $db->execute($sth,array($id,$name,$pass)); return$}$id=add_user('jerry','pass');var_dump($id);?>add_user.php中的代码首先执行一个查询以找到id的最大值。然后文件以id值加1运行一个INSERT语句。该代码在负载很重的服务器上会在竞态条件中失败。另外,它也效率低下。那么替代方案是什么呢?使用MySQL中的自动增量特性来自动地为每个插入创建惟一的ID。更新后的模式如下所示。清单5.Goodid.php
DROPTABLEIFEXISTSCREATETABLEusers( idMEDIUMINTNOTNULLAUTO_INCREMENT, loginTEXTNOTNULL, passwordTEXTNOTNULL, PRIMARYKEY(id));INSERTINTOusersVALUES(null,'jack','pass');INSERTINTOusersVALUES(null,'joan','pass');INSERTINTOusersVALUES(null,'jane','pass');我们添加了NOTNULL标志来指示字段必须不能为空。我们还添加了AUTO_INCREMENT标志来指示字段是自动增量的,添加PRIMARYKEY标志来指示那个字段是一个id。这些更改加快了速度。清单6展示了更新后的PHP代码,即将用户插入表中。清单6.Add_user_good.php
<?phprequire_once(&DB.php&);functionadd_user($name,$pass){ $dsn='mysql://root:password@localhost/good_genid'; $db=&DB::Connect($dsn,array()); if(PEAR::isError($db)){die($db->getMessage());} $sth=$db->prepare(&INSERTINTOusersVALUES(null,?,?)&); $db->execute($sth,array($name,$pass)); $res=$db->query(&SELECTlast_insert_id()&); $id= while($res->fetchInto($row)){$id=$row[0];} return$}$id=add_user('jerry','pass');var_dump($id);?>
现在我不是获得最大的id值,而是直接使用INSERT语句来插入数据,然后使用SELECT语句来检索最后插入的记录的id。该代码比最初的版本及其相关模式要简单得多,且效率更高。
#p#分页标题#e#
问题3:使用多个数据库偶尔,我们会看到一个应用程序中,每个表都在一个单独的数据库中。在非常大的数据库中这样做是合理的,但是对于一般的应用程序,则不需要这种级别的分割。此外,不能跨数据库执行关系查询,这会影响使用关系数据库的整体思想,更不用说跨多个数据库管理表会更困难了。那么,多个数据库应该是什么样的呢?首先,您需要一些数据。清单7展示了分成4个文件的这样的数据。清单7.数据库文件
Files.sql:CREATETABLEfiles( idMEDIUMINT, user_idMEDIUMINT, nameTEXT, pathTEXT);Load_files.sql:INSERTINTOfilesVALUES(1,1,'test1.jpg','files/test1.jpg');INSERTINTOfilesVALUES(2,1,'test2.jpg','files/test2.jpg');Users.sql:DROPTABLEIFEXISTSCREATETABLEusers( idMEDIUMINT, loginTEXT, passwordTEXT);Load_users.sql:INSERTINTOusersVALUES(1,'jack','pass');INSERTINTOusersVALUES(2,'jon','pass');在这些文件的多数据库版本中,您应该将SQL语句加载到一个数据库中,然后将usersSQL语句加载到另一个数据库中。用于在数据库中查询与某个特定用户相关联的文件的PHP代码如下所示。清单8.Getfiles.php
<?phprequire_once(&DB.php&);functionget_user($name){ $dsn='mysql://root:password@localhost/bad_multi1'; $db=&DB::Connect($dsn,array()); if(PEAR::isError($db)){die($db->getMessage());} $res=$db->query(&SELECTidFROMusersWHERElogin=?&,array($name)); $uid= while($res->fetchInto($row)){$uid=$row[0];} return$}functionget_files($name){ $uid=get_user($name); $rows=array(); $dsn='mysql://root:password@localhost/bad_multi2'; $db=&DB::Connect($dsn,array()); if(PEAR::isError($db)){die($db->getMessage());} $res=$db->query(&SELECT*FROMfilesWHEREuser_id=?&,array($uid)); while($res->fetchInto($row)){$rows[]=$} return$}$files=get_files('jack');var_dump($files);?>get_user函数连接到包含用户表的数据库并检索给定用户的ID。get_files函数连接到文件表并检索与给定用户相关联的文件行。做所有这些事情的一个更好办法是将数据加载到一个数据库中,然后执行查询,比如下面的查询。清单9.Getfiles_good.php
<?phprequire_once(&DB.php&);functionget_files($name){ $rows=array(); $dsn='mysql://root:password@localhost/good_multi'; $db=&DB::Connect($dsn,array()); if(PEAR::isError($db)){die($db->getMessage());} $res=$db->query(&SELECTfiles.*FROMusers,filesWHEREusers.login=?ANDusers.id=files.user_id&,array($name)); while($res->fetchInto($row)){$rows[]=$} return$}$files=get_files('jack');var_dump($files);?>
该代码不仅更短,而且也更容易理解和高效。我们不是执行两个查询,而是执行一个查询。尽管该问题听起来有些牵强,但是在实践中我们通常总结出所有的表应该在同一个数据库中,除非有非常迫不得已的理由。
#p#分页标题#e#
问题4:不使用关系关系数据库不同于编程语言,它们不具有数组类型。相反,它们使用表之间的关系来创建对象之间的一到多结构,这与数组具有相同的效果。我在应用程序中看到的一个问题是,工程师试图将数据库当作编程语言来使用,即通过使用具有逗号分隔的标识符的文本字符串来创建数组。请看下面的模式。清单10.Bad.sql
DROPTABLEIFEXISTSCREATETABLEfiles( idMEDIUMINT, nameTEXT, pathTEXT);DROPTABLEIFEXISTSCREATETABLEusers( idMEDIUMINT, loginTEXT, passwordTEXT, filesTEXT);INSERTINTOfilesVALUES(1,'test1.jpg','media/test1.jpg');INSERTINTOfilesVALUES(2,'test1.jpg','media/test1.jpg');INSERTINTOusersVALUES(1,'jack','pass','1,2');系统中的一个用户可以具有多个文件。在编程语言中,应该使用数组来表示与一个用户相关联的文件。在本例中,程序员选择创建一个files字段,其中包含一个由逗号分隔的文件id列表。要得到一个特定用户的所有文件的列表,程序员必须首先从用户表中读取行,然后解析文件的文本,并为每个文件运行一个单独的SELECT语句。该代码如下所示。清单11.Get.php
<?phprequire_once(&DB.php&);functionget_files($name){ $dsn='mysql://root:password@localhost/bad_norel'; $db=&DB::Connect($dsn,array()); if(PEAR::isError($db)){die($db->getMessage());} $res=$db->query(&SELECTfilesFROMusersWHERElogin=?&,array($name)); $files= while($res->fetchInto($row)){$files=$row[0];} $rows=array(); foreach(split(',',$files)as$file) {$res=$db->query(&SELECT*FROMfilesWHEREid=?&,array($file));while($res->fetchInto($row)){$rows[]=$} } return$}$files=get_files('jack');var_dump($files);?>该技术很慢,难以维护,且没有很好地利用数据库。惟一的解决方案是重新架构模式,以将其转换回到传统的关系形式,如下所示。清单12.Good.sql
DROPTABLEIFEXISTSCREATETABLEfiles( idMEDIUMINT, user_idMEDIUMINT, nameTEXT, pathTEXT);DROPTABLEIFEXISTSCREATETABLEusers( idMEDIUMINT, loginTEXT, passwordTEXT);INSERTINTOusersVALUES(1,'jack','pass');INSERTINTOfilesVALUES(1,1,'test1.jpg','media/test1.jpg');INSERTINTOfilesVALUES(2,1,'test1.jpg','media/test1.jpg');这里,每个文件都通过user_id函数与文件表中的用户相关。这可能与任何将多个文件看成数组的人的思想相反。当然,数组不引用其包含的对象&&事实上,反之亦然。但是在关系数据库中,工作原理就是这样的,并且查询也因此要快速且简单得多。清单13展示了相应的PHP代码。清单13.Get_good.php
<?phprequire_once(&DB.php&);functionget_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(&SELECTfiles.*FROMusers,filesWHEREusers.login=?ANDusers.id=files.user_id&,array($name)); while($res->fetchInto($row)){$rows[]=$} return$}$files=get_files('jack');var_dump($files);?>
这里,我们对数据库进行一次查询,以获得所有的行。代码不复杂,并且它将数据库作为其原有的用途使用。
#p#分页标题#e#
问题5:n+1模式我真不知有多少次看到过这样的大型应用程序,其中的代码首先检索一些实体(比如说客户),然后来回地一个一个地检索它们,以得到每个实体的详细信息。我们将其称为n+1模式,因为查询要执行这么多次&&一次查询检索所有实体的列表,然后对于n个实体中的每一个执行一次查询。当n=10时这还不成其为问题,但是当n=100或n=1000时呢?然后肯定会出现低效率问题。清单14展示了这种模式的一个例子。清单14.Schema.sql
DROPTABLEIFEXISTSCREATETABLEauthors( idMEDIUMINTNOTNULLAUTO_INCREMENT, nameTEXTNOTNULL, PRIMARYKEY(id));DROPTABLEIFEXISTSCREATETABLEbooks( idMEDIUMINTNOTNULLAUTO_INCREMENT, author_idMEDIUMINTNOTNULL, nameTEXTNOTNULL, PRIMARYKEY(id));INSERTINTOauthorsVALUES(null,'JackHerrington');INSERTINTOauthorsVALUES(null,'DaveThomas');INSERTINTObooksVALUES(null,1,'CodeGenerationinAction');INSERTINTObooksVALUES(null,1,'PodcastingHacks');INSERTINTObooksVALUES(null,1,'PHPHacks');INSERTINTObooksVALUES(null,2,'PragmaticProgrammer');INSERTINTObooksVALUES(null,2,'Rubyalign=centerbgColor=#e7e9e9border=1&
<?phprequire_once('DB.php');$dsn='mysql://root:password@localhost/good_books';$db=&DB::Connect($dsn,array());if(PEAR::isError($db)){die($db->getMessage());}functionget_author_id($name){ global$ $res=$db->query(&SELECTidFROMauthorsWHEREname=?&,array($name)); $id= while($res->fetchInto($row)){$id=$row[0];} return$}functionget_books($id){ global$ $res=$db->query(&SELECTidFROMbooksWHEREauthor_id=?&,array($id)); $ids=array(); while($res->fetchInto($row)){$ids[]=$row[0];} return$}functionget_book($id){ global$ $res=$db->query(&SELECT*FROMbooksWHEREid=?&,array($id)); while($res->fetchInto($row)){return$} }$author_id=get_author_id('JackHerrington');$books=get_books($author_id);foreach($booksas$book_id){ $book=get_book($book_id); var_dump($book);}?>如果您看看下面的代码,您可能会想,&嘿,这才是真正的清楚明了。&首先,得到作者id,然后得到书籍列表,然后得到有关每本书的信息。的确,它很清楚明了,但是其高效吗?回答是否定的。看看只是检索JackHerrington的书籍时要执行多少次查询。一次获得id,另一次获得书籍列表,然后每本书执行一次查询。三本书要执行五次查询!解决方案是用一个函数来执行大量的查询,如下所示。清单16.Get_good.php
<?phprequire_once('DB.php');$dsn='mysql://root:password@localhost/good_books';$db=&DB::Connect($dsn,array());if(PEAR::isError($db)){die($db->getMessage());}functionget_books($name){ global$ $res=$db->query(&SELECTbooks.*FROMauthors,booksWHEREbooks.author_id=authors.idANDauthors.name=?&, array($name)); $rows=array(); while($res->fetchInto($row)){$rows[]=$}return$ } $books=get_books('JackHerrington'); var_dump($books);?>现在检索列表需要一个快速、单个的查询。这意味着我将很可能必须具有几个这些类型的具有不同参数的方法,但是实在是没有选择。如果您想要具有一个扩展的PHP应用程序,那么必须有效地使用数据库,这意味着更智能的查询。本例的问题是它有点太清晰了。通常来说,这些类型的n+1或n*n问题要微妙得多。并且它们只有在数据库管理员在系统具有性能问题时在系统上运行查询剖析器时才会出现。结束语数据库是强大的工具,就跟所有强大的工具一样,如果您不知道如何正确地使用就会滥用它们。识别和解决这些问题的诀窍是更好地理解底层技术。长期以来,我老听到业务逻辑编写人员抱怨,他们不想要必须理解数据库或SQL代码。他们把数据库当成对象使用,并疑惑性能为什么如此之差。他们没有认识到,理解SQL对于将数据库从一个困难的必需品转换成强大的联盟是多么重要。如果您每天使用数据库,但是不熟悉SQL,那么请阅读TheArtofSQL,这本书写得很好,实践性也很强,可以指导您基本了解数据库。
相关文章列表:
最新图文资讯
站长之家专栏推荐
论坛推荐帖子保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
单击提交则表示您同意developerWorks
的条款和条件。 .
所有提交的信息确保安全。
developerWorks 社区:
我的概要信息
选择语言:
揭露 PHP 应用程序中出现的五个常见数据库问题 —— 包括数据库模式设计、数据库访问和使用数据库的业务逻辑代码 —— 以及它们的解决方案。
(), 高级软件工程师, Studio B
Jack D. Herrington 是一名具有 20 多年经验的高级软件工程师。他编写了 3 本书:Code Generation in Action、Podcasting Hacks 和 PHP Hacks。他还撰写过 30 多篇文章。
如果只有一种 方式使用数据库是正确的……您可以用很多的方式创建数据库设计、数据库访问和基于数据库的 PHP 业务逻辑代码,但最终一般以错误告终。本文说明了数据库设计和访问数据库的 PHP 代码中出现的五个常见问题,以及在遇到这些问题时如何修复它们。问题 1:直接使用 MySQL一个常见问题是较老的 PHP 代码直接使用 mysql_ 函数来访问数据库。清单 1 展示了如何直接访问数据库。清单 1. Access/get.php&?php
function get_user_id( $name )
$db = mysql_connect( 'localhost', 'root', 'password' );
mysql_select_db( 'users' );
$res = mysql_query( "SELECT id FROM users WHERE login='".$name."'" );
while( $row = mysql_fetch_array( $res ) ) { $id = $row[0]; }
var_dump( get_user_id( 'jack' ) );
?&注意使用了 mysql_connect 函数来访问数据库。还要注意查询,其中使用字符串连接来向查询添加 $name 参数。该技术有两个很好的替代方案:PEAR DB 模块和 PHP Data Objects (PDO) 类。两者都从特定数据库选择提供抽象。因此,您的代码无需太多调整就可以在 IBM® DB2®、MySQL、PostgreSQL 或者您想要连接到的任何其他数据库上运行。使用 PEAR DB 模块和 PDO 抽象层的另一个价值在于您可以在 SQL 语句中使用 ? 操作符。这样做可使 SQL 更加易于维护,且可使您的应用程序免受 SQL 注入攻击。使用 PEAR DB 的替代代码如下所示。清单 2. Access/get_good.php&?php
require_once("DB.php");
function get_user_id( $name )
$dsn = 'mysql://root:password@localhost/users';
$db =& DB::Connect( $dsn, array() );
if (PEAR::isError($db)) { die($db-&getMessage()); }
$res = $db-&query( 'SELECT id FROM users WHERE login=?',
array( $name ) );
while( $res-&fetchInto( $row ) ) { $id = $row[0]; }
var_dump( get_user_id( 'jack' ) );
?&注意,所有直接用到 MySQL 的地方都消除了,只有 $dsn 中的数据库连接字符串除外。此外,我们通过 ? 操作符在 SQL 中使用 $name 变量。然后,查询的数据通过 query() 方法末尾的 array 被发送进来。问题 2:不使用自动增量功能与大多数现代数据库一样,MySQL 能够在每记录的基础上创建自动增量惟一标识符。除此之外,我们仍然会看到这样的代码,即首先运行一个 SELECT 语句来找到最大的 id,然后将该 id 增 1,并找到一个新记录。清单 3 展示了一个示例坏模式。清单 3. Badid.sqlDROP TABLE IF EXISTS
CREATE TABLE users (
id MEDIUMINT,
login TEXT,
password TEXT
INSERT INTO users VALUES ( 1, 'jack', 'pass' );
INSERT INTO users VALUES ( 2, 'joan', 'pass' );
INSERT INTO users VALUES ( 1, 'jane', 'pass' );这里的 id 字段被简单地指定为整数。所以,尽管它应该是惟一的,我们还是可以添加任何值,如 CREATE 语句后面的几个 INSERT 语句中所示。清单 4 展示了将用户添加到这种类型的模式的 PHP 代码。清单 4. Add_user.php&?php
require_once("DB.php");
function add_user( $name, $pass )
$rows = array();
$dsn = 'mysql://root:password@localhost/bad_badid';
$db =& DB::Connect( $dsn, array() );
if (PEAR::isError($db)) { die($db-&getMessage()); }
$res = $db-&query( "SELECT max(id) FROM users" );
while( $res-&fetchInto( $row ) ) { $id = $row[0]; }
$sth = $db-&prepare( "INSERT INTO users VALUES(?,?,?)" );
$db-&execute( $sth, array( $id, $name, $pass ) );
$id = add_user( 'jerry', 'pass' );
var_dump( $id );
?&add_user.php 中的代码首先执行一个查询以找到 id 的最大值。然后文件以 id 值加 1 运行一个 INSERT 语句。该代码在负载很重的服务器上会在竞态条件中失败。另外,它也效率低下。那么替代方案是什么呢?使用 MySQL 中的自动增量特性来自动地为每个插入创建惟一的 ID。更新后的模式如下所示。清单 5. Goodid.phpDROP TABLE IF EXISTS
CREATE TABLE users (
id MEDIUMINT NOT NULL AUTO_INCREMENT,
login TEXT NOT NULL,
password TEXT NOT NULL,
PRIMARY KEY( id )
INSERT INTO users VALUES ( null, 'jack', 'pass' );
INSERT INTO users VALUES ( null, 'joan', 'pass' );
INSERT INTO users VALUES ( null, 'jane', 'pass' );我们添加了 NOT NULL 标志来指示字段必须不能为空。我们还添加了 AUTO_INCREMENT 标志来指示字段是自动增量的,添加 PRIMARY KEY 标志来指示那个字段是一个 id。这些更改加快了速度。清单 6 展示了更新后的 PHP 代码,即将用户插入表中。清单 6. Add_user_good.php&?php
require_once("DB.php");
function add_user( $name, $pass )
$dsn = 'mysql://root:password@localhost/good_genid';
$db =& DB::Connect( $dsn, array() );
if (PEAR::isError($db)) { die($db-&getMessage()); }
$sth = $db-&prepare( "INSERT INTO users VALUES(null,?,?)" );
$db-&execute( $sth, array( $name, $pass ) );
$res = $db-&query( "SELECT last_insert_id()" );
while( $res-&fetchInto( $row ) ) { $id = $row[0]; }
$id = add_user( 'jerry', 'pass' );
var_dump( $id );
?&现在我不是获得最大的 id 值,而是直接使用 INSERT 语句来插入数据,然后使用 SELECT 语句来检索最后插入的记录的 id。该代码比最初的版本及其相关模式要简单得多,且效率更高。问题 3:使用多个数据库偶尔,我们会看到一个应用程序中,每个表都在一个单独的数据库中。在非常大的数据库中这样做是合理的,但是对于一般的应用程序,则不需要这种级别的分割。此外,不能跨数据库执行关系查询,这会影响使用关系数据库的整体思想,更不用说跨多个数据库管理表会更困难了。那么,多个数据库应该是什么样的呢?首先,您需要一些数据。清单 7 展示了分成 4 个文件的这样的数据。清单 7. 数据库文件Files.sql:
CREATE TABLE files (
id MEDIUMINT,
user_id MEDIUMINT,
name TEXT,
Load_files.sql:
INSERT INTO files VALUES ( 1, 1, 'test1.jpg', 'files/test1.jpg' );
INSERT INTO files VALUES ( 2, 1, 'test2.jpg', 'files/test2.jpg' );
Users.sql:
DROP TABLE IF EXISTS
CREATE TABLE users (
id MEDIUMINT,
login TEXT,
password TEXT
Load_users.sql:
INSERT INTO users VALUES ( 1, 'jack', 'pass' );
INSERT INTO users VALUES ( 2, 'jon', 'pass' );在这些文件的多数据库版本中,您应该将 SQL 语句加载到一个数据库中,然后将 users SQL 语句加载到另一个数据库中。用于在数据库中查询与某个特定用户相关联的文件的 PHP 代码如下所示。清单 8. Getfiles.php&?php
require_once("DB.php");
function get_user( $name )
$dsn = 'mysql://root:password@localhost/bad_multi1';
$db =& DB::Connect( $dsn, array() );
if (PEAR::isError($db)) { die($db-&getMessage()); }
$res = $db-&query( "SELECT id FROM users WHERE login=?",
array( $name ) );
while( $res-&fetchInto( $row ) ) { $uid = $row[0]; }
function get_files( $name )
$uid = get_user( $name );
$rows = array();
$dsn = 'mysql://root:password@localhost/bad_multi2';
$db =& DB::Connect( $dsn, array() );
if (PEAR::isError($db)) { die($db-&getMessage()); }
$res = $db-&query( "SELECT * FROM files WHERE user_id=?",
array( $uid ) );
while( $res-&fetchInto( $row ) ) { $rows[] = $ }
$files = get_files( 'jack' );
var_dump( $files );
?&get_user 函数连接到包含用户表的数据库并检索给定用户的 ID。get_files 函数连接到文件表并检索与给定用户相关联的文件行。做所有这些事情的一个更好办法是将数据加载到一个数据库中,然后执行查询,比如下面的查询。清单 9. Getfiles_good.php&?php
require_once("DB.php");
function get_files( $name )
$rows = array();
$dsn = 'mysql://root:password@localhost/good_multi';
$db =& DB::Connect( $dsn, array() );
if (PEAR::isError($db)) { die($db-&getMessage()); }
$res = $db-&query(
"SELECT files.* FROM users, files WHERE
users.login=? AND users.id=files.user_id",
array( $name ) );
while( $res-&fetchInto( $row ) ) { $rows[] = $ }
$files = get_files( 'jack' );
var_dump( $files );
?&该代码不仅更短,而且也更容易理解和高效。我们不是执行两个查询,而是执行一个查询。尽管该问题听起来有些牵强,但是在实践中我们通常总结出所有的表应该在同一个数据库中,除非有非常迫不得已的理由。问题 4:不使用关系关系数据库不同于编程语言,它们不具有数组类型。相反,它们使用表之间的关系来创建对象之间的一到多结构,这与数组具有相同的效果。我在应用程序中看到的一个问题是,工程师试图将数据库当作编程语言来使用,即通过使用具有逗号分隔的标识符的文本字符串来创建数组。请看下面的模式。清单 10. Bad.sqlDROP TABLE IF EXISTS
CREATE TABLE files (
id MEDIUMINT,
name TEXT,
DROP TABLE IF EXISTS
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 ) );
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[] = $ }
$files = get_files( 'jack' );
var_dump( $files );
?&该技术很慢,难以维护,且没有很好地利用数据库。惟一的解决方案是重新架构模式,以将其转换回到传统的关系形式,如下所示。清单 12. Good.sqlDROP TABLE IF EXISTS
CREATE TABLE files (
id MEDIUMINT,
user_id MEDIUMINT,
name TEXT,
DROP TABLE IF EXISTS
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[] = $ }
$files = get_files( 'jack' );
var_dump( $files );
?&这里,我们对数据库进行一次查询,以获得所有的行。代码不复杂,并且它将数据库作为其原有的用途使用。问题 5:n+1 模式我真不知有多少次看到过这样的大型应用程序,其中的代码首先检索一些实体(比如说客户),然后来回地一个一个地检索它们,以得到每个实体的详细信息。我们将其称为 n+1 模式,因为查询要执行这么多次 —— 一次查询检索所有实体的列表,然后对于 n 个实体中的每一个执行一次查询。当 n=10 时这还不成其为问题,但是当 n=100 或 n=1000 时呢?然后肯定会出现低效率问题。清单 14 展示了这种模式的一个例子。清单 14. Schema.sqlDROP TABLE IF EXISTS
CREATE TABLE authors (
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name TEXT NOT NULL,
PRIMARY KEY ( id )
DROP TABLE IF EXISTS
CREATE TABLE books (
id MEDIUMINT NOT NULL AUTO_INCREMENT,
author_id MEDIUMINT NOT NULL,
name TEXT NOT NULL,
PRIMARY KEY ( id )
INSERT INTO authors VALUES ( null, 'Jack Herrington' );
INSERT INTO authors VALUES ( null, 'Dave Thomas' );
INSERT INTO books VALUES ( null, 1, 'Code Generation in Action' );
INSERT INTO books VALUES ( null, 1, 'Podcasting Hacks' );
INSERT INTO books VALUES ( null, 1, 'PHP Hacks' );
INSERT INTO books VALUES ( null, 2, 'Pragmatic Programmer' );
INSERT INTO books VALUES ( null, 2, 'Ruby on Rails' );
INSERT INTO books VALUES ( null, 2, 'Programming Ruby' );该模式是可靠的,其中没有任何错误。问题在于访问数据库以找到一个给定作者的所有书籍的代码中,如下所示。清单 15. Get.php&?php
require_once('DB.php');
$dsn = 'mysql://root:password@localhost/good_books';
$db =& DB::Connect( $dsn, array() );
if (PEAR::isError($db)) { die($db-&getMessage()); }
function get_author_id( $name )
$res = $db-&query( "SELECT id FROM authors WHERE name=?",
array( $name ) );
while( $res-&fetchInto( $row ) ) { $id = $row[0]; }
function get_books( $id )
$res = $db-&query( "SELECT id FROM books WHERE author_id=?",
array( $id ) );
$ids = array();
while( $res-&fetchInto( $row ) ) { $ids []= $row[0]; }
function get_book( $id )
$res = $db-&query( "SELECT * FROM books WHERE id=?", array( $id ) );
while( $res-&fetchInto( $row ) ) { return $ }
$author_id = get_author_id( 'Jack Herrington' );
$books = get_books( $author_id );
foreach( $books as $book_id ) {
$book = get_book( $book_id );
var_dump( $book );
?&如果您看看下面的代码,您可能会想,“嘿,这才是真正的清楚明了。” 首先,得到作者 id,然后得到书籍列表,然后得到有关每本书的信息。的确,它很清楚明了,但是其高效吗?回答是否定的。看看只是检索 Jack Herrington 的书籍时要执行多少次查询。一次获得 id,另一次获得书籍列表,然后每本书执行一次查询。三本书要执行五次查询!解决方案是用一个函数来执行大量的查询,如下所示。清单 16. Get_good.php&?php
require_once('DB.php');
$dsn = 'mysql://root:password@localhost/good_books';
$db =& DB::Connect( $dsn, array() );
if (PEAR::isError($db)) { die($db-&getMessage()); }
function get_books( $name )
$res = $db-&query(
"SELECT books.* FROM authors,books WHERE
books.author_id=authors.id AND authors.name=?",
array( $name ) );
$rows = array();
while( $res-&fetchInto( $row ) ) { $rows []= $ }
$books = get_books( 'Jack Herrington' );
var_dump( $books );
?&现在检索列表需要一个快速、单个的查询。这意味着我将很可能必须具有几个这些类型的具有不同参数的方法,但是实在是没有选择。如果您想要具有一个扩展的 PHP 应用程序,那么必须有效地使用数据库,这意味着更智能的查询。本例的问题是它有点太清晰了。通常来说,这些类型的 n+1 或 n*n 问题要微妙得多。并且它们只有在数据库管理员在系统具有性能问题时在系统上运行查询剖析器时才会出现。结束语数据库是强大的工具,就跟所有强大的工具一样,如果您不知道如何正确地使用就会滥用它们。识别和解决这些问题的诀窍是更好地理解底层技术。长期以来,我老听到业务逻辑编写人员抱怨,他们不想要必须理解数据库或 SQL 代码。他们把数据库当成对象使用,并疑惑性能为什么如此之差。他们没有认识到,理解 SQL 对于将数据库从一个困难的必需品转换成强大的联盟是多么重要。如果您每天使用数据库,但是不熟悉 SQL,那么请阅读 The Art of SQL,这本书写得很好,实践性也很强,可以指导您基本了解数据库。
参考资料 您可以参阅本文在 developerWorks 全球站点上的
Stephane Faroult 和 Peter Robson 编写的
对于在其应用程序中使用数据库的程序员来说是必读书籍。 是学习 PHP 的起点。 是一个很好的资源。 可以帮助您快速掌握 PHP Data Objects (PDO)。 具有优秀的文档,其中的例子展示了如何更好地使用数据库。访问 IBM developerWorks 的 ,更多地了解 PHP。
随时关注 。
检查世界各地即将到来的与 IBM 开放源码开发人员有关的会议、贸易展会、网络广播和其他 。访问 developerWorks ,获得广泛的 how-to 信息、工具和项目更新,帮助您利用开放源码技术进行开发,并将它们与 IBM 产品结合使用。
要聆听对软件开发人员有兴趣的访谈和讨论,请检查 。用
革新您的下一个开放源码开发项目,这些软件可通过下载或 DVD 获得。通过参与
加入 developerWorks 社区。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
IBM PureSystems(TM) 系列解决方案是一个专家集成系统
通过学习路线图系统掌握软件开发技能
软件下载、试用版及云计算
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=Open sourceArticleID=166479ArticleTitle=五个常见 PHP 数据库问题publish-date=

我要回帖

更多关于 怎么新建一个数据库 的文章

 

随机推荐