﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-一江春水向东流-文章分类-开源数据库学习研究</title><link>http://www.blogjava.net/huyi2006/category/30474.html</link><description>                            做一个有思想的人,期待与每一位热爱思考的人交流,您的关注是对我最大的支持。</description><language>zh-cn</language><lastBuildDate>Wed, 12 Jan 2011 07:32:46 GMT</lastBuildDate><pubDate>Wed, 12 Jan 2011 07:32:46 GMT</pubDate><ttl>60</ttl><item><title>开源NoSQL构建大型分布式架构</title><link>http://www.blogjava.net/huyi2006/articles/342813.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Wed, 12 Jan 2011 01:17:00 GMT</pubDate><guid>http://www.blogjava.net/huyi2006/articles/342813.html</guid><wfw:comment>http://www.blogjava.net/huyi2006/comments/342813.html</wfw:comment><comments>http://www.blogjava.net/huyi2006/articles/342813.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi2006/comments/commentRss/342813.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi2006/services/trackbacks/342813.html</trackback:ping><description><![CDATA[2009年开始掀起的“NoSQL革命”在Web领域造成了极大的反响，Twitter也在2010年对其Tweets数据类型引进新生的NoSQL数据库。近日，国外知名网站readwriteweb.com企业频道作者Klint Finley撰写了一篇有关“Twitter放弃MySQL转而使用NoSQL缘由”的文章。

infoQ在今年早些时候发布了一个演讲视频，在该视频中，Kevin Weil谈到了公司应如何使用NoSQL。Weil指出Twitter严重依赖于MySQL。然而，当MYSQL在许多用途上表现的并不理想的时候 Twitter使用了NoSQL解决方案。据威尔介绍，在2009年里，Twitter用户数从1月份的每天约 200万人，激增至12月份的每天近5000万人。每天登陆Twitter的用户数量增长已经超过了20倍。目前Twitter每天产生的用户数据在 12TB左右，而每年约产生4PB的数据。
　　Scribe
　　Twitter的系统日志在一段时间后停止进行压缩，所以Facebook使用Scribe来替代它。日志的收集创建在Facebook开源框架上，Twitter已经发布了一些Scribe的补丁。Twitter使用Scribe来记录Hadoop的日志。Scribe使Twitter记录日志数据变得简单。Scribe还可以比以前记录更多的数据，现在数据日志已经分成了80个不同的类别。
　　Hadoop
　　Twitter每天都需要将更多的数据可靠的写入到一个硬盘驱动器上，然后这是不现实的，所以像Twitter这样每天都产生大量数据的机构需要把数据存储在集群之中才能满足其业务需求。Twitter使用了Cloudera的Hadoop为其分配集群。Weil指出能够，MySQL不能满足 Twitter在大规模做需求分析时所要求的效率，为了满足需求，Twitter使用了Hadoop及自己拥有的开源项目，他们称之为FlockDB。 Hadoop可以运行分析并找到在FlockBD中相似的社交图数据集合。
　　Pig
　　
　　这种Pig脚本可以帮您找到其网站年龄在18至25岁访问者中访问量排名前五位的网页
　　Weil说Hadoop是通过Java语言实现的，但是Java是复杂的，这使得它很难快速的重复执行。相反，Twitter使用Pig脚本的语言，这个高级语言运行在Hadoop之上。
　　Yahoo创造了Pig脚本语言并使其快速发展，Weil表示，Pig非常易学并且容易理解。他说，你将受益于Pig的方便，并且它缩短了执行时间，但这是值得的。
　　HBase
　　HBase是建立在Hadoop的之上的，并且具有低延时和数据可变性的设计。 Twitter的使用它来增强人们的搜索。
　　FlockDB
　　FlockDB是一个实时的、分布式的数据库。如上所述，它的建立和开源由来自Twitter。该公司使用它的社交图分析。它仍然在MySQL的下面，但是它的速度非常快。
　　Weil用一个在FlockDB的应用程序举例，显示哪些用户显示@表示回复。举个例子。如果Ashton Kutcher发送tweet到@foursquare。它不应该显示在Kutcher的6156915粉丝之中，他应该仅在关注Kutcher的用户和 Foursquare中显示。
　　Cassandra

　　Twitter至今仍然在尝试并使用Casandra，这个开源的数据库由Facebook创建。Weil说，Twitter当前的原子计算实验使用的就是Cassandra。但对Twitter而言，Cassandra也非万能，首先在于Cassandra代码或许还存在不少问题，Twitter如果投入大量的精力来改进Cassandra和比较优化MySQL 的投入来看有点得不偿失。在QCon Beijing上@nk也提到Cassandra在Twitter的内部测试中曾经暴露出不少严重的问题。
　　Twitter拿所有的这些数据都用来做什么?
　　Twitter的使用它收集的所有数据有各种用途。有些只是简单的计数问题，如计算出有多少请求它的服务，每天有多少搜索服务，每天来处理这些交易的平均时间，等等。
　　其他用途更为复杂。例如，不同类型用户的运行比较。Twitter的分析数据，以确定是否移动用户，用户谁使用了第三方客户短或“超级用户”与普通用户使用Twitter的不同。
　　韦伊最后指出，Twitter的其他问题包括：确定转推的话题中哪些类型是人们最感兴趣，最成功的网络需要什么样的社会效果图结构，以及如何区分不同类型的人或机器人。<img src ="http://www.blogjava.net/huyi2006/aggbug/342813.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi2006/" target="_blank">allic</a> 2011-01-12 09:17 <a href="http://www.blogjava.net/huyi2006/articles/342813.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MySQL修改root密码的各种方法整理</title><link>http://www.blogjava.net/huyi2006/articles/247943.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Tue, 23 Dec 2008 09:12:00 GMT</pubDate><guid>http://www.blogjava.net/huyi2006/articles/247943.html</guid><wfw:comment>http://www.blogjava.net/huyi2006/comments/247943.html</wfw:comment><comments>http://www.blogjava.net/huyi2006/articles/247943.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi2006/comments/commentRss/247943.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi2006/services/trackbacks/247943.html</trackback:ping><description><![CDATA[
		<p>整理了以下四种在MySQL中修改root密码的方法,可能对大家有所帮助!</p>
		<p>方法1： 用SET PASSWORD命令</p>
		<p>　　mysql -u root</p>
		<p>　　mysql&gt; SET PASSWORD FOR <a href="mailto:'root'@'localhost'">'root'@'localhost'</a> = PASSWORD('newpass');</p>
		<p>方法2：用mysqladmin</p>
		<p> </p>
		<p>　　mysqladmin -u root password "newpass"</p>
		<p>　　如果root已经设置过密码，采用如下方法</p>
		<p>　　mysqladmin -u root password oldpass "newpass"</p>
		<p>方法3： 用UPDATE直接编辑user表</p>
		<p>　　mysql -u root</p>
		<p>　　mysql&gt; use mysql;</p>
		<p>　　mysql&gt; UPDATE user SET Password = PASSWORD('newpass') WHERE user = 'root';</p>
		<p>　　mysql&gt; FLUSH PRIVILEGES;</p>
		<p>在丢失root密码的时候，可以这样</p>
		<p>　　mysqld_safe --skip-grant-tables&amp;</p>
		<p>　　mysql -u root mysql</p>
		<p>　　mysql&gt; UPDATE user SET password=PASSWORD("new password") WHERE user='root';</p>
		<p>　　mysql&gt; FLUSH PRIVILEGES;</p>
		<p> </p>
<img src ="http://www.blogjava.net/huyi2006/aggbug/247943.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi2006/" target="_blank">allic</a> 2008-12-23 17:12 <a href="http://www.blogjava.net/huyi2006/articles/247943.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux下两个不同版本Mysql的安装实战（Mysql5和mysql4）</title><link>http://www.blogjava.net/huyi2006/articles/247941.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Tue, 23 Dec 2008 09:05:00 GMT</pubDate><guid>http://www.blogjava.net/huyi2006/articles/247941.html</guid><wfw:comment>http://www.blogjava.net/huyi2006/comments/247941.html</wfw:comment><comments>http://www.blogjava.net/huyi2006/articles/247941.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi2006/comments/commentRss/247941.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi2006/services/trackbacks/247941.html</trackback:ping><description><![CDATA[问题的产生：在已有的Red Hat Enterprise Linux AS 3.0系统上已经运行了一套web程序，使用Mysql4, tomcat41, 现在又要求安装一套新程序，依旧使用该tomcat41, 但数据库变为<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>。 <br /><br />注意事项： <br />新的程序需要注意字符集的问题， <br />1)具体数据库的权限和分组问题， <br />2)<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>下的具体数据库从windows直接拷贝到Linux下不好使的问题， <br />3)以及<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>需要设置密码的问题， <br />4)<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>在linux下对数据库区分大小写的问题。 <br />5) mysql在终端进入 <br />   mysql&gt; <br />   时的用户名和密码问题 <br /><br />此外，在具体安装<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>的过程中，要注意将<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>的安装位置（baseDir），数据库的具体存放位置（dataDir），端口号（改为3307）,进行修改，这样才能保证两个不同版本的数据库的同时运行。 <br /><br />版本号： <br />MySQL v4.0.24 <br />(1)MySQL-server-4.0.24-0.i386.rpm <br />(2)MySQL-client-4.0.24-0.i386.rpm <br />(3)MySQL-devel-4.0.24-0.i386.rpm <br />MySQL 5.0.51a <br />mysql-5.0.51a.tar.gz <br />下载地址：http://ftp.ntu.edu.tw/pub/MySQL/Downloads/MySQL-5.0/mysql-5.0.51a.tar.gz <br /><br />安装MySQL v4.0.24 <br />#rpm -qa | grep sql <br />查询系统是否默认安装了mysql服务器 <br />然后卸载系统默认安装的mysql <br />卸载mysql命令如下： <br />#rpm -e --nodeps mysql-3.23.58-1 <br /><br />安装MySQL服务端： <br />#rpm -ivh MySQL-server-4.0.24-0.i386.rpm <br />测试服务端是否安装成功： <br />#netstat -nat <br />查看端口3306是否打开 <br />然后安装MySQL客户端 <br />#rpm -ivh MySQL-client-4.0.24-0.i386.rpm <br />安装MySQL连接包： <br />#rpm -ivh MySQL-devel-4.0.24-0.i386.rpm <br />此时Mysql4的各个安装路径如下： <br />以我们在Redhat下安装的MySQl4.0.26数据库为例： <br />(注意事项：rpm包使用的都是默认的设置，不能更改，以下均为默认设置) <br />1.配置文件：/etc/my.cnf <br />2.数据库目录：/var/lib/mysql <br />3.启动脚本：/etc/rc.d/init.d/mysql <br />4.端口3306 <br />5..socket文件/tmp/mysql.socket <br />—————————————————————————————————————— <br /><br />下面安装MySQL 5.0.51a <br /><br />由于我们安装的MySQL4.0.26的安装包类型是rpm包，所以，需要大家注意的是， <br />它使用的都是默认的设置，安装后生成的配置文件和数据库目录等等一系列的配置都是我们不能改变的。 <br />因此，如果要在同一开发环境下安装两个数据库的话，我们就必须处理以下这些问题： <br />1.配置文件安装路径不能相同 <br />2.数据库目录不能相同 <br />3.启动脚本不能同名 <br />4.端口不能相同 <br />5..socket文件的生成路径不能相同 <br />依据上面的各种要求：<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>.0.51a.tar.gz的源码包安装做出以下调整： <br />--prefix=/usr/local/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>  ### 数据库安装目录 <br />--localstatedir=/var/lib/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>  ### 数据库存放目录 <br />--with-charset=gbk --with-collation=gbk_chinese_ci --with-extra-charsets=all ### 字符集gbk加载和gbk_chinese_ci加载，可处理中文乱码问题 <br />其他的设置是对数据库的一下优化，在此就不再赘述。 <br /><br />参考了一些msyql5的安装文档，在这里感谢各位前辈 <br />mysql-5.0.51a.tar.gz解压后的安装详解： <br /><br />1# cd mysql-5.0.51a <br />2# mkdir /usr/local/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span><br /><br />(这步骤中的诸多参数中，关键的参数已经在前面介绍了，如有不懂，请参看前面的介绍。) <br />3# ./configure <br />--prefix=/usr/local/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span><br />--localstatedir=/var/lib/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span> --with-comment=Source   <br />--with-server-suffix=-Community <br />--with-mysqld-user=mysql <br />--without-debug <br />--with-big-tables <br />--with-charset=gbk --with-collation=gbk_chinese_ci --with-extra-charsets=all <br />--with-pthread <br />--enable-static <br />--enable-thread-safe-client <br />--with-client-ldflags=-all-static <br />--with-mysqld-ldflags=-all-static <br />--enable-assembler <br />--without-innodb <br />--without-ndb-debug <br />4# make <br />5# make install <br /><br />6.# useradd mysql //添加 mysql 用户 <br />7# cd /usr/local/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span><br />(注意：！！！在安装第二个数据库时候，虽然在./configure后加上了--localstatedir=/var/lib/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>但是并未在/var/lib下产生<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>目录，所以我们要在源码包编译安装完成之后先检查一下是否有这个目录，如果没有的话一定要手动创建一个 命令：＃ mkdir /var/lib/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>再执行第八步骤。) <br />8# bin/mysql_install_db --user=mysql <br />(在确保第七步骤正确完成之后，在执行本步骤时，如果正确的话，在/var/lib/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>下将会产生相应的数据库文件。) <br />9# chown -R root:mysql . 　　　　　　//设置权限，注意后面有一个 "." <br />10# chown -R mysql /var/lib/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span> 　　//设置 mysql 目录权限 <br />11# chgrp -R mysql . 　　　　　　　　 //注意后面有一个 "." <br />12# cp share/mysql/my-huge.cnf /etc/my5.cnf <br />13# cp share/mysql/mysql.server /etc/rc.d/init.d/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span> //开机自动启动 mysql。 <br />14# chmod 755 /etc/rc.d/init.d/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span><br />15# chkconfig --add <span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span><br /><br />16以下是安装第二个数据库时，对启动文件<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>和配置文件my5.cnf做出的必要修改。 <br />=================================================================================== <br />/etc/rc.d/init.d/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span><br /><br />修改下面的内容： <br /><br />1.datadir=/var/lib/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span><br />2.conf=/etc/my5.cnf <br />3.把"$bindir/mysqld_safe --datadir=$datadir --pid-file=$server_pid_file $other_args &gt;/dev/null 2&gt;&amp;1 &amp;"替换为（双引号中的） <br />"$bindir/mysqld_safe --defaults-file=/etc/my5.cnf --datadir=$datadir --pid-file=$server_pid_file $other_args &gt;/dev/null 2&gt;&amp;1 &amp;"（双引号中的） <br />=================================================================================== <br />/etc/my5.cnf <br /><br />修改下面的内容： <br /><br />port = 3307 ###修改相关的端口 <br />socket文件生成路径 <br /><br />把[client]和[mysqld]中的port号都改成3307, <br />socket = /tmp/mysql.sock改成socket = /tmp/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>.sock <br />[client] <br />#password = your_password <br />port  = 3307 <br />socket  = /tmp/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>.sock <br /><br /># Here follows entries for some specific programs <br /><br /># The MySQL server <br />[mysqld] <br />port  = 3307 <br />socket  = /tmp/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>.sock <br />================================================================================== <br />17# /etc/rc.d/init.d/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span> start 　　　　　　　　　　//启动 MySQL <br />18# bin/mysqladmin -u root password "password_for_root" ### 设置数据库JDBC连接的密码 <br />    注意事项：此密码与从终端客户端登陆数据库的密码是否为同一密码，还存在疑问。 <br />              设置终端客户端登陆数据库的密码：(默认设置：用户名：root 密码：（空）) <br />19# cd /usr/local/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>/bin(进入数据库安装目录下执行以下命令) <br />20# ./mysql -u root -p (登陆数据库，以mysql&gt;开头均属数据库内的操作,注意不要丢掉分号 <br />mysql&gt; use mysql; <br /><br />mysql&gt; UPDATE user SET Password=PASSWORD('newpassword') where USER='root'; <br />mysql&gt; FLUSH PRIVILEGES; <br />mysql&gt; exit; <br />21# service <span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span> stop 　　　　　　　　　　　　　　//关闭 MySQL <br /><br />22tomcat部署文件下的修改： <br />修改/usr/tomcat/jetmambo/WEB-INF/classes/jdbc.properties <br />1.3306改成3307 <br />2.jdbc.password=system(注意事项：这个密码就是数据库JDBC连接的密码) <br /><br />修改后如下： <br />jdbc.driverClassName=com.mysql.jdbc.Driver <br />jdbc.url=jdbc:mysql://localhost:3307/timef3_cmd?&amp;useUnicode=true&amp;characterEncoding=gbk <br />jdbc.username=root <br />jdbc.password=system <br /><br />23启动数据库和WEB服务器，验证数据库安装是否成功 <br />/etc/init.d/mysql restart <br />/etc/init.d/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span> restart <br />注意事项：必须保持两个数据库都开启服务,否则tomcat报SQLException <br />/usr/tomcat/bin/catalina.sh run <br /><br />补充说明： <br /><br />24linux下默认数据库中表名不忽略大小写，做如下设置： <br />/etc/my5.cnf <br /><br /># The MySQL server <br />[mysqld] <br />lower_case_table_names = 1 ### 1为忽略大小写 0为不忽略大小写 <br />port  = 3307 <br />socket  = /tmp/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>.sock <br /><br />———————————————————————————————————— <br />遗留问题，不知那位大侠可以解答一下： <br />在终端进入 <br />&gt;mysql时 <br />报： <br />ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2) <br />错误。 <br />---------------------------------------------------------------- <br />问题解决了 <br />http://www.javaeye.com/topic/203986 <br />非常感谢这篇文章 <br /><br />./mysql -uroot -p -S /tmp/<span class="hilite1"><font style="BACKGROUND-COLOR: #ffff00">mysql5</font></span>.sock <br /><br />如果不加参数-S，则在默认目录去找mysql.sock <br /><br /><img src ="http://www.blogjava.net/huyi2006/aggbug/247941.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi2006/" target="_blank">allic</a> 2008-12-23 17:05 <a href="http://www.blogjava.net/huyi2006/articles/247941.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>简洁、明晰！数据库设计三大范式应用实例剖析</title><link>http://www.blogjava.net/huyi2006/articles/228904.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Sun, 14 Sep 2008 09:12:00 GMT</pubDate><guid>http://www.blogjava.net/huyi2006/articles/228904.html</guid><wfw:comment>http://www.blogjava.net/huyi2006/comments/228904.html</wfw:comment><comments>http://www.blogjava.net/huyi2006/articles/228904.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi2006/comments/commentRss/228904.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi2006/services/trackbacks/228904.html</trackback:ping><description><![CDATA[
		<div id="vogate_ad_area">
				<p>引言<br /><br />　　数据库的<a class="vLink1" id="vad_1" onmouseover="this.style.borderBottom='2px #FF3366 solid';var fxEvent=arguments[0];kwmouseover(this,1,fxEvent);" title="站长中国-中国站长门户 @Vogate.com" style="FONT-SIZE: 1em; CURSOR: hand; COLOR: #ff3366; BORDER-BOTTOM: #ff3366 1px dotted; TEXT-DECORATION: underline" onmouseout="this.style.borderBottom='1px #FF3366 dotted';kwmouseout(this,1)" href="http://action.vogate.com/c/c.php?r=http%3A//www.baidu.com/s%3Fwd%3D%25CA%25FD%25BE%25DD%25BF%25E2+%25B9%25D8%25BC%25FC%25D7%25D6&amp;aid=4862&amp;sid=6235007045049473&amp;click=1&amp;url=http%3A//WWW.ZZCHN.COM&amp;v=0&amp;k=%u8BBE%u8BA1&amp;s=http%3A//news.csdn.net/n/20061230/100207.html&amp;rn=832291" target="_blank" name="1">设计</a>范式是数据库设计所需要满足的规范，满足这些规范的数据库是简洁的、结构明晰的，同时，不会发生插入（insert）、删除（delete）和更新（update）操作异常。反之则是乱七八糟，不仅给数据库的编程人员制造麻烦，而且面目可憎，可能存储了大量不需要的冗余<a class="vLink1" id="vad_2" onmouseover="this.style.borderBottom='2px #FF3366 solid';var fxEvent=arguments[0];kwmouseover(this,2,fxEvent);" title="商丘网-商丘热线 @Vogate.com" style="FONT-SIZE: 1em; CURSOR: hand; COLOR: #ff3366; BORDER-BOTTOM: #ff3366 1px dotted; TEXT-DECORATION: underline" onmouseout="this.style.borderBottom='1px #FF3366 dotted';kwmouseout(this,2)" href="http://action.vogate.com/c/c.php?r=http%3A//www.baidu.com/s%3Fwd%3D%25CA%25FD%25BE%25DD%25BF%25E2+%25B9%25D8%25BC%25FC%25D7%25D6&amp;aid=5404&amp;sid=6235007045049473&amp;click=1&amp;url=http%3A//www.shangqiu.cc&amp;v=0&amp;k=%u4FE1%u606F&amp;s=http%3A//news.csdn.net/n/20061230/100207.html&amp;rn=356113" target="_blank" name="2">信息</a>。<br /><br />　　设计范式是不是很难懂呢？非也，大学教材上给我们一堆数学公式我们当然看不懂，也记不住。所以我们很多人就根本不按照范式来设计数据库。<br /><br />　　实质上，设计范式用很<a class="vLink1" id="vad_0" onmouseover="this.style.borderBottom='2px #FF3366 solid';var fxEvent=arguments[0];kwmouseover(this,0,fxEvent);" title="形象顾问培训 @Vogate.com" style="FONT-SIZE: 1em; CURSOR: hand; COLOR: #ff3366; BORDER-BOTTOM: #ff3366 1px dotted; TEXT-DECORATION: underline" onmouseout="this.style.borderBottom='1px #FF3366 dotted';kwmouseout(this,0)" href="http://action.vogate.com/c/c.php?r=http%3A//www.baidu.com/s%3Fwd%3D%25CA%25FD%25BE%25DD%25BF%25E2+%25B9%25D8%25BC%25FC%25D7%25D6&amp;aid=5228&amp;sid=6235007045049473&amp;click=1&amp;url=http%3A//www.funtry.com&amp;v=0&amp;k=%u5F62%u8C61&amp;s=http%3A//news.csdn.net/n/20061230/100207.html&amp;rn=866855" target="_blank" name="0">形象</a>、很简洁的话语就能说清楚，道明白。本文将对范式进行通俗地说明，并以笔者曾经设计的一个简单论坛的数据库为例来讲解怎样将这些范式应用于实际工程。<br /><br />　　范式说明<br /><br />　　第一范式（1NF）：数据库表中的字段都是单一属性的，不可再分。这个单一属性由基本类型构成，包括整型、实数、字符型、逻辑型、日期型等。<br /><br />　　例如，如下的数据库表是符合第一范式的：<br /><br /></p>
				<table cellspacing="0" cellpadding="2" width="90%" align="center" border="1">
						<tbody>
								<tr>
										<td>字段1 </td>
										<td>字段2 </td>
										<td>字段3 </td>
										<td>字段4</td>
								</tr>
								<tr>
										<td> </td>
										<td> </td>
										<td> </td>
										<td> </td>
								</tr>
						</tbody>
				</table>
				<br />　　而这样的数据库表是不符合第一范式的：<br /><br /><table cellspacing="0" cellpadding="2" width="90%" align="center" border="1"><tbody><tr><td>字段1 </td><td>字段2 </td><td colspan="2">字段3 </td><td>字段4</td></tr><tr><td> </td><td> </td><td>字段3.1</td><td>字段3.2 </td><td> </td></tr></tbody></table><p><br />　　很显然，在当前的任何关系数据库管理系统（DBMS）中，傻瓜也不可能做出不符合第一范式的数据库，因为这些DBMS不允许你把数据库表的一列再分成二列或多列。因此，你想在现有的DBMS中设计出不符合第一范式的数据库都是不可能的。<br /><br />　　第二范式（2NF）：数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖（部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况），也即所有非关键字段都完全依赖于任意一组候选关键字。 
</p><table cellspacing="0" cellpadding="0" align="left" border="0"><tbody><tr><td valign="top"> </td></tr><tr><td> </td></tr></tbody></table><br /><br />　　假定选课关系表为SelectCourse(学号, 姓名, 年龄, 课程名称, 成绩, 学分)，关键字为组合关键字(学号, 课程名称)，因为存在如下决定关系：<br /><br />　　(学号, 课程名称) → (姓名, 年龄, 成绩, 学分)<br /><br />　　这个数据库表不满足第二范式，因为存在如下决定关系：<br /><br />　　(课程名称) → (学分)<br /><br />　　(学号) → (姓名, 年龄)<br /><br />　　即存在组合关键字中的字段决定非关键字的情况。<br /><br />　　由于不符合2NF，这个选课关系表会存在如下问题：<br /><br />　　(1) 数据冗余：<br /><br />　　同一门课程由n个学生选修，"学分"就重复n-1次；同一个学生选修了m门课程，姓名和年龄就重复了m-1次。<br /><br />　　(2) 更新异常：<br /><br />　　若调整了某门课程的学分，数据表中所有行的"学分"值都要更新，否则会出现同一门课程学分不同的情况。<br /><br />　　(3) 插入异常：<br /><br />　　假设要开设一门新的课程，暂时还没有人选修。这样，由于还没有"学号"关键字，课程名称和学分也无法记录入数据库。<br /><br />　　(4) 删除异常：<br /><br />　　假设一批学生已经完成课程的选修，这些选修记录就应该从数据库表中删除。但是，与此同时，课程名称和学分信息也被删除了。很显然，这也会导致插入异常。 <br /><br />　　把选课关系表SelectCourse改为如下三个表：<br /><br />　　学生：Student(学号, 姓名, 年龄)；<br /><br />　　课程：Course(课程名称, 学分)；<br /><br />　　选课关系：SelectCourse(学号, 课程名称, 成绩)。<br /><br />　　这样的数据库表是符合第二范式的，消除了数据冗余、更新异常、插入异常和删除异常。<br /><br />　　另外，所有单关键字的数据库表都符合第二范式，因为不可能存在组合关键字。<br /><br />　　第三范式（3NF）：在第二范式的基础上，数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。所谓传递函数依赖，指的是如果存在"A → B → C"的决定关系，则C传递函数依赖于A。因此，满足第三范式的数据库表应该不存在如下依赖关系：<br /><br />　　关键字段 → 非关键字段x → 非关键字段y<br /><br />　　假定学生关系表为Student(学号, 姓名, 年龄, 所在<a href="http://edu.itbulo.com/"><font color="#000000">学院</font></a>, <a href="http://edu.itbulo.com/"><u><font color="#004a9c">学院</font></u></a>地点, <a href="http://edu.itbulo.com/"><u><font color="#004a9c">学院</font></u></a>电话)，关键字为单一关键字"学号"，因为存在如下决定关系：<br /><br />　　(学号) → (姓名, 年龄, 所在<a href="http://edu.itbulo.com/"><u><font color="#004a9c">学院</font></u></a>, <a href="http://edu.itbulo.com/"><u><font color="#004a9c">学院</font></u></a>地点, <a href="http://edu.itbulo.com/"><u><font color="#004a9c">学院</font></u></a>电话)<br /><br />　　这个数据库是符合2NF的，但是不符合3NF，因为存在如下决定关系：<br /><br />　　(学号) → (所在<a href="http://edu.itbulo.com/"><u><font color="#004a9c">学院</font></u></a>) → (<a href="http://edu.itbulo.com/"><u><font color="#004a9c">学院</font></u></a>地点, <a href="http://edu.itbulo.com/"><u><font color="#004a9c">学院</font></u></a>电话)<br /><br />　　即存在非关键字段"<a href="http://edu.itbulo.com/"><u><font color="#004a9c">学院</font></u></a>地点"、"<a href="http://edu.itbulo.com/"><u><font color="#004a9c">学院</font></u></a>电话"对关键字段"学号"的传递函数依赖。<br /><br />　　它也会存在数据冗余、更新异常、插入异常和删除异常的情况，读者可自行分析得知。<br /><br />　　把学生关系表分为如下两个表：<br /><br />　　学生：(学号, 姓名, 年龄, 所在<a href="http://edu.itbulo.com/"><u><font color="#004a9c">学院</font></u></a>)；<br /><br />　　<a href="http://edu.itbulo.com/"><u><font color="#004a9c">学院</font></u></a>：(<a href="http://edu.itbulo.com/"><u><font color="#004a9c">学院</font></u></a>, 地点, 电话)。<br /><br />　　这样的数据库表是符合第三范式的，消除了数据冗余、更新异常、插入异常和删除异常。<br /><br />　　鲍依斯-科得范式（BCNF）：在第三范式的基础上，数据库表中如果不存在任何字段对任一候选关键字段的传递函数依赖则符合第三范式。<p>　假设仓库管理关系表为StorehouseManage(仓库ID, 存储物品ID, 管理员ID, 数量)，且有一个管理员只在一个仓库<a class="vLink1" id="vad_3" onmouseover="this.style.borderBottom='2px #FF3366 solid';var fxEvent=arguments[0];kwmouseover(this,3,fxEvent);" title="找酒店工作，上最佳东方！ @Vogate.com" style="FONT-SIZE: 1em; CURSOR: hand; COLOR: #ff3366; BORDER-BOTTOM: #ff3366 1px dotted; TEXT-DECORATION: underline" onmouseout="this.style.borderBottom='1px #FF3366 dotted';kwmouseout(this,3)" href="http://action.vogate.com/c/c.php?r=http%3A//www.baidu.com/s%3Fwd%3D%25CA%25FD%25BE%25DD%25BF%25E2+%25B9%25D8%25BC%25FC%25D7%25D6&amp;aid=10358&amp;sid=6235007045049473&amp;click=1&amp;url=http%3A//www.veryeast.cn&amp;v=0&amp;k=%u5DE5%u4F5C&amp;s=http%3A//news.csdn.net/n/20061230/100207.html&amp;rn=416714" target="_blank" name="3">工作</a>；一个仓库可以存储多种物品。这个数据库表中存在如下决定关系：<br /><br />　　(仓库ID, 存储物品ID) →(管理员ID, 数量)<br /><br />　　(管理员ID, 存储物品ID) → (仓库ID, 数量)<br /><br />　　所以，(仓库ID, 存储物品ID)和(管理员ID, 存储物品ID)都是StorehouseManage的候选关键字，表中的唯一非关键字段为数量，它是符合第三范式的。但是，由于存在如下决定关系：<br /><br />　　(仓库ID) → (管理员ID)<br /><br />　　(管理员ID) → (仓库ID)<br /><br />　　即存在关键字段决定关键字段的情况，所以其不符合BCNF范式。它会出现如下异常情况：<br /><br />　　(1) 删除异常：<br /><br />　　当仓库被清空后，所有"存储物品ID"和"数量"信息被删除的同时，"仓库ID"和"管理员ID"信息也被删除了。<br /><br />　　(2) 插入异常：<br /><br />　　当仓库没有存储任何物品时，无法给仓库分配管理员。<br /><br />　　(3) 更新异常：<br /><br />　　如果仓库换了管理员，则表中所有行的管理员ID都要修改。<br /><br />　　把仓库管理关系表分解为二个关系表：<br /><br />　　仓库管理：StorehouseManage(仓库ID, 管理员ID)；<br /><br />　　仓库：Storehouse(仓库ID, 存储物品ID, 数量)。<br /><br />　　这样的数据库表是符合BCNF范式的，消除了删除异常、插入异常和更新异常。 </p><p> </p><p>范式应用<br /><br />　　我们来逐步搞定一个论坛的数据库，有如下信息：<br /><br />　　（1） 用户：用户名，email，主页，电话，联系地址<br /><br />　　（2） 帖子：发帖标题，发帖内容，回复标题，回复内容 <br /><br />　　第一次我们将数据库设计为仅仅存在表：<br />　　 
</p><table cellspacing="0" cellpadding="2" width="90%" align="center" border="1"><tbody><tr><td>用户名 </td><td>email </td><td>主页</td><td>电话</td><td>联系地址</td><td>发帖标题</td><td>发帖内容</td><td>回复标题</td><td>回复内容</td></tr></tbody></table><br />　　这个数据库表符合第一范式，但是没有任何一组候选关键字能决定数据库表的整行，唯一的关键字段用户名也不能完全决定整个元组。我们需要增加"发帖ID"、"回复ID"字段，即将表修改为：<br /><br /><table cellspacing="0" cellpadding="2" width="90%" align="center" border="1"><tbody><tr><td>用户名</td><td>email</td><td>主页</td><td>电话</td><td>联系地址</td><td>发帖ID</td><td>发帖标题</td><td>发帖内容</td><td>回复ID</td><td>回复标题</td><td>回复内容</td></tr></tbody></table><br />　　这样数据表中的关键字(用户名，发帖ID，回复ID)能决定整行：<br /><br />　　(用户名,发帖ID,回复ID) → (email,主页,电话,联系地址,发帖标题,发帖内容,回复标题,回复内容)<br /><br />　　但是，这样的设计不符合第二范式，因为存在如下决定关系：<br /><br />　　(用户名) → (email,主页,电话,联系地址)<br /><br />　　(发帖ID) → (发帖标题,发帖内容)<br /><br />　　(回复ID) → (回复标题,回复内容)<br /><br />　　即非关键字段部分函数依赖于候选关键字段，很明显，这个设计会导致大量的数据冗余和操作异常。 
<table cellspacing="0" cellpadding="0" align="left" border="0"><tbody><tr><td valign="top"> </td></tr><tr><td> </td></tr></tbody></table><br /><br />　　我们将数据库表分解为（带下划线的为关键字）：<br /><br />　　（1） 用户信息：用户名，email，主页，电话，联系地址<br /><br />　　（2） 帖子信息：发帖ID，标题，内容<br /><br />　　（3） 回复信息：回复ID，标题，内容<br /><br />　　（4） 发贴：用户名，发帖ID<br /><br />　　（5） 回复：发帖ID，回复ID<br /><br />　　这样的设计是满足第1、2、3范式和BCNF范式要求的，但是这样的设计是不是最好的呢？<br /><br />　　不一定。<br /><br />　　观察可知，第4项"发帖"中的"用户名"和"发帖ID"之间是1：N的关系，因此我们可以把"发帖"合并到第2项的"帖子信息"中；第5项"回复"中的"发帖ID"和"回复ID"之间也是1：N的关系，因此我们可以把"回复"合并到第3项的"回复信息"中。这样可以一定量地减少数据冗余，新的设计为：<br /><br />　　（1） 用户信息：用户名，email，主页，电话，联系地址<br /><br />　　（2） 帖子信息：用户名，发帖ID，标题，内容<br /><br />　　（3） 回复信息：发帖ID，回复ID，标题，内容<br /><br />　　数据库表1显然满足所有范式的要求；<br /><br />　　数据库表2中存在非关键字段"标题"、"内容"对关键字段"发帖ID"的部分函数依赖，即不满足第二范式的要求，但是这一设计并不会导致数据冗余和操作异常；<br /><br />　　数据库表3中也存在非关键字段"标题"、"内容"对关键字段"回复ID"的部分函数依赖，也不满足第二范式的要求，但是与数据库表2相似，这一设计也不会导致数据冗余和操作异常。<br /><br />　　由此可以看出，并不一定要强行满足范式的要求，对于1：N关系，当1的一边合并到N的那边后，N的那边就不再满足第二范式了，但是这种设计反而比较好！<br /><br />　　对于M：N的关系，不能将M一边或N一边合并到另一边去，这样会导致不符合范式要求，同时导致操作异常和数据冗余。 <br />对于1：1的关系，我们可以将左边的1或者右边的1合并到另一边去，设计导致不符合范式要求，但是并不会导致操作异常和数据冗余。<br /><br />　　结论<br /><br />　　满足范式要求的数据库设计是结构清晰的，同时可避免数据冗余和操作异常。这并意味着不符合范式要求的设计一定是错误的，在数据库表中存在1：1或1：N关系这种较特殊的情况下，合并导致的不符合范式要求反而是合理的。<br /><br />　　在我们设计数据库的时候，一定要时刻考虑范式的要求。<p></p></div>
<img src ="http://www.blogjava.net/huyi2006/aggbug/228904.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi2006/" target="_blank">allic</a> 2008-09-14 17:12 <a href="http://www.blogjava.net/huyi2006/articles/228904.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何在mysql中创建内存表</title><link>http://www.blogjava.net/huyi2006/articles/208867.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Wed, 18 Jun 2008 06:41:00 GMT</pubDate><guid>http://www.blogjava.net/huyi2006/articles/208867.html</guid><wfw:comment>http://www.blogjava.net/huyi2006/comments/208867.html</wfw:comment><comments>http://www.blogjava.net/huyi2006/articles/208867.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi2006/comments/commentRss/208867.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi2006/services/trackbacks/208867.html</trackback:ping><description><![CDATA[
		<strong>如何创建内存表</strong>？<br />    创建内存表非常的简单，只需注明 ENGINE= MEMORY 即可:<br />    CREATE TABLE  `tablename` ( `columnName` varchar(256) NOT NUL) ENGINE=MEMORY DEFAULT CHARSET=latin1 MAX_ROWS=100000000; 
<p> </p><p><strong>注意</strong>：<br />    当内存表中的数据大于max_heap_table_size设定的容量大小时，mysql会转换超出的数据存储到磁盘上，因此这是性能就大打折扣了，所以我们还需要根据我们的实际情况调整max_heap_table_size，例如在.cnf文件中[mysqld]的下面加入：<br />        max_heap_table_size = 2048M<br />    另外在建表语句中还可以通过MAX_ROWS来控制表的记录数。<br /><br />内存表使用哈希散列索引把数据保存在内存中，因此具有极快的速度，适合缓存中小型数据库，但是使用上受到一些限制，以下是蓝草使用的一些感受。<br /><br />1、heap对所有用户的连接是可见的，这使得它非常适合做缓存。<br /><br />2、仅适合使用的场合。heap不允许使用xxxTEXT和xxxBLOB数据类型；只允许使用=和&lt;=&gt;操作符来搜索记录（不允许&lt;、&gt;、&lt;=或&gt;=）；不支持auto_increment；只允许对非空数据列进行索引（not null）。<br />注：操作符 “&lt;=&gt;” 说明：NULL-safe equal.这个操作符和“=”操作符执行相同的比较操作，不过在两个操作码均为NULL时，其所得值为1而不为NULL，而当一个操作码为NULL时，其所得值为0而不为NULL。<br /><br />3、一旦服务器重启，所有heap表数据丢失，但是heap表结构仍然存在，因为heap表结构是存放在实际数据库路径下的，不会自动删除。重启之后，heap将被清空，这时候对heap的查询结果都是空的。<br /><br />4、如果heap是复制的某数据表，则复制之后所有主键、索引、自增等格式将不复存在，需要重新添加主键和索引，如果需要的话。<br /><br />5、对于重启造成的数据丢失，有以下的解决办法：<br />　a、在任何查询之前，执行一次简单的查询，判断heap表是否存在数据，如果不存在，则把数据重新写入，或者DROP表重新复制某张表。这需要多做一次查询。不过可以写成include文件，在需要用该heap表的页面随时调用，比较方便。<br />　b、对于需要该heap表的页面，在该页面第一次且仅在第一次查询该表时，对数据集结果进行判断，如果结果为空，则需要重新写入数据。这样可以节省一次查询。<br />　c、更好的办法是在mysql每次重新启动时自动写入数据到heap，但是需要配置服务器，过程比较复杂，通用性受到限制。<br /><br />6、一些预期可能用到的sql语句<br /><br />//如果表存在，则删除<br />DROP TABLE IF EXISTS `abc`;<br />//复制整张表xyz为heap表abc（包含所有数据）<br />CREATE TABLE `abc` type=heap select * from `xyz`;<br />//添加主键id<br />ALTER TABLE `abc` ADD PRIMARY KEY (`id`);<br />//添加索引username<br />ALTER TABLE `abc` ADD INDEX `abc` (`username`); <br />出自蓝草空间<br /></p><img src ="http://www.blogjava.net/huyi2006/aggbug/208867.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi2006/" target="_blank">allic</a> 2008-06-18 14:41 <a href="http://www.blogjava.net/huyi2006/articles/208867.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>php下操作sqlite的一个类</title><link>http://www.blogjava.net/huyi2006/articles/203413.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Wed, 28 May 2008 02:34:00 GMT</pubDate><guid>http://www.blogjava.net/huyi2006/articles/203413.html</guid><wfw:comment>http://www.blogjava.net/huyi2006/comments/203413.html</wfw:comment><comments>http://www.blogjava.net/huyi2006/articles/203413.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi2006/comments/commentRss/203413.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi2006/services/trackbacks/203413.html</trackback:ping><description><![CDATA[
		<p>class Sqlite {<br />var $link;<br />var $querynum = 0;</p>
		<p>/*连接Sqlite数据库，参数：dbname-&gt;数据库名字*/<br />function Open($dbname) {<br />if(!($this-&gt;link = @sqlite_open($dbname))) {<br />$this-&gt;halt('Can not Open to Sqlite');<br />}<br />}</p>
		<p>/*执行sql语句，返回对应的结果标识*/<br />function Query($sql) {<br />$this-&gt;querynum++;<br />if($query = @sqlite_query($this-&gt;link, $sql)) {<br />return $query;<br />} else {<br />$this-&gt;halt('Sqlite Query Error', $sql);<br />}<br />}</p>
		<p>/*执行Insert Into语句，并返回最后的insert操作所产生的自动增长的id*/<br />function Insert($table, $iarr) {<br />$value = $this-&gt;InsertSql($iarr);<br />$this-&gt;Query('INSERT INTO "' . $table . '" ' . $value);<br />return sqlite_last_insert_rowid($this-&gt;link);<br />}</p>
		<p>/*执行Update语句，并返回最后的update操作所影响的行数*/<br />function Update($table, $uarr, $condition = '') {<br />$value = $this-&gt;UpdateSql($uarr);<br />if ($condition) {<br />$condition = ' WHERE ' . $condition;<br />}<br />$this-&gt;Query('UPDATE "' . $table . '"' . ' SET ' . $value . $condition);<br />return sqlite_changes($this-&gt;link);<br />}</p>
		<p>/*执行Delete语句，并返回最后的Delete操作所影响的行数*/<br />function Delete($table, $condition = '') {<br />if ($condition) {<br />$condition = ' WHERE ' . $condition;<br />}<br />$this-&gt;Query('DELETE "' . $table . '"' . $condition);<br />return sqlite_changes($this-&gt;link);<br />}</p>
		<p>/*将字符转为可以安全保存的sqlite值，比如a'a转为a''a*/<br />/*<br />function EnCode($str) {<br />if (strpos($str, "\0") === false) {<br />if (strpos($str, '\'') === false) {<br />return $str;<br />} else {<br />return str_replace('\'', '\'\'', $str);<br />}<br />} else {<br />$str = str_replace("\0", '', $str);<br />if (strpos($str, '\'') === false) {<br />return $str;<br />} else {<br />return str_replace('\'', '\'\'', $str);<br />}<br />}<br />}<br />*/<br />function EnCode($str) {<br />return sqlite_escape_string($str);<br />}</p>
		<p>/*将可以安全保存的sqlite值转为正常的值，比如a''a转为a'a*/<br />function DeCode($str) {<br />if (strpos($str, '\'\'') === false) {<br />return $str;<br />} else {<br />return str_replace('\'\'', '\'', $str);<br />}<br />}</p>
		<p>/*将对应的列和值生成对应的insert语句，如：array('id' =&gt; 1, 'name' =&gt; 'name')返回("id", "name") VALUES (1, 'name')*/<br />function InsertSql($iarr) {<br />if (is_array($iarr)) {<br />$fstr = '';<br />$vstr = '';<br />foreach ($iarr as $key =&gt; $val) {<br />$fstr .= '"' . $key . '", ';<br />$vstr .= '\'' . $val . '\', ';<br />}<br />if ($fstr) {<br />$fstr = '(' . substr($fstr, 0, -2) . ')';<br />$vstr = '(' . substr($vstr, 0, -2) . ')';<br />return $fstr . ' VALUES ' . $vstr;<br />} else {<br />return '';<br />}<br />} else {<br />return '';<br />}<br />}</p>
		<p>/*将对应的列和值生成对应的insert语句，如：array('id' =&gt; 1, 'name' =&gt; 'name')返回"id" = 1, "name" = 'name'*/<br />function UpdateSql($uarr) {<br />if (is_array($uarr)) {<br />$ustr = '';<br />foreach ($uarr as $key =&gt; $val) {<br />$ustr .= '"' . $key . '" = \'' . $val . '\', ';<br />}<br />if ($ustr) {<br />return substr($ustr, 0, -2);<br />} else {<br />return '';<br />}<br />} else {<br />return '';<br />}<br />}</p>
		<p>/*返回对应的查询标识的结果的一行*/<br />function GetRow($query, $result_type = SQLITE_ASSOC) {<br />return sqlite_fetch_array($query, $result_type);<br />}</p>
		<p>/*清空查询结果所占用的内存资源*/<br />function Clear($query) {<br />$query = null;<br />return true;<br />}</p>
		<p>/*关闭数据库*/<br />function Close() {<br />return sqlite_close($this-&gt;link);<br />}</p>
		<p>function halt($message = '', $sql = '') {<br />$ei = sqlite_last_error($this-&gt;link);<br />$message .= '&lt;br /&gt;Sqlite Error: ' . $ei . ', ' . sqlite_error_string($ei);<br />if ($sql) {<br />$sql = '&lt;br /&gt;sql:' . $sql;<br />}<br />exit('DataBase Error.&lt;br /&gt;Message: ' . $message . $sql);<br />}<br />}</p>
<img src ="http://www.blogjava.net/huyi2006/aggbug/203413.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi2006/" target="_blank">allic</a> 2008-05-28 10:34 <a href="http://www.blogjava.net/huyi2006/articles/203413.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于sqlite_exec回调函数中参数传递的问题</title><link>http://www.blogjava.net/huyi2006/articles/199724.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Sat, 10 May 2008 08:32:00 GMT</pubDate><guid>http://www.blogjava.net/huyi2006/articles/199724.html</guid><wfw:comment>http://www.blogjava.net/huyi2006/comments/199724.html</wfw:comment><comments>http://www.blogjava.net/huyi2006/articles/199724.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi2006/comments/commentRss/199724.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi2006/services/trackbacks/199724.html</trackback:ping><description><![CDATA[
		<p>上一篇转载的文章中涉及到了如何用C来作回调函数读取或写入SQLITE数据库的问题，但其中没有关于回调函数如何作参数传递的问题，比如想要在你的主调函数中获取该变量，就需要通过调用sqlite3_exec函数给回调函数传递结构体指针，下面我作了一例：<br />     <br />#include &lt;stdio.h&gt;<br />#include &lt;stdlib.h&gt;<br />#include &lt;sqlite3.h&gt;</p>
		<p>struct olt_info<br />{<br />    int olt_index;<br />    int onu_on_line;<br />    int ui_port1;<br />    int ui_port2;<br />    int ui_port3;<br />    int ui_port4;<br />};</p>
		<p>int my_callback(void * olt_temp, int argc, char * value[], char * name[])<br />{<br />    int i;<br />    struct olt_info * pdata = NULL;</p>
		<p>    pdata = (struct olt_info *)olt_temp;<br />    <br />    puts("Here below is the code line:\n");<br />    for (i = 0; i &lt; argc; i++)<br />    {<br />        printf("%s == %s\n", name[i], value[i]);<br />    }<br />    puts("Code line over.\n");<br />    <br />    pdata-&gt;olt_index = (int)atoi(value[0]);<br />    pdata-&gt;onu_on_line = (int)atoi(value[1]);<br />    pdata-&gt;ui_port1 = (int)atoi(value[2]);<br />    pdata-&gt;ui_port2 = (int)atoi(value[3]);<br />    pdata-&gt;ui_port3 = (int)atoi(value[4]);<br />    pdata-&gt;ui_port4 = (int)atoi(value[5]);<br />    <br />    return 0;<br />}</p>
		<p>int main(int argc, char * argv[])<br />{<br />    sqlite3 * olt_db = NULL;<br />    int rc = 0;<br />    int i;<br />    char * err_msg = NULL;<br />    char temp_msg[150];<br />    struct olt_info * olt_temp= (struct olt_info *)malloc(sizeof(struct olt_info));    <br />    <br />    rc = sqlite3_open("olt.db", &amp;olt_db);<br />    if (rc)<br />    {<br />        fprintf(stderr, "Open database error, %s\n", sqlite3_errmsg(olt_db));<br />        exit(1);<br />    }<br />    else<br />    {<br />        fprintf(stdout, "Open database OK.\n");<br />    }</p>
		<p>    rc = sqlite3_exec(olt_db, "create table olt_tbl(olt_index integer primary key autoincrement, onu_on_line smallint, ui_port1 smallint, ui_port2 smallint, ui_port3 smallint, ui_port4 smallint);", NULL, NULL, &amp;err_msg);</p>
		<p>    if (rc != SQLITE_OK)<br />    {<br />        fprintf(stderr, "Create table error, %s\n", err_msg);<br />        exit(1);<br />    }<br />    else<br />    {<br />        fprintf(stdout, "Create table OK.\n");<br />    }</p>
		<p>    for (i = 0; i &lt; 6; i++)<br />    {<br />        sprintf(temp_msg, "insert into olt_tbl(onu_on_line, ui_port1, ui_port2, ui_port3, ui_port4) values(%d, %d, %d, %d, %d)", i * 16, i, i, i, i);<br />        //rc = sqlite3_exec(olt_db, "insert into olt_tbl(onu_on_line, ui_port1, ui_port2, ui_port3, ui_port4) values(32, 1, 1, 1, 1);", NULL, NULL, &amp;err_msg);<br />        rc = sqlite3_exec(olt_db, temp_msg, NULL, NULL, &amp;err_msg);<br />    }</p>
		<p>    if (rc != SQLITE_OK)<br />    {<br />        fprintf(stderr, "Insert items failure, %s\n", err_msg);<br />    }<br />    else<br />    {<br />        fprintf(stdout, "Insert items OK.\n");<br />    }</p>
		<p>    rc = sqlite3_exec(olt_db, "select * from olt_tbl where olt_index==4;", my_callback, olt_temp, &amp;err_msg);<br />    if (rc != SQLITE_OK)<br />    {<br />        fprintf(stderr, "Selete from olt_tbl failure, %s\n", err_msg);<br />        exit(1);<br />    }<br />    else<br />    {<br />        fprintf(stdout, "Excute sql OK.\n");<br />    }</p>
		<p>     printf("%d-%d-%d-%d-%d-%d\n", olt_temp-&gt;olt_index, olt_temp-&gt;onu_on_line,olt_temp-&gt;ui_port1,olt_temp-&gt;ui_port2,olt_temp-&gt;ui_port3,olt_temp-&gt;ui_port4);</p>
		<p>    free(olt_temp);</p>
		<p>    sqlite3_close(olt_db);<br />    return 0;<br />}</p>
		<p>其中my_callback(void * pdata, int argc, char * value[], char *name[])为回调函数，切记回调函数只能按照这种格式来定义参数，<br />    第一个参数为你的主调函数传递过来的指针，<br />    第二个参数为变量的个数，<br />    第三个为变量的值，<br />    第四个为变量的名称，<br />    有两个问题需要注意：<br />        一、这里面参数都是字符串类型，根据您的需要作出强制类型转换即可。<br />        二、第一个参数为void *类型，需要在你的回调函数里强制转换成需要的类型。<br /> </p>
		<p>
				<br />Trackback: <a href="http://tb.blog.csdn.net/TrackBack.aspx?PostId=1914908">http://tb.blog.csdn.net/TrackBack.aspx?PostId=1914908</a></p>
		<p> </p>
<img src ="http://www.blogjava.net/huyi2006/aggbug/199724.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi2006/" target="_blank">allic</a> 2008-05-10 16:32 <a href="http://www.blogjava.net/huyi2006/articles/199724.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在VC6.0中使用sqlite数据库</title><link>http://www.blogjava.net/huyi2006/articles/199720.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Sat, 10 May 2008 08:21:00 GMT</pubDate><guid>http://www.blogjava.net/huyi2006/articles/199720.html</guid><wfw:comment>http://www.blogjava.net/huyi2006/comments/199720.html</wfw:comment><comments>http://www.blogjava.net/huyi2006/articles/199720.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi2006/comments/commentRss/199720.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi2006/services/trackbacks/199720.html</trackback:ping><description><![CDATA[
		<p>在sqlite.org 上下载得到Windows版本的sqlite,它是以sqlitedll.zip文件提供的,其中有sqlite3.def和 sqlite3.dll文件,当然可以直接通过LoadLibrary等WIN32API来操作dll,查找其中包含的函数,并使用这些函数,但是一般都 不这么做,原因很简单:这样太麻烦,所以一般先使用LIB命令生成用于链接的lib,然后把sqlite头文件sqlite3.h包含进程序中,<br />这样直接调用 sqlite的API就方便多了.当然sqlite3.h文件得从sqlite源代码（以sqlite-source-3_3_4.zip文件提供）中搞到,在源码中sqlite3.h这个头文件是sqlite3.h.in存在的，解压出来改成sqlite.h就可以了. <br />使用VC++的LIB命令有以下步骤： <br />（1）设置VC98中LIB.exe所在的路径： <br />D:\MyDoc\db\capi&gt;set path=%path%;"D:\Program Files\Microsoft Visual Studio\VC98\Bin" <br />(2)生成SQLite的lib文件： <br />D:\MyDoc\db\capi&gt;LIB /DEF:SQLITE3.DEF /MACHINE:IX86 </p>
		<p>Microsoft (R) Library Manager Version 6.00.8168 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. Creating library SQLITE.lib and object SQLITE.exp <br />  这样就成功地创建了在WIN32程序中访问sqlite所需要的库,可以用于链接WIN32程序. <br />    到此所有使用sqlite的准备工作已告罄.现在在MSVC6中新建一个Win32 Console Application工程,把sqlite.dll,sqlite.h和sqlite.lib文件复制到工程文件夹中,把sqlite.h文件加入到项 目中,然后在Project Setting的Link中的对象库模块中增加sqlite.lib文件. 或者project-&gt;add to project-&gt;files，选择这个lib文件<br />然后修改加入如下代码即可: </p>
		<p>#include &lt;IOSTREAM&gt;<br />#include &lt;STRING&gt;<br />#include &lt;SSTREAM&gt;<br />#include &lt;stdio.h&gt;<br />#include "sqlite3.h"</p>
		<p>using namespace std;</p>
		<p>sqlite3* pDB;</p>
		<p>int createTable()<br />{<br />  char* errMsg;<br />  std::string dropTab="drop table test_tab;";<br />  string strSQL= "create table test_tab (f1 int, f2 long, f3 varchar(20));";<br />  int res = sqlite3_exec(pDB,dropTab.c_str(),0,0, &amp;errMsg);<br />  if (res != SQLITE_OK)<br />  {<br />   std::cout &lt;&lt; "执行SQL 出错." &lt;&lt; errMsg &lt;&lt; std::endl;<br />   //return -1;<br />  } </p>
		<p>  res = sqlite3_exec(pDB,strSQL.c_str(),0,0, &amp;errMsg);</p>
		<p>  if (res != SQLITE_OK)<br />  {<br />    std::cout &lt;&lt; "执行创建table的SQL 出错." &lt;&lt; errMsg &lt;&lt; std::endl;<br />    return -1;<br />  }<br />  else<br />  {<br />      std::cout &lt;&lt; "创建table的SQL成功执行."&lt;&lt; std::endl;<br />  }</p>
		<p>  return 0;<br />}</p>
		<p>int insert1()<br />{<br />  char* errMsg;</p>
		<p>  int res = sqlite3_exec(pDB,"begin transaction;",0,0, &amp;errMsg);</p>
		<p>  for (int i= 1; i &lt; 100; ++i)<br />  {<br />    std::stringstream strsql;<br />    strsql &lt;&lt; "insert into test_tab  values(";<br />    strsql  &lt;&lt; i &lt;&lt; ","&lt;&lt; (i+10) &lt;&lt;",'huyi'"&lt;&lt; ");";<br />    std::string str = strsql.str();<br />    cout &lt;&lt; str &lt;&lt;endl;<br />    res = sqlite3_exec(pDB,str.c_str(),0,0, &amp;errMsg);<br />    if (res != SQLITE_OK)<br />    {<br />      std::cout &lt;&lt; "执行SQL 出错." &lt;&lt; errMsg &lt;&lt; std::endl;<br />      return -1;<br />    }<br />  }<br />  res = sqlite3_exec(pDB,"commit transaction;",0,0, &amp;errMsg);<br />  std::cout &lt;&lt; "SQL成功执行."&lt;&lt; std::endl;<br />  return 0; <br />}</p>
		<p>
				<br />int select1()<br />{<br />  char* errMsg;<br /> int nrow = 0, ncolumn = 0;<br /> char **azResult; //二维数组存放结果<br />  string strSQL= "select * from test_tab;";<br />     /*<br />  int res = sqlite3_exec(pDB,strSQL.c_str(),0,0, &amp;errMsg);</p>
		<p>  if (res != SQLITE_OK)<br />  {<br />    std::cout &lt;&lt; "执行SQL 出错." &lt;&lt; errMsg &lt;&lt; std::endl;<br />    return -1;<br />  }<br />  else<br />  {<br />       std::cout &lt;&lt; "SQL成功执行."&lt;&lt; std::endl;<br />  }<br />  */<br />  sqlite3_get_table(pDB, strSQL.c_str(), &amp;azResult, &amp;nrow, &amp;ncolumn, &amp;errMsg);<br />     int i = 0;<br />  for( i=0 ; i&lt;( nrow + 1 ) * ncolumn ; i++ )<br />  {<br />   if (i&gt;0 &amp;&amp; i%ncolumn==0)<br />    printf("\n");<br />      printf( "%s ",azResult[i]);<br />  }<br />         printf("\n");<br />  //释放掉 azResult 的内存空间<br />  sqlite3_free_table( azResult );<br />  sqlite3_close(pDB); //关闭数据库<br />  return 0;<br />}</p>
		<p>int main(int argc, char* argv[])<br />{<br />  if (argc &lt; 2)<br />  {<br />    std::cout &lt;&lt; "请输入命令行参数：sqlite数据库名." &lt;&lt; std::endl;<br />    return 0;<br />  }</p>
		<p>  int res = sqlite3_open(argv[1], &amp;pDB);</p>
		<p>  if( res ){<br />    std::cout &lt;&lt; "Can't open database: "&lt;&lt; sqlite3_errmsg(pDB);<br />    sqlite3_close(pDB);<br />    return -1;<br />  }<br />  res = createTable();<br />  if (res != 0)<br />  {<br />      return 0;<br />  }<br />  res = insert1();<br />  if (res != 0)<br />  {<br />      return 0;<br />  }<br />  select1();<br />   return 0;<br />}<br /></p>
<img src ="http://www.blogjava.net/huyi2006/aggbug/199720.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi2006/" target="_blank">allic</a> 2008-05-10 16:21 <a href="http://www.blogjava.net/huyi2006/articles/199720.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据库设计指南</title><link>http://www.blogjava.net/huyi2006/articles/197518.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Wed, 30 Apr 2008 06:07:00 GMT</pubDate><guid>http://www.blogjava.net/huyi2006/articles/197518.html</guid><wfw:comment>http://www.blogjava.net/huyi2006/comments/197518.html</wfw:comment><comments>http://www.blogjava.net/huyi2006/articles/197518.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi2006/comments/commentRss/197518.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi2006/services/trackbacks/197518.html</trackback:ping><description><![CDATA[
		<br />
		<font style="BACKGROUND-COLOR: #ffffff" color="#808080">如果把企业的数据比做生命所必需的血液，那么数据库的设计就是应用中最重要的一部分。有关数据<br />库设计的材料汗牛充栋，大学学位课程里也有专门的讲述。不过，就如我们反复强调的那样，再好的<br />老师也比不过经验的教诲。所以我们最近找了些对数据库设计颇有造诣的专业人士给大家传授一些设<br />计数据库的<u><strong>技巧</strong></u>和经验。我们的编辑从收到的130 个反馈中精选了其中的60 个最佳技巧，并把这些<br />技巧编写成了本文，为了方便索引其内容划分为5 个部分：<br />第1 部分— 设计数据库之前<br />这一部分罗列了12 个基本技巧，包括命名规范和明确业务需求等。<br />第2 部分— 设计数据库表<br />总共24 个指南性技巧，涵盖表内字段设计以及应该避免的常见问题等。<br />第3 部分— 选择键<br />怎么选择键呢？这里有10 个技巧专门涉及系统生成的主键的正确用法，还有何时以及如何索引字段<br />以获得最佳性能等。<br />第 4 部分 — 保证数据完整性<br />讨论如何保持数据库的清晰和健壮，如何把有害数据降低到最小程度。<br />第5 部分— 各种小技巧<br />不包括在以上4 个部分中的其他技巧，五花八门，有 了它们希望你的数据库开发工作会更轻松一些。<br />Page 2 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br /><strong>第1 部分— 设计数据库之前</strong><br />1. 考察现有环境<br />在设计一个新数据库时，你不但应该仔细研究业务需求而且还要考察现有的系统。大多数数据库<br />项目都不是从头开始建立的；通常，机构内总会存在用来满足特定需求的现有系统（可能没有实<br />现自动计算）。显然，现有系统并不完美，否则你就不必再建立新系统了。但是对旧系统的研究<br />可以让你发现一些可能会忽略的细微问题。一般来说，考察现有系统对你绝对有好处。<br />— Lamont Adams<br />我曾经接手过一个为地区运输公司开发的数据库项目，活不难，用的是Access 数据库。我设置<br />了一些项目设计参数，而且同客户一道对这些参数进行了评估，事先还查看了开发环境下所采取<br />的工作模式，等到最后部署应用的时候，只见终端上出了几个提示符然后立马在我面前翘辫子<br />了！抓耳挠腮的折腾了好几个小时，我才意识到，原来这家公司的<u><strong>网络</strong></u>上跑着两个数据库应用，<br />而对网络的访问需要明确和严格的用户帐号及其访问权限。明白了这一点，问题迎刃而解：只需<br />采用客户的系统即可。这个项目给我的教训就是：记住，假如你在诸如Access 或者Interbase 这<br />类公共环境下开发应用程序，一定要从表面下手深入系统内部搞清楚你面临的环境到底是怎么回<br />事。<br />— kg<br />2. <strong>定义标准的<u>对象</u>命名规范</strong><br />一定要定义数据库对象的命名规范 。对数据库表来说，从项目一开始就要确定表名是采用复数还<br />是单数形式。此外还要给表的别名定义简单规则（比方说，如果表名是一个单词，别名就取单词<br />的前4 个字母；如果表名是两个单词，就各取两个单词的前两个字母组成4 个字母长的别名；如<br />果表的名字由3 个单词组成，你不妨从头两个单词中各取一个然后从最后一个单词中再取出两个<br />字母，结果还是组成4 字母长的别名，其余依次类推）对工作用表来说，表名可以加上前缀<br />WORK_ 后面附上采用该表的应用程序的名字。表内的列要针对键采用一整套设计规则。比如，<br />如果键是数字类型，你可以用_NO 作为后缀；如果是字符类型则可以采用 _CODE 后缀。对列名<br />应该采用标准的前缀和后缀。再如，假如你的表里有好多“money”字段，你不妨给每个列增加<br />一个_AMT 后缀。还有，日期列最好以DATE_作为名字打头。<br />— richard<br />检查表名、报表名和查询名之间的命名规范。你可能会很快就被这些不同的数据库要素的名称搞<br />糊涂了。假如你坚持统一地命名这些数据库的不同组成部分，至少你应该在这些对象名字的开头<br />用table、query 或者report 等前缀加以区别。<br />— rrydenm<br />如果采用了Microsoft Access，你可以用 qry、rpt、 tbl 和mod 等符号来标识对象（比如<br />tbl_Employees）。我在和SQL Server（或者Oracle）打交道的时候还用过tbl 来索引表，但我<br />用sp_company （现在用sp_feft_）标识存储过程，因为在有的时候如果我发现了更好的处理办<br />法往往会保存好几个拷贝。我在实现 SQL Server 2000 时用udf_ （或者类似的标记）标识我编<br />写的函数。<br />— Timothy J. Bruce<br />Page 3 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br /><strong>3. 预先计划</strong><br />上个世纪80 年代初，我还在使用资产帐目系统和System 38 平台，那时我负责设计所有的日期<br />字段，这样在不费什么力气的情况下将来就可以轻松处理2000 年问题了。许多人给我说就别去<br />解决这一问题了，因为要处理起来太麻烦了（这在世人皆知的Y2K 问题之前很久了）。我回击说<br />只要预先计划今后就不会遇到大麻烦。结果我只用了两周的时间就把程序全部改完了。因为预先<br />计划的好，后来Y2K 问题对该系统的危害降到了最低程度（最近听说该程序甚至到了1995 年都<br />还运行在AS/400 系统上，唯一出现的小问题是从代码中删除注释费了点工夫）。<br />— generalist<br /><strong>4. 获取数据模式资源手册</strong><br />正在寻求示例模式的人可以阅读《 数据模式资源手册 》一书，该书由Len Silverston、W. H.<br />Inmon 和Kent Graziano 编写，是一本值得拥有的最佳数据建模图书。该书包括的章节涵盖多种<br />数据领域，比如人员、机构和工作效能等。<br />— minstrelmike<br /><strong>5. 畅想未来，但不可忘了过去的教训</strong><br />我发现询问用户如何看待未来需求变化非常有用。这样做可以达到两个目的：首先，你可以清楚<br />地了解应用设计在哪个地方应该更具灵活性以及如何避免性能瓶颈；其次，你知道发生事先没有<br />确定的需求变更时用户将和你一样感到吃惊。<br />— chrisdk<br />一定要记住过去的经验教训！我们开发人员还应该通过分享自己的体会和经验互相帮助。即使用<br />户认为他们再也不需要什么支持了，我们也应该对他们进行这方面的教育，我们都曾经面临过这<br />样的时刻“当初要是这么做了该多好⋯⋯”。<br />— dhattrem<br /><strong>6. 在物理实践之前进行逻辑设计</strong><br />在深入物理设计之前要先进行逻辑设计。随着大量的 CASE 工具不断涌现出来，你的设计也可以<br />达到相当高的逻辑水准，你通常可以从整体上更好地了解数据库设计所需要的方方面面。<br />— chardove<br /><strong>7. 了解你的业务</strong><br />在你百分百地确定系统从客户角度满足其需求之前不要在你的ER（实体关系）模式中加入哪怕<br />一个数据表（怎么，你还没有模式？那请你参看技巧9）。了解你的企业业务可以在以后的开发<br />阶段节约大量的时间。一旦你明确了业务需求，你就可以自己做出许多决策 了。<br />— rangel<br />一旦你认为你已经明确 了业务内容，你最好同客户进行一次系统的交流。采用客户的术语并且向<br />他们解释你所想到的和你所听到的。同时还应该用可能、将会和必须等词汇表达出系统的关系基<br />数。这样你就可以让你的客户纠正你自己的理解然后做好下一步的ER 设计。<br />— teburlew<br />Page 4 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br /><strong>8. 创建数据字典和ER 图表</strong><br />一定要花点时间创建ER 图表和数据字典。其中至少应该包含每个字段的数据类型和在每个表内<br />的主外键。创建ER 图表和数据字典确实有点费时但对其他开发人员要了解整个设计却是完全必<br />要的。越早创建越能有助于避免今后面临的可能混乱，从而可以让任何了解数据库的人都明确如<br />何从数据库中获得数据。<br />— bgumbert<br />有一份诸如ER 图表等最新文档其重要性如何强调都不过分，这对表明表之间关系很有用，而数<br />据字典则说明了每个字段的用途以及任何可能存在的别名。对SQL 表达式的文档化来说这是完<br />全必要的。<br />— vanduin.chris.cj<br /><strong>9. 创建模式</strong><br />一张图表胜过千言万语：开发人员不仅要阅读和实现它，而且还要用它来帮助自己和用户对话。<br />模式有助于提高协作效能，这样在先期的数据库设计中几乎不可能出现大的问题。模式不必弄的<br />很复杂；甚至可以简单到手写在一张纸上就可以了。只是要保证其上的逻辑关系今后能产生效<br />益。<br />— Dana Daigle<br /><strong>10. 从输入输出下手</strong><br />在定义数据库表和字段需求（输入）时，首先应检查现有的或者已经设计出的报表、查询和视图<br />（输出）以决定为了支持这些输出哪些是必要的表和字段。举个简单的例子：假如客户需要一个<br />报表按照邮政编码排序、分段和求和，你要保证其中包括了单独的邮政编码字段而不要把邮政编<br />码糅进地址字段里。<br />— peter.marshall<br /></font>
		<font style="BACKGROUND-COLOR: #ffffff">
				<font color="#808080">
						<strong>11. 报表技巧<br /></strong>要了解用户通常是如何报告数据的：批处理还是在线提交报表？时间间隔是每天、每周、每月、<br />每个季度还是每年？如果需要的话还可以考虑创建总结表。系统生成的主键在报表中很难管理。<br />用户在具有系统生成主键的表内用副键进行检索往往会返回许多重复数据。这样的检索性能比较<br />低而且容易引起混乱。<br />— kol<br /><strong>12. 理解客户需求</strong><br />看起来这应该是显而易见的事，但需求就是来自客户（这里要从内部和外部客户的角度考虑）。<br />不要依赖用户写下来的需求，真正的需求在客户的脑袋里。你要让客户解释其需求，而且随着开<br />发的继续，还要经常询问客户保证其需求仍然在开发的目的之中。一个不变的真理是：“只有我<br />看见了我才知道我想要的是什么”必然会导致大量的返工，因为数据库没有达到客户从来没有写<br />下来的需求标准。而更糟的是你对他们需求的解释只属于你自己，而且可能是完全错误的。<br />— kgilson<br />Page 5 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br />第2 部分— 设计表和字段<br />1. 检查各种变化<br />我在设计数据库的时候会考虑到哪些数据字段将来可能会发生变更。比方说，姓氏就是如此（注<br />意是西方人的姓氏，比如女性结婚后从夫姓等）。所以，在建立系统存储客户信息时，我倾向于<br />在单独的一个数据表里存储姓氏字段，而且还附加起始日和终止日等字段，这样就可以跟踪这一<br />数据条目的变化。<br />— Shropshire Lad<br />2. 采用有意义的字段名<br />有一回我参加开发过一个项目，其中有从其他程序员那里继承的程序，那个程序员喜欢用屏幕上<br />显示数据指示用语命名字段，这也不赖，但不幸的是，她还喜欢用一些奇怪的命名法，其命名采<br />用了匈牙利命名和控制序号的组合形式，比如cbo1、 txt2、txt2_b 等等。<br />除非你在使用只面向你的缩写字段名的系统，否则请尽可能地把字段描述的清楚些。当然，也别<br />做过头了，比如Customer_Shipping_Address_Street_Line_1 I 虽然很富有说明性，但没人愿意<br />键入这么长的名字，具体尺度就在你的把握中。<br />— Lamont Adams<br />3. 采用前缀命名<br />如果多个表里有好多同一类型的字段（比如FirstName），你不妨用特定表的前缀（比如<br />CusLastName）来帮助你标识字段。<br />— notoriousDOG<br />时效性数据应包括“最近更新日期/时间”字段。时间标记对查找数据问题的原因、按日期重新处<br />理/重载数据和清除旧数据特别有用。<br />— kol<br />5. 标准化和数据驱动<br />数据的标准化不仅方便了自己而且也方便了其他人。比方说，假如你的用户界面要访问外部数据<br />源（文件、XML 文档、其他数据库等），你不妨把相应的连接和路径信息存储在用户界面支持表<br />里。还有，如果用户界面执行工作流之类的任务（发送邮件、打印信笺、修改记录状态等），那<br />么产生工作流的数据也可以存放在数据库里。预先安排总需要付出努力，但如果这些过程采用数<br />据驱动而非硬编码的方式，那么策略变更和维护都会方便得多。事实上，如果过程是数据驱动<br />的，你就可以把相当大的责任推给用户，由用户来维护自己的工作流过程。<br />— tduvall<br />6. 标准化不能过头<br />对那些不熟悉标准化一词（normalization ）的人而言，标准化可以保证表内的字段都是最基础的<br />要素，而这一措施有助于消除数据库中的数据冗余。标准化有好几种形式，但Third Normal<br />Form（3NF）通常被认为在性能、扩展性和数据完整性方面达到了最好平衡。简单来说，3NF 规<br />定：<br />Page 6 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br />· 表内的每一个值都只能被表达一次。<br />· 表内的每一行都应该被唯一的标识（有唯一键）。<br />· 表内不应该存储依赖于其他键的非键信息。<br />遵守3NF 标准的数据库具有以下特点：有一组表专门存放通过键连接起来的关联数据。比方说，<br />某个存放客户及其有关定单的3NF 数据库就可能有两个表：Customer 和Order。Order 表不包<br />含定单关联客户的任何信息，但表内会存放一个键值，该键指向Customer 表里包含该客户信息<br />的那一行。<br />更高层次的标准化也有，但更标准是否就一定更好呢？答案是不一定。事实上，对某些项目来<br />说，甚至就连3NF 都可能给数据库引入太高的复杂性。<br />— Lamont Adams<br />为了效率的缘故，对表不进行标准化有时也是必要的，这样的例子很多。曾经有个开发财务分析<br />软件的活就是用非标准化表把查询时间从平均40 秒降低到了两秒左右。虽然我不得不这么做，<br />但我绝不把数据表的非标准化当作当然的设计理念。而具体的操作不过是一种派生。所以如果表<br />出了问题重新产生非标准化的表是完全可能的。<br />— epepke<br />7. Microsoft Access 报表技巧<br />如果你正在使用Microsoft Access，你可以用对用户友好的字段名来代替编号的名称：比如用<br />Customer Name 代替txtCNaM。这样，当你用向导程序创建表单和报表时，其名字会让那些不<br />是程序员的人更容易阅读。<br />— jwoodruf<br />8. 不活跃或者不采用的指示符<br />增加一个字段表示所在记录是否在业务中不再活跃挺有用的。不管是客户、员工还是其他什么<br />人，这样做都能有助于再运行查询的时候过滤活跃或者不活跃状态。同时还消除了新用户在采用<br />数据时所面临的一些问题，比如，某些记录可能不再为他们所用，再删除的时候可以起到一定 的<br />防范作用。<br />— theoden<br />9. 使用角色实体定义属于某类别的列<br />在需要对属于特定类别或者具有特定角色的事物做定义时，可以用角色实体来创建特定的时间关<br />联关系，从而可以实现自我文档化。<br />这里的含义不是让PERSON 实体带有Title 字段，而是说，为什么不用PERSON 实体和<br />PERSON_TYPE 实体来描述人员呢？然后，比方说，当 John Smith, Engineer 提升为John<br />Smith, Director 乃至最后爬到John Smith, CIO 的高位，而所有你要做的不过是改变两个表<br />PERSON 和PERSON_TYPE 之间关系的键值，同时增加一个日期/时间字段来知道变化是何时<br />发生的。这样，你的PERSON_TYPE 表就包含了所有PERSON 的可能类型，比如Associate、<br />Engineer、Director、CIO 或者CEO 等。<br />还有个替代办法就是改变PERSON 记录来反映新头衔的变化，不过这样一来在时间上无法跟踪<br />个人所处位置的具体时间。<br />Page 7 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br />— teburlew<br />10. 采用常用实体命名机构数据<br />组织数据的最简单办法就是采用常用名字，比如：PERSON、ORGANIZATION、ADDRESS 和<br />PHONE 等等。当你把这些常用的一般名字组合起来或者创建特定的相应副实体时，你就得到了<br />自己用的特殊版本。开始的时候采用一般术语的主要原因在于所有的具体用户都能对抽象事物具<br />体化。<br />有了这些抽象表示，你就可以在第2 级标识中采用自己的特殊名称，比如，PERSON 可能是<br />Employee、Spouse、Patient、Client、Customer、Vendor 或者Teacher 等。同样的，<br />ORGANIZATION 也可能是MyCompany、MyDepartment、Competitor、Hospital、<br />Warehouse、Government 等。最后ADDRESS 可以具体为Site、Location、Home、Work、<br />Client、Vendor、Corporate 和FieldOffice 等。<br />采用一般抽象术语来标识“事物”的类别可以让你在关联数据以满足业务要求方面获得巨大的灵<br />活性，同时这样做还可以显著降低数据存储所需的冗余量。<br />— teburlew<br />11. 用户来自世界各地<br />在设计用到网络或者具有其他国际特性的数据库时，一定要记住大多数国家都有不同的字段格<br />式，比如邮政编码等，有些国家，比如新西兰就没有邮政编码一说。<br />— billh<br />12. 数据重复需要采用分立的数据表<br />如果你发现自己在重复输入数据，请创建新表和新的关系。<br />— Alan Rash<br />13. 每个表中都应该添加的3 个有用的字段<br />· dRecordCreationDate，在VB 下默认是Now()，而在SQL Server 下默认为GETDATE()<br />· sRecordCreator，在SQL Server 下默认为NOT NULL DEFAULT USER<br />· nRecordVersion，记录的版本标记；有助于准确说明记录中出现null 数据或者丢失数据的原<br />因<br />— Peter Ritchie<br />14. 对地址和电话采用多个字段<br />描述街道地址就短短一行记录是不够的。Address_Line1、Address_Line2 和Address_Line3 可<br />以提供更大的灵活性。还有，电话号码和邮件地址最好拥有自己的数据表，其间具有自身的类型<br />和标记类别。<br />— dwnerd<br />过分标准化可要小心，这样做可能会导致性能上出现问题。虽然地址和电话表分离通常可以达到<br />最佳状态，但是如果需要经常访问这类信息，或许在其父表中存放“首选”信息（比如<br />Customer 等）更为妥当些。非标准化和加速访问之间的妥协是有一定意义的。<br />— dhattrem<br />Page 8 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br />15. 使用多个名称字段<br />我觉得很吃惊，许多人在数据库里就给 name 留一个字段。我觉得只有刚入门的开发人员才会这<br />么做，但实际上网上这种做法非常普遍。我建议应该把姓氏和名字当作两个字段来处理，然后在<br />查询的时候再把他们组合起来。<br />— klempan<br />Klempan 不是唯一一个注意到使用单个name 字段的人，要把这种情况变得对用户更为友好有好<br />些方法。我最常用的是在同一表中创建一个计算列，通过它可以自动地连接标准化后的字段，这<br />样数据变动的时候它也跟着变。不过，这样做在采用建模软件时得很机灵才行。总之，采用连接<br />字段的方式可以有效的隔离用户应用和开发人员界面。<br />— damon<br />16. 提防大小写混用的对象名和特殊字符<br />过去最令我恼火的事情之一就是数据库里有大小写混用的对象名，比如CustomerData。这一问<br />题从Access 到Oracle 数据库都存在。我不喜欢采用这种大小写混用的对象命名方法，结果还不<br />得不手工修改名字。想想看，这种数据库/应用程序能混到采用更强大数据库的那一天吗？采用全<br />部大写而且包含下划符的名字具有更好的可读性（CUSTOMER_DATA），绝对不要在对象名的<br />字符之间留空格。<br />— bfren<br />17. 小心保留词<br />要保证你的字段名没有和保留词、数据库系统或者常用访问方法冲突，比如，最近我编写的一个<br />ODBC 连接程序里有个表，其中就用了DESC 作为说明字段名。后果可想而知！DESC 是<br />DESCENDING 缩写后的保留词。表里的一个SELECT *语句倒是能用，但我得到的却是一大堆<br />毫无用处的信息。<br />— Daniel Jordan<br />18. 保持字段名和类型的一致性<br />在命名字段并为其指定数据类型的时候一定要保证一致性。假如字段在某个表中叫做<br />“agreement_number”，你就别在另一个表里把名字改成“ref1”。假如数据类型在一个表里<br />是整数，那在另一个表里可就别变成字符型了。记住，你干完自己的活了，其他人还要用你的数<br />据库呢。<br />— setanta<br />19. 仔细选择数字类型<br />在SQL 中使用smallint 和tinyint 类型要特别小心，比如，假如你想看看月销售总额，你的总额字<br />段类型是smallint，那么，如果总额超过了$32,767 你就不能进行计算操作了。<br />— egermain<br />20. 删除标记<br />在表中包含一个“删除标记”字段，这样就可以把行标记为删除。在关系数据库里不要单独删除<br />某一行；最好采用清除数据程序而且要仔细维护索引整体性。<br />— kol<br />Page 9 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br />21. 避免使用触发器<br />触发器的功能通常可以用其他方式实现。在调试程序时触发器可能成为干扰。假如你确实需要采<br />用触发器，你最好集中对它文档化。<br />— kol<br />22. 包含版本机制<br />建议你在数据库中引入版本控制机制来确定使用中的数据库的版本。无论如何你都要实现这一要<br />求。时间一长，用户的需求总是会改变的。最终可能会要求修改数据库结构。虽然你可以通过检<br />查新字段或者索引来确定数据库结构的版本，但我发现把版本信息直接存放到数据库中不更为方<br />便吗？。<br />— Richard Foster<br />23. 给文本字段留足余量<br />ID 类型的文本字段，比如客户ID 或定单号等等都应该设置得比一般想象更大，因为时间不长你<br />多半就会因为要添加额外的字符而难堪不已。比方说，假设你的客户ID 为10 位数长。那你应该<br />把数据库表字段的长度设为12 或者13 个字符长。这算浪费空间吗？是有一点，但也没你想象的<br />那么多：一个字段加长3 个字符在有1 百万条记录，再加上一点索引的情况下才不过让整个数据<br />库多占据3MB 的空间。但这额外占据的空间却无需将来重构整个数据库就可以实现数据库规模<br />的增长了。<br />— tlundin<br />24. 列命名技巧<br />我们发现，假如你给每个表的列名都采用统一的前缀，那么在编写SQL 表达式的时候会得到大<br />大的简化。这样做也确实有缺点，比如破坏了自动表连接工具的作用，后者把公共列名同某些数<br />据库联系起来，不过就连这些工具有时不也连接错误嘛。举个简单的例子，假设有两个表：<br />Customer 和Order。Customer 表的前缀是cu_，所以该表内的子段名如下：cu_name_id、<br />cu_surname、cu_initials 和cu_address 等。Order 表的前缀是or_，所以子段名是：<br />or_order_id、or_cust_name_id、or_quantity 和or_descrīption 等。<br />这样从数据库中选出全部数据的SQL 语句可以写成如下所示：<br />Select * from Customer, Order<br />Where cu_surname = "MYNAME"<br />and cu_name_id = or_cust_name_id<br />and or_quantity = 1;<br />在没有这些前缀的情况下则写成这个样子：<br />Select * from Customer, Order<br />Where Customer.surname = "MYNAME"<br />and Customer.name_id = Order.cust_name_id<br />and Order.quantity = 1<br />第1 个SQL 语句没少键入多少字符。但如果查询涉及到5 个表乃至更多的列你就知道这个技巧<br />多有用了。<br />— Bryce Stenberg<br />Page 10 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br />第3 部分— 选择键和索引<br />1. 数据采掘要预先计划<br />我所在的市场部门一度要处理8 万多份联系方式，同时填写每个客户的必要数据（这绝对不是小<br />活）。我从中还要确定出一组客户作为市场目标。当我从最开始设计表和字段的时候，我试图不<br />在主索引里增加太多的字段以便加快数据库的运行速度。然后我意识到特定的组查询和信息采掘<br />既不准确速度也不快。结果只好在主索引中重建而且合并了数据字段。我发现有一个指示计划相<br />当关键——当我想创建系统类型查找时为什么要采用号码作为主索引字段呢？我可以用传真号码<br />进行检索，但是它几乎就象系统类型一样对我来说并不重要。采用后者作为主字段，数据库更新<br />后重新索引和检索就快多了。<br />— hscovell<br />可操作数据仓库（ODS）和数据仓库（DW）这两种环境下的数据索引是有差别的。在DW 环境<br />下，你要考虑销售部门是如何组织销售活动的。他们并不是数据库管理员，但是他们确定表内的<br />键信息。这里设计人员或者数据库工作人员应该分析数据库结构从而确定出性能和正确输出之间<br />的最佳条件。<br />— teburlew<br />2. 使用系统生成的主键<br />这一天类同技巧1，但我觉得有必要在这里重复提醒大家。假如你总是在设计数据库的时候采用<br />系统生成的键作为主键，那么你实际控制了数据库的索引完整性。这样，数据库和非人工机制就<br />有效地控制了对存储数据中每一行的访问。<br />采用系统生成键作为主键还有一个优点：当你拥有一致的键结构时，找到逻辑缺陷很容易。<br />— teburlew<br />3. 分解字段用于索引<br />为了分离命名字段和包含字段以支持用户定义的报表，请考虑分解其他字段（甚至主键）为其组<br />成要素以便用户可以对其进行索引。索引将加快SQL 和报表生成器脚本的执行速度。比方说，<br />我通常在必须使用SQL LIKE 表达式的情况下创建报表，因为 case number 字段无法分解为<br />year、serial number、case type 和defendant code 等要素。性能也会变坏。假如年度和类型字<br />段可以分解为索引字段那么这些报表运行起来就会快多了。<br />— rdelval<br />4. 键设计4 原则<br />· 为关联字段创建外键。<br />· 所有的键都必须唯一。<br />· 避免使用复合键。<br />· 外键总是关联唯一的键字段。<br />— Peter Ritchie<br />Page 11 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br />5. 别忘了索引<br />索引是从数据库中获取数据的最高效方式之一。95%的数据库性能问题都可以采用索引技术得到<br />解决。作为一条规则，我通常对逻辑主键使用唯一的成组索引，对系统键（作为存储过程）采用<br />唯一的非成组索引，对任何外键列采用非成组索引。不过，索引就象是盐，太多了菜就篌了。你<br />得考虑数据库的空间有多大，表如何进行访问，还有这些访问是否主要用作读写。<br />— tduvall<br />大多数数据库都索引自动创建的主键字段，但是可别忘了索引外键，它们也是经常使用的键，比<br />如运行查询显示主表和所有关联表的某条记录就用得上。还有，不要索引memo/note 字段，不<br />要索引大型字段（有很多字符），这样作会让索引占用太多的存储空间。<br />— gbrayton<br />6. 不要索引常用的小型表<br />不要为小型数据表设置任何键，假如它们经常有插入和删除操作就更别这样作了。对这些插入和<br />删除操作的索引维护可能比扫描表空间消耗更多的时间。<br />— kbpatel<br />7. 不要把社会保障号码（SSN）选作键<br />永远都不要使用SSN 作为数据库的键。除了隐私原因以外，须知政府越来越趋向于不准许把<br />SSN 用作除收入相关以外的其他目的，SSN 需要手工输入。永远不要使用手工输入的键作为主<br />键，因为一旦你输入错误，你唯一能做的就是删除整个记录然后从头开始。<br />— teburlew<br />上个世纪70 年代我还在读大学的时候，我记得那时SSN 还曾被用做学号，当然尽管这么做是非<br />法的。而且人们也都知道这是非法的，但他们已经习惯了。后来，随着盗取身份犯罪案件的增<br />加，我现在的大学校园正痛苦地从一大摊子数据中把SSN 删除。<br />— generalist<br />8. 不要用用户的键<br />在确定采用什么字段作为表的键的时候，可一定要小心用户将要编辑的字段。通常的情况下不要<br />选择用户可编辑的字段作为键。这样做会迫使你采取以下两个措施：<br />· 在创建记录之后对用户编辑字段的行为施加限制。假如你这么做了，你可能会发现你的应用程<br />序在商务需求突然发生变化，而用户需要编辑那些不可编辑的字段时缺乏足够的灵活性。当用<br />户在输入数据之后直到保存记录才发现系统出了问题他们该怎么想？删除重建？假如记录不可<br />重建是否让用户走开？<br />· 提出一些检测和纠正键冲突的方法。通常，费点精力也就搞定了，但是从性能上来看这样做的<br />代价就比较大了。还有，键的纠正可能会迫使你突破你的数据和商业/用户界面层之间的隔<br />离。<br />所以还是重提一句老话：你的设计要适应用户而不是让用户来适应你的设计。<br />— Lamont Adams<br />不让主键具有可更新性的原因是在关系模式下，主键实现了不同表之间的关联。比如，<br />Customer 表有一个主键CustomerID，而客户的定单则存放在另一个表里。Order 表的主键可能<br />Page 12 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br />是OrderNo 或者OrderNo、CustomerID 和日期的组合。不管你选择哪种键设置，你都需要在<br />Order 表中存放CustomerID 来保证你可以给下定单的用户找到其定单记录。<br />假如你在Customer 表里修改了CustomerID，那么你必须找出Order 表中的所有相关记录对其进<br />行修改。否则，有些定单就会不属于任何客户——数据库的完整性就算完蛋了。<br />如果索引完整性规则施加到表一级，那么在不编写大量代码和附加删除记录的情况下几乎不可能<br />改变某一条记录的键和数据库内所有关联的记录。而这一过程往往错误丛生所以应该尽量避免。<br />— ljboast<br />9. 可选键有时可做主键<br />记住，查询数据的不是机器而是人。<br />假如你有可选键，你可能进一步把它用做主键。那样的话，你就拥有了建立强大索引的能力。这<br />样可以阻止使用数据库的人不得不连接数据库从而恰当的过滤数据。在严格控制域表的数据库<br />上，这种负载是比较醒目的。如果可选键真正有用，那就是达到了主键的水准。<br />我的看法是，假如你有可选键，比如国家表内的state_code，你不要在现有不能变动的唯一键上<br />创建后续的键。你要做的无非是创建毫无价值的数据。比如以下的例子：<br />Select count(*)<br />from address, state_ref<br />where<br />address.state_id = state_ref.state_id<br />and state_ref.state_code = 'TN'<br />我的做法是这样的：<br />Select count(*)<br />from address<br />where<br />and state_code = 'TN'<br />如你因为过度使用表的后续键建立这种表的关联，操作负载真得需要考虑一下了。<br />— Stocker<br />10. 别忘了外键<br />大多数数据库索引自动创建的主键字段。但别忘了索引外键字段，它们在你想查询主表中的记录<br />及其关联记录时每次都会用到。还有，不要索引memo/notes 字段而且不要索引大型文本字段<br />（许多字符），这样做会让你的索引占据大量的数据库空间。。<br />— gbrayton<br />Page 13 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br />第4 部分— 保证数据的完整性<br />1. 用约束而非商务规则强制数据完整性<br />如果你按照商务规则来处理需求，那么你应当检查商务层次/用户界面：如果商务规则以后发生变<br />化，那么只需要进行更新即可。<br />假如需求源于维护数据完整性的需要，那么在数据库层面上需要施加限制条件。<br />如果你在数据层确实采用了约束，你要保证有办法把更新不能通过约束检查的原因采用用户理解<br />的语言通知用户界面。除非你 的字段命名很冗长，否则字段名本身还不够。<br />— Lamont Adams<br />只要有可能，请采用数据库系统实现数据的完整性。这不但包括通过标准化实现的完整性而且还<br />包括数据的功能性。在写数据的时候还可以增加触发器来保证数据的正确性。不要依赖于商务层<br />保证数据完整性；它不能保证表之间（外键）的完整性所以不能强加于其他完整性规则之上。<br />— Peter Ritchie<br />2. 分布式数据系统<br />对分布式系统而言，在你决定是否在各个站点复制所有数据还是把数据保存在一个地方之前应该<br />估计一下未来5 年或者10 年的数据量。当你把数据传送到其他站点的时候，最好在数据库字段<br />中设置一些标记。在目的站点收到你的数据之后更新你的标记。为了进行这种数据传输，请写下<br />你自己的批处理或者调度程序以特定时间间隔运行而不要让用户在每天的工作后传输数据。本地<br />拷贝你的维护数据，比如计算常数和利息率等，设置版本号保证数据在每个站点都完全一致。<br />— Suhair TechRepublic<br />3. 强制指示完整性<br />没有好办法能在有害数据进入数据库之后消除它，所以你应该在它进入数据库之前将其剔除。激<br />活数据库系统的指示完整性特性。这样可以保持数据的清洁而能迫使开发人员投入更多的时间处<br />理错误条件。<br />— kol<br />4. 关系<br />如果两个实体之间存在多对一关系，而且还有可能转化为多对多关系，那么你最好一开始就设置<br />成多对多关系。从现有的多对一关系转变为多对多关系比一开始就是多对多关系要难得多。<br />— CS Data Architect<br />5. 采用视图<br />为了在你的数据库和你的应用程序代码之间提供另一层抽象，你可以为你的应用程序建立专门的<br />视图而不必非要应用程序直接访问数据表。这样做还等于在处理数据库变更时给你提供了更多的<br />自由。<br />— Gay Howe<br />Page 14 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br />6. 给数据保有和恢复制定计划<br />考虑数据保有策略并包含在设计过程中，预先设计你的数据恢复过程。采用可以发布给用户/开发<br />人员的数据字典实现方便的数据识别同时保证对数据源文档化。编写在线更新来“更新查询”供<br />以后万一数据丢失可以重新处理更新。<br />— kol<br />7. 用存储过程让系统做重活<br />解决了许多麻烦来产生一个具有高度完整性的数据库解决方案之后，我所在的团队决定封装一些<br />关联表的功能组，提供一整套常规的存储过程来访问各组以便加快速度和简化客户程序代码的开<br />发。在此期间，我们发现3GL 编码器设置了所有可能的错误条件，比如以下所示：<br />SELECT Cnt = COUNT (*)<br />FROM [&lt;Table&gt;]<br />WHERE [&lt;primary key column&gt;] = &lt;new value&gt;<br />IF Cnt = 0<br />BEGIN<br />INSERT INTO [&lt;Table&gt;]<br />( [&lt; primary key column&gt;] )<br />VALUES ( &lt;New value&gt; )<br />END<br />ELSE<br />BEGIN<br />&lt;indicate duplication error&gt;<br />END<br />而一个非3GL 编码器是这样做的：<br />INSERT INTO [&lt;Table&gt;]<br />( [&lt; primary key column&gt;] )<br />VALUES<br />( &lt;New value&gt; )<br />IF @@ERROR = 2627 -- Literal error code for Primary Key Constraint<br />BEGIN<br />&lt;indicate duplication error&gt;<br />END<br />第2 个程序简单多了，而且事实上，利用了我们给数据库的功能。虽然我个人不喜欢使用嵌入文<br />字（2627）。但是那样可以很方便地用一点预先处理来代替。数据库不只是一个存放数据的地<br />方，它也是简化编码之地。<br />— a-smith<br />8. 使用查找<br />控制数据完整性的最佳方式就是限制用户的选择。只要有可能都应该提供给用户一个清晰的价值<br />列表供其选择。这样将减少键入代码的错误和误解同时提供数据的一致性。某些公共数据特别适<br />合查找：国家代码、状态代码等。<br />— CS Data Architect<br />Page 15 © CNET Networks Inc. 2002<br />www.zdnet.com.cn/developer<br />第5 部分— 各种小技巧<br />1. 文档、文档、文档<br />对所有的快捷方式、命名规范、限制和函数都要编制文档。<br />— nickypendragon<br />采用给表、列、触发器等加注释的数据库工具。是的，这有点费事，但从长远来看，这样做对开<br />发、支持和跟踪修改非常有用。<br />— chardove<br />取决于你使用的数据库系统，可能有一些软件会给你一些供你很快上手的文档。你可能希望先开<br />始在说，然后获得越来越多的细节。或者你可能希望周期性的预排，在输入新数据同时随着你的<br />进展对每一部分细节化。不管你选择哪种方式，总要对你的数据库文档化，或者在数据库自身的<br />内部或者单独建立文档。这样，当你过了一年多时间后再回过头来做第2 个版本，你犯错的机会<br />将大大减少。<br />— mrs_helm<br />2. 使用常用英语（或者其他任何语言）而不要使用编码<br />为什么我们经常采用编码（比如9935A 可能是墨水笔的供应代码，4XF788-Q 可能是帐目编<br />码）？理由很多。但是用户通常都用英语进行思考而不是编码。工作5 年的会计或许知道<br />4XF788-Q 是什么东西，但新来的可就不一定了。在创建下拉菜单、列表、报表时最好按照英语<br />名排序。假如你需要编码，那你可以在编码旁附上用户知道的英语。<br />— amasa<br />3. 保存常用信息<br />让一个表专门存放一般数据库信息非常有用。我常在这个表里存放数据库当前版本、最近检查/修<br />复（对Access）、关联设计文档的名称、客户等信息。这样可以实现一种简单机制跟踪数据<br />库，当客户抱怨他们的数据库没有达到希望的要求而与你联系时，这样做对非客户机/服务器环境<br />特别有用。<br />— Richard Foster<br />4. 测试、测试、反复测试<br />建立或者修订数据库之后，必须用用户新输入的数据测试数据字段。最重要的是，让用户进行测<br />试并且同用户一道保证你选择的数据类型满足商业要求。测试需要在把新数据库投入实际服务之<br />前完成。<br />— juneebug<br />5. 检查设计<br />在开发期间检查数据库设计的常用技术是通过其所支持的应用程序原型检查数据库。换句话说，<br />针对每一种最终表达数据的原型应用，保证你检查了数据模型并且查看如何取出数据。</font>
		</font>
<img src ="http://www.blogjava.net/huyi2006/aggbug/197518.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi2006/" target="_blank">allic</a> 2008-04-30 14:07 <a href="http://www.blogjava.net/huyi2006/articles/197518.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>sqlite的C开发</title><link>http://www.blogjava.net/huyi2006/articles/189156.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Thu, 27 Mar 2008 15:06:00 GMT</pubDate><guid>http://www.blogjava.net/huyi2006/articles/189156.html</guid><wfw:comment>http://www.blogjava.net/huyi2006/comments/189156.html</wfw:comment><comments>http://www.blogjava.net/huyi2006/articles/189156.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi2006/comments/commentRss/189156.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi2006/services/trackbacks/189156.html</trackback:ping><description><![CDATA[写了一个简单的C测试程序，里面调有了几个sqlite接口。然后编译。我就试试如何编译链接<br />程序目录如下<br />/home/sqlite-ix86-linux<br />[root@localhost sqlite-ix86-linux]# ls<br />bin  ctest  huyi.db  include  lib  test  test.c<br />库和头文件都不是在标准的/usr/include 和/usr/lib目录下<br />gcc -L/home/sqlite-ix86-linux/lib/ -lsqlite3 -o test test.c <br />编译通过。其实后来把头文件拷到了/usr/include 目录下了。半天没有搞对，就拷过去了。<br />运行test报<br />./test: error while loading shared libraries: libsqlite3.so.0: cannot open shared object file: No such file or directory<br /><br />再到网上一查原来是加载动态链接库的路径不对<br />export LD_LIBRARY_PATH=/home/sqlite-ix86-linux/lib<br /><br />运行成功了<br /><img src ="http://www.blogjava.net/huyi2006/aggbug/189156.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi2006/" target="_blank">allic</a> 2008-03-27 23:06 <a href="http://www.blogjava.net/huyi2006/articles/189156.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>sqlite基本操作</title><link>http://www.blogjava.net/huyi2006/articles/189116.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Thu, 27 Mar 2008 12:21:00 GMT</pubDate><guid>http://www.blogjava.net/huyi2006/articles/189116.html</guid><wfw:comment>http://www.blogjava.net/huyi2006/comments/189116.html</wfw:comment><comments>http://www.blogjava.net/huyi2006/articles/189116.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi2006/comments/commentRss/189116.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi2006/services/trackbacks/189116.html</trackback:ping><description><![CDATA[1、创建库<br />  #sqlite3 name.db<br />2、创建表<br />  &gt;create table tabelname (field1[类型] ,field2[类型] ,field3[类型].....);<br />3、修改表<br />  &gt;alter table tablename add culumn fieldN;   只适用与追加<br />4、删除表<br />  &gt;drop table tablename;<br />5、列出表格<br />  &gt; tables or show tables;<br />6、显示库结构<br />  &gt; schema tablename;<br />7、数据操作<br />   查询 select  from tablename;<br />   增加 insert into tablename values(filed|value);<br />   删除 delete from tablename ;<br />   改变 update tablename set filedN=valueN;<br />以上数据操作均可以跟where条件表达式，orderby<br />逻辑表达式有  AND OR NOT &gt; =  = + = * / ()<br /><br /><br />.还有很有用的SQL<br />Select * from Sqlite_master <br />Select datetime('now')<br />Select date('now')<br />Select time('now')<br /><br />数据类型和创建表示例<br />CREATE TABLE ex2<br />(<br />　 a VARCHAR(10),<br />　 b NVARCHAR(15),<br />　 c TEXT,<br />　 d INTEGER,<br />　 e FLOAT,<br />　 f BOOLEAN,<br />　 g CLOB,<br />　 h BLOB,<br />　 i TIMESTAMP,<br />　 j NUMERIC(10,5)<br />　 k VARYING CHARACTER (24),<br />　 l NATIONAL VARYING CHARACTER(16)<br />);<br /><br /><img src ="http://www.blogjava.net/huyi2006/aggbug/189116.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi2006/" target="_blank">allic</a> 2008-03-27 20:21 <a href="http://www.blogjava.net/huyi2006/articles/189116.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQLite数据库文件格式分析(B树的基本组织)</title><link>http://www.blogjava.net/huyi2006/articles/189050.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Thu, 27 Mar 2008 08:37:00 GMT</pubDate><guid>http://www.blogjava.net/huyi2006/articles/189050.html</guid><wfw:comment>http://www.blogjava.net/huyi2006/comments/189050.html</wfw:comment><comments>http://www.blogjava.net/huyi2006/articles/189050.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi2006/comments/commentRss/189050.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi2006/services/trackbacks/189050.html</trackback:ping><description><![CDATA[
		<span id="ContentBody" style="PADDING-RIGHT: 10px; DISPLAY: block; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; PADDING-TOP: 10px">此分析称为简易版，因为后面还计划分析一个更复杂的数据库文件，以深入理解SQLite数据库B树实现的结构，从简易的开始不失为一种好的学习方法，这里的简易版本文件是指大小为2K字节，即每个B树页1K字节，共两个B树页，补充说明一下，这里的B树页就是指经典数据结构书上所讲的B树节点，在这里称为页是因为SQLite在实现B树时就是使用页page的概念来组织的。 
<div class="content imgzoom"></div><div class="content imgzoom">创建方法如下：<br />CREATE TABLE tbl1(one varchar(10),two varchar(10));<br />INSERT INTO "tbl1" VALUES('first', 'xxx');<br />INSERT INTO "tbl1" VALUES('second', 'yyy');</div><div class="content imgzoom"><br />然后退出，用UltraEdit打开这个数据库文件：<br />00000000h: 53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00 ; SQLite format 3.<br />00000010h: 04 00 01 01 00 40 20 20 00 00 00 07 00 00 00 00 ; .....@  ........<br />00000020h: 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 01 ; ................<br />00000030h: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ; ................<br />00000040h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................<br />00000050h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................<br />00000060h: 00 00 00 00 0D 00 00 00 01 03 B8 00 03 B8 00 00 ; ..........?.?.<br />00000070h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................<br />这中间部分全部都是零。省去！<br />000003a0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................<br />000003b0h: 00 00 00 00 00 00 00 00 46 01 06 17 15 15 01 71 ; ........F......q<br />000003c0h: 74 61 62 6C 65 74 62 6C 31 74 62 6C 31 02 43 52 ; tabletbl1tbl1.CR<br />000003d0h: 45 41 54 45 20 54 41 42 4C 45 20 74 62 6C 31 28 ; EATE TABLE tbl1(<br />000003e0h: 6F 6E 65 20 76 61 72 63 68 61 72 28 31 30 29 2C ; one varchar(10),<br />000003f0h: 74 77 6F 20 76 61 72 63 68 61 72 28 31 30 29 29 ; two varchar(10))<br /></div><div class="content imgzoom">     这是第一个B树页，这个B树页里存放了表sqlite_master的信息，这就是SQLite数据库的系统表了。<br />下面分析一下这些二进制的具体涵义，SQLite统一采用大端法来表示数据，不同与一般intel机器的小端法了：<br />偏移地址   大小    涵义<br /> 0          16     "SQLite format 3\000"<br />16           2     400H＝1024个字节，每个页面的字节数  <br />18           2     0101H表示版本号而已<br />20           1     每页末端的未用空间，这里为零表示数据都是从每页最后一个字节开始存放<br />21           1     最大负载分片数，类似与IP分片，一页存不下，要分片<br />22           1     最小负载分片数<br />23           1     最小叶子负载分片数<br />24           4     文件修改计数，用于实现并行访问<br />28           4     保留未用<br />32           4     第一个freelist页<br />36           4     文件中的freelist页数<br />40          60     这里未用<br />上面的这一百个字节称为数据库文件的文件头，这个文件头只有第一个B树页才有，后面的每一个B树页都没有这个结构，后面每一页结构都相同：<br />依次为：B树页头结构，B树指针结构，未用空间，B树实际数据负载。<br />这里和经典数据结构书上的B树结构有些出入，这里的目的是实际应用方便，而书上的结构目的是解释清楚B树的原理。所以有些不同：<br />一般书上讲的一个B树页的结构为：指针，数据，指针，数据，指针，数据，...，指针<br />而SQLite组织为：指针，指针，指针，...，指针，数据，数据，...数据。<br />第一个页面中从00000060h行第五个字节开始就表示B树页头结构了：<br />偏移地址   大小    涵义<br />0           1      0Dh＝1101b各位意义为1: intkey, 2: zerodata, 4: leafdata, 8: leaf<br />1           2      第一个空闲块的字节偏移量，这里为0<br />3           2      01，这个B树页存放的记录数为1个，即系统表中只存放了一条记录，因为只创建了一个表tbl1<br />5           2      负载区首地址，03B8，往下看到000003b0h行那个46就是负载区的开始了<br />7           1      分片数，这里数据少，不考虑，所以为0<br />到0000006Bh偏移处B数头结束了，接下来的就是B数指针结构了，此处只有一项，只有一个指针03B8h处。<br />从000003B8h偏移到结束都是sqlite_master表的实际数据了。当然这些数据也是有结构的。46h表示这条记录有70个字节，除去其本身46，和后面的01是索引外，整个记录刚好是70个字节，01索引后面都是payload负载数据了。<br />如法炮制，下面列出第二个B树页：<br />00000400h: 0D 00 00 00 02 03 E5 00 03 F3 03 E5 00 00 00 00 ; ......?.??...<br />00000410h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................<br />这中间部分全部为零。省去！<br />000007d0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................<br />000007e0h: 00 00 00 00 00 0C 02 03 19 13 73 65 63 6F 6E 64 ; ..........second<br />000007f0h: 79 79 79 0B 01 03 17 13 66 69 72 73 74 78 78 78 ; yyy.....firstxxx<br />由于不是第一页，所以不存在文件头的100个字节了，一开始就是B树页头结构了，这里有两个指针03F3和03E5，其它的和上面一样。整个数据库管理系统就是准确无误地对这个文件进行管理。<br />进一步的工作：只有数据多了，才能看出B树组织的好处：查找，删除，增加的快速！把这个文件变大再分析！</div></span>
<img src ="http://www.blogjava.net/huyi2006/aggbug/189050.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi2006/" target="_blank">allic</a> 2008-03-27 16:37 <a href="http://www.blogjava.net/huyi2006/articles/189050.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>sqlite-3.3.6编译安装与交叉编译</title><link>http://www.blogjava.net/huyi2006/articles/189032.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Thu, 27 Mar 2008 07:53:00 GMT</pubDate><guid>http://www.blogjava.net/huyi2006/articles/189032.html</guid><wfw:comment>http://www.blogjava.net/huyi2006/comments/189032.html</wfw:comment><comments>http://www.blogjava.net/huyi2006/articles/189032.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi2006/comments/commentRss/189032.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi2006/services/trackbacks/189032.html</trackback:ping><description><![CDATA[下文介绍的内容都是基于 Linux RedHat 9.0 平台的。<br /><br />一、PC机编译安装<br />请阅读在安装包里的 INSTALL 文件。或者使用PEAR installer with "pear install sqlite"。SQLite已经内置了，你不需要安装任何附加的软件（additional software）。<br />Windows users可以下载SQLite扩展DLL（php_sqlite.dl）。<br />这里简单介绍一下：<br />假设你得到的是源代码sqlite-3.3.6.tar.gz，这里将告诉你怎么编译它。<br />解压sqlite-3.3.6.tar.gz 到 /home目录下<br />For example:<br />    tar zxvf sqlite-3.3.6.tar.gz -C /home            <br />    cd /home<br />    mkdir sqlite-ix86-linux<br />    cd /home/sqlite-ix86-linux/<br />    ../sqlite-3.3.6/configure --prefix=/home/sqlite-ix86-linux/<br />编译并安装，然后生成帮助文档    <br />    make &amp;&amp; make install     &amp;&amp; make doc<br /><br />如果出现下列错误<br />../sqlite-3.3.6/src/tclsqlite.c: In function `DbUpdateHandler':<br />../sqlite-3.3.6/src/tclsqlite.c:333: warning: passing arg 3 of `Tcl_ListObjAppendElement' makes pointer from integer without a cast<br />../sqlite-3.3.6/src/tclsqlite.c: In function `tclSqlFunc':<br />../sqlite-3.3.6/src/tclsqlite.c:419: warning: passing arg 1 of `Tcl_NewByteArrayObj' discards qualifiers from pointer target type<br />这个都时tcl相关的错误,可以先安装ActiveTcl以解决.假如你不需要tcl支持,那么这个错误可以这样避免:<br />    cd /home/sqlite-ix86-linux/<br />    ../sqlite-3.3.6/configure --disable-tcl  --prefix=/home/sqlite-ix86-linux/<br />编译并安装，然后生成帮助文档    <br />    make &amp;&amp; make install     &amp;&amp; make doc<br />不出意外,将不会出现错误,那么<br />库文件已经生成在 /home/sqlite-ix86-linux/lib 目录下 <br />可执行文件sqlite3已经生成在 /home/sqlite-ix86-linux/bin 目录下 <br />下面创建一个新的数据库文件名叫"zieckey.db" (当然你可以使用不同的名字) 来测试数据库.<br />直接输入:  /home/sqlite-ix86-linux/bin/sqlite3 test.db<br />如果出现下面字样表明编译安装已经成功了.<br />SQLite version 3.3.6<br />Enter ".help" for instructions<br />sqlite&gt;<br /><br /><br />二、交叉编译sqlite.3.3.6.tar.gz库文件<br />    tar zxvf sqlite-3.3.6.tar.gz -C /home     (这一步前面已经有了,为了完整性,这里还是写出来)<br />    mkdir /home/sqlite-arm-linux<br /><br />设置交叉编译环境<br />    export PATH=/usr/local/arm-linux/bin:$PATH<br />    <br />    cd /home/sqlite-arm-linux/<br />    ../sqlite-3.3.6/configure  --disable-tcl --prefix=/home/sqlite-arm-linux/ --host=arm-linux<br />    这步出现错误而没有生成Makefile<br />    configure: error: unable to find a compiler for building build tools<br />    <br />    前面检查arm-linux-gcc都通过了，怎么还说没有找到编译器呢？花了点时间看configure的脚本，太复杂了，又结合 configure.ac看了一下。原来是要设置config_TARGET_CC和config_BUILD_CC两个环境变量。 config_TARGET_CC是交叉编译器，config_BUILD_CC是主机编译器。重来：<br /><br />    export config_BUILD_CC=gcc<br />    export config_TARGET_CC=arm-linux-gcc<br />    ../sqlite-3.3.6/configure  --disable-tcl --prefix=/home/sqlite-arm-linux/ --host=arm-linux<br />又出现如下错误<br />    checking for /usr/include/readline.h... configure: error: cannot check for file existence when cross compiling<br />说readline.h的错,找到readline.h在/usr/include/readline/readline.h目录,我想这样解决<br />    ln -s /usr/include/readline/readline.h /usr/include/readline.h<br />但还是不行<br />    ../sqlite-3.3.6/configure  --disable-tcl --prefix=/home/sqlite-arm-linux/ --host=arm-linux<br />还是出现如下同样的错误<br />    checking for /usr/include/readline.h... configure: error: cannot check for file existence when cross compiling<br />    <br />上面说是要检查交叉编译环境，我可以肯定我的交叉编译环境是正确的，<br />所以我决定欺骗configure，我时这样做的<br />    cd /home/sqlite-3.3.6<br />将该目录下的 configure 文件的部分内容修改下(这里是根据   test "$cross_compiling" = yes &amp;&amp;  找到的 ),<br />这样可以让configure不去检查你的交叉编译环境。<br />  20420行 { (exit 1); exit 1; }; }改为 { (echo 1); echo 1; }; }<br />  20446行 { (exit 1); exit 1; }; }改为 { (echo 1); echo 1; }; }<br /> 在回去重新配置下：<br />      cd /home/sqlite-arm-linux/<br />    ../sqlite-3.3.6/configure  --disable-tcl --prefix=/home/sqlite-arm-linux/ --host=arm-linux<br />中间打印信息出现如下错误信息,<br />checking for /usr/include/readline.h... configure: error: cannot check for file existence when cross compiling<br />但是还是生成了Makefile文件一个libtool脚本，这些将在make时用到.    <br />注意:<br />如果Makefile文件中有如下语句<br />BCC = arm-linux-gcc -g -O2 <br />请将其改掉，改成：<br />BCC = gcc -g -O2     <br />    <br />编译并安装<br />    make &amp;&amp; make install     <br />这里如果不出意外,将不会出现错误,那么<br />库文件已经生成在 /home/sqlite-ix86-linux/lib 目录下    <img src ="http://www.blogjava.net/huyi2006/aggbug/189032.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi2006/" target="_blank">allic</a> 2008-03-27 15:53 <a href="http://www.blogjava.net/huyi2006/articles/189032.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>