分类 编程相关 下的文章

去年搞LAMP时,想过一个问题:关于数据库中数据ID选择UUID(或者类似UUID的GUID等),还是自增型(整数类型)?其实搞毕业设计时就想过了,但是那时受实习公司的影响,采用了UUID而放弃自增型。后来发现其实采用自增型ID也有其好处。

UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。UUID按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。其主要由以下几部分的组合:当前日期和时间(UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同),时钟序列和全局唯一的IEEE机器识别号(如果有网卡,从网卡获得其MAC码,没有网卡以其他方式获得)。UUID的唯一缺陷在于生成的结果串会比较长。关于UUID这个标准使用最普遍的是微软的GUID(Globals Unique Identifiers)。(摘自本人毕业设计,其它参考:维基百科《UUID做主键,好还是不好?这是个问题。》

自增型ID(Autoincrement ID),从字面可以理解,自动增加的整数。

两者比较,UUID的优点是方便数据迁移、数据库集群等,缺点是占的空间比自增型ID大很多,查询效率可能比较低。自增型ID的优点是查询快、方便排序,缺点明显是不能保证数据库间ID的唯一性。

空间的问题,正如我同事经常说的,现在硬盘不值钱,存储空间不用考虑。相信银行的系统也不会随便仅仅挂个500GB的硬盘上去。

性能的问题,网上有人说拿200万条数据做测试对比,发现UUID的查询效率落后于自增型ID一个数量级。虽然随着CPU的发展,计算机的性能不能提升,但是对于大型数据库系统来说,效率很重要!没做过对比,我也不好说。

唯一性的问题,如果用自增型ID,做数据迁移或数据库集群时,就会带来灾难性的问题!有人说可以通过修改ID来解决,但数据关联都用到ID,ID一修改,关联就没了。如果约定自增型ID在不同数据库中的范围不同,是可以在一定程度上解决问题的,但数据一旦超出预计范围,那还是没解决问题。UUID就灵活多了,但网上有人说居然发现有UUID重复的情况,难以置信!

感觉对于我们开发的中小系统来说,还是UUID比较适合,毕竟数据量还不算庞大。

昨天看到消息说,Oracle终于通过欧盟的审查,同意其收购SUN。至此,2009年最大最受关注的并购落下帷幕,SUN也结束了27年的创业历程。

Java之父也在其Bolg上发悼文:
So long, old friend...
http://blogs.sun.com/jag/entry/so_long_old_friend

[caption id="" align="alignnone" width="294" caption="So long, old friend..."]So long, old friend...[/caption]

除了Java的未来,还有一个让人担心的问题是,MySQL的前途。

PS. 翻查了资料,当年(大概是2004吧),SUN推出过Java桌面系统,据说系统需要20分钟以上(不是普通人能接受 囧!)。该系统就是Linux上“铺”个Java虚拟机,这想法被Google用来成就了Android。

今晚有个无知少女(不排除是人妖)在群里嚷着要谁给她个Ajax实现长连接的例子。对那女的没什么兴趣,但是她提的问题引起我的注意。

网上找到比较经典的文章:
Comet:基于 HTTP 长连接的“服务器推”技术
http://www.ibm.com/developerworks/cn/web/wa-lo-comet/

问了一下胖子,他说HTTP长连接的话,常用的是内嵌Flash作为客户端,而Ajax只能实现长轮询。

终于决心装个64位的Linux了。

首先由于光驱坏了(狂呼BenQ是垃圾!),所以装系统也要走点弯路——直接通过硬盘上的ISO文件来安装。由于Linux不认NTFS,而Fat32又不支持大于4GB的文件,所以只好再切个Ext3分区来放这个ISO文件。然后利用强大的Grub来启动安装程序。具体是:

1)从硬盘切割个Ext3分区出来,大约5GB就可以了。例如是第一个硬盘的扩展分区的第二个分区,即hd0,6。

2)把安装系统的ISO文件复制到刚切出来的分区下。

3)再把ISO文件里的isolinux文件夹下的initrd.img和vmlinuz文件解压出来,也放到刚切出来的分区下。

4)找个Grub装一下,或者什么“深山红叶”启动盘也有。

5)重启电脑,进入Grub,并按e进入编辑模式,输入以下命令,然后按b启动:(注意空格,这三行都有)
grub>root (hd0,6)
grub>kernel /vmlinuz
grub>initrd /initrd.img

6)然后熟悉的安装界面便出来了。

非常麻烦的方法,但是装系统时,速度飞快。装完系统后最郁闷的是要装一大堆软件。下次还是选择升级系统比较省事。

今天午休上网,偶然发现Richard Stallman在上星期六来珠海演讲的新闻。顿时惊呆了,反应过来时一股无奈的气流贯穿全身。这么难得的机会居然跟我擦身而过,成为本年度最大遗憾!

认识他,是看《OS Revolution(操作系统革命)》的其中一个收获。那时才知道,早在80年代,“开源运动”就由他发起。只是对freedom的不断追求,为了帮助人们更自由地使用自己的电脑,于是发起了GNU计划,提出GPL v1和v2,为电脑软件的发展作出巨大的贡献,很让我感动。

很想成为这样的人!即使路途遥远,但他的吸引力实在太大了。所以,今天觉得极其遗憾。

台风“巨爵”离去后,今晚又恢复如常的看书计划。《高质量程序设计艺术》来到第6章了,本章主要探讨程序的可移植性问题。

可移植性主要面对的几个难题是:操作系统、处理器体系结构、编译器与语言特性、图形界面环境、区域(如:显示多语言)、硬件设备与平台等方面的差异。提高程序的可移植性,主要就是解决以上几个难题。

解决可移植性的常用方法是使用一个代码层来对功能进行抽象,这实际上将差异性用一部分代码隔离了。例如:JavaScript的话,可以编写通用方法来获取屏幕大小,而该方法是通过判断不同浏览来调用不同的方法来实现。又例如:C/C++可以使用预处理。

 本章用了较大的篇幅探讨了图形界面的问题。值得注意的有以下几点:

1)字符编码应该采用更通用、兼容性更高的UTF-8,而不是特定于某个区域的编码。虽然GB1080已经提高了其兼容性,但面向国际的话,还是很勉强。

2)程序/软件中的消息,应该与代码分离,作为独立的、容易替换的资源来处理,以简化其本地化的工作。

3)可移植GUI(图形用户界面)除了可以考虑建立可移植层(如建立统一的API,分别在Windows和X上封装实现该API,程序便可该API)、采用仿真层(好象就是WINE的做法)、基于可移植层的平台(如Java的Swing、SWT等)以外,还可以考虑使用HTTP/HTML或AJAX层来提供用户界面。

首先,今天是个很特别的日子,因为很多情侣特意选择今天结婚(09年09月09日,有长长久久之意)。

废话说完。《高质量程序设计艺术》终于完成第5章了。第4章时间性能和第5章空间性能,其实可以合起来,就是程序优化的问题。首先,程序的时间性能跟空间性能,可以说是矛盾的,因为很多时候都是空间换时间,或者时间换空间。其次,程序优化,就有可能导致可移植性降低。所以,很多专家都认为,程序优化的首要准则是:不要优化(出自Michael A. Jackson)。当然,前提是该程序已经一个良好的程序(不懂怎么表达,反正就是好程序最好不要优化)。

优化的另一个指导思想是帕雷托法则(Pareto Principle)。本来是用在经济学问上的,而用在程序执行上表明,20%的代码通常占用了80%的执行时间。那么,只要找出这20%的代码,就可以对程序进行优化了。

优化的方法嘛,不外乎那几种:空间换时间、减少I/O操作、降低算法复杂度等等。

对于空间性能方面,由于涉及到硬件方面,所以主要是C/C++方面的问题。对于Java程序员来说,底层硬件都是不可见的,所以研究的意义不大。有个问题值得注意的,代码的长度,准确来说是编译后的文件(目标文件)大小,有时候跟执行效率有关。目标文件越小,占用内存空间就越小。

还有一个收获,认识了“内存对齐”。例如:在32位计算机中,一个char变量(占1个字节,即1 byte,也就是8位,8 bit)和一个long变量(占4个字节,即4 byte,也就是32位,32 bit)储存在一起。如果不进行内存对齐,要读取该long变量时,就要读取两个32位字的内容,再进行复杂的操作。但如果对齐后,读取该long变量就只要读取一个32位字的内容,没有复杂的操作,但这样就意味char变量后面紧跟着3个字节来实现对齐,就是有3个字节的内存空间浪费了。这是明显的空间换时间。同时这就知道了为什么内存容量总是32的倍数(因为32位的计算机每次处理32位数据或指令)。我估计下一代的计算机是64位(32的两倍),而不是40位、48位之类,是为了向下兼容。

PS. 可能近来睡眠不足,导致看书时精力不足(总是打瞌睡)。

睡觉前总结一下今天看书的收获。

《高质量程序设计艺术(Code Quality: The Open Source Perspective)》已经看到第3章了。本章的内容仍然很精彩!

正如书中所说,软件安全性是一个复杂又独特的难题。

1、缓冲区溢出,一个恒久的入侵课题。以前看很多黑客文章(应该是黑客故事),一开场就说溢出,但就是不知道接着做什么。书中介绍的例子是首先使得程序溢出,使得程序的指针指向要执行的恶意代码所在的内存地址,然后恶意代码便可以执行了。虽然不太懂具体的做法,但是只要想到指针能被替换,就已经很唬人了。

PS. 就算是Java/.NET,声称对缓冲区溢出漏洞是免疫的(因为它们提供了数组边界检查机制),但使用对象数组实现的环形缓冲区也有可能出现缓冲区溢出。

2、文件替换。有些软件是在root权限下运行的,并且带有更改文件权限或删除文件操作。如果把这些软件运行时所操作的文件指向一些重要的系统文件,那后果是非常严重的。

3、不可信输入。这个最简单最有名的例子是SQL注入。很多时候,特别是登陆系统时,输入的用户名都没有过滤特殊字符,或者只是在页面上用JavaScript来过滤,到了服务器就直接组装成SQL语句来查询。这时候,如果用户名后加个“;”(分号),再加个恶意的SQL语句,本来一个语句就会当作两个语句来执行(一般的数据库系统都可以识别分号为一个SQL语句的结束符),后果就不说了。

4、木马。又是恒久的主题。书中提及的不是怎么上传木马程序并运行,而是说某些开源软件的代码如果在服务器上被修改过,那用户下载来编译运行后会带来灾难。即使绝大部分的开源代码都会提供验证码(如MD5、PGP签名等)来检验是否被修改过,但绝大部分的用户都不会去检验一下。

看完本章后,突然想起以前想买的那本《入侵的艺术》,于是去“卓越”看看(http://www.amazon.cn/mn/detailApp/ref=sr_1_1?_encoding=UTF8&s=books&qid=1252254843&asin=B0011CU4RU&sr=8-1)。看过试读后,感觉这本说在写小说似的,剧情很跟《越狱(第四季)》有点像。其实最难防的是,那人直接到你机房去。

对了,还有两个细微的地方要记一下:

1)Windows 的某文件夹下,有两个可执行文件aa.com和aa.exe。如果在命令状态执行aa,那默认会先找到aa.com并执行,而找不到aa.com才会找aa.exe来执行。

2)Windows有个环境变量叫“ComSpec”,用来设置命令行解释器。

时间很快来到9月。回顾8月,唉,太浪费时间了。整个8月都不知道忙了啥,就连工作也是超无聊(每星期都有好几天没具体工作任务)。于是,希望9月来个突破!

今晚赶紧吃完饭后,独自到中大自习。本来想看《系统架构设计师教程》(想到11月去考一下),但精神不佳,于是拿出《高质量程序设计艺术(Code Quality: The Open Source Perspective)》来看。

首先第1章翻了几翻便过去了。到了第2章看到几个挺好的话题:

1)一个8位的硬件计数器是否能用来对一个256字节缓冲区的成员进行计数?
    该问题有点不明白,“硬件计数器”是什么?“一个256字节缓冲区的成员”又是什么?我觉得该提问者想说,8位的处理能力最大是255字节。纯猜测,跳过……

2)多路处理的问题
    处理多个分支的代码(如switch语句)时,作者提出以下几个处理方法:
(1)在每个分支或步骤添加注释,即具体说明;
(2)代码与复合数据成员(结构体与类)之间的关系;
(3)switch中,case的值要覆盖所有可能的情况,或者用defualt来处理可能遗漏的情况;
(4)或者根本不用多路处理,把数据与代码直接联系在一起,可以通过为原本是一个case成员的处理创建一个子类,或者是将各个实现特定接口的函数与每个数据成员相关联来实现。

3)软件发布版中的隐藏功能
    由于软件发布版中的隐藏功能,如调试功能,会带来潜在的危险与额外的资源消耗,所以应该避免。著名的反面教材是“莫里斯蠕虫”病毒,利用Unix的邮件传送代理sendmail中的调试代码,来执行命令,达到自我复制、传播的目的。

4)溢出的问题
    一个简单的表达式子:
int a = b * 100 / 255;
    当b接近int的最大值时就可能溢出,但改为这样就可以避免问题发生:
int a = b  / 255 * 100;

 经过两天的研究,终于成功用G1发彩信了。在这激动人心的时刻,首先对中国移动(特别是广东分公司)送上伟大的神兽——草泥马,以表示此刻的心情。

我的sim卡是属于广东移动的神州行畅听卡,根据androidin论坛里的教程设置APN后可以接收彩信,但发送总不成功。昨天收到一条短信,说我“使用GPRS产生CMNET流量77K,超出GPRS套餐内容,收取流量费用1.00元”。后来查了广东移动的网站(https://www.gd.chinamobile.com/easyown/operation/internet/02,52.shtml)才知道,广东移动的新GPRS套餐是CMWAP可以包月,但CMNET不能包月,且收费为1元/MB。恐怖~~于是马上把CMNET删了。

最后领悟出APN的设置,需要建立以下两个APN:

---------第一个---------
名称:cmwap
APN:cmwap
代理:10.0.0.172
端口:80
用户名:<未设置>
密码:<未设置>
服务器:<未设置>
MMSC:<未设置>
彩信代理:<未设置>
彩信端口:<未设置>
MCC:460
MNC:02
APN类型:default

---------第二个---------
名称:cmwap mms
APN:cmwap
代理:10.0.0.172
端口:80
用户名:<未设置>
密码:<未设置>
服务器:<未设置>
MMSC:http://mmsc.monternet.com
彩信代理:010.000.000.172
彩信端口:80
MCC:460
MNC:02
APN类型:mms

其中“名称”随便填,而“MNC”有的说移动的是00(零零),其实默认就可以了,我的“MNC”默认是02(零二)。以上配置没有配CMNET,所以不能上Internet。也因为广东移动的CMNET收费很变态,所以没有配CMNET。

总结一下实验结果吧。首先,虽然这个设置是没错,但是彩信发送的发送不能百分百成功。原因可能跟网络及彩信大小有关。彩信大小为1K,成功率较高,但白天在公司,彩信一条都发不出去。晚上发的话,成功率很高,发了几条,别人都能收到,我也给自己发了个照片,40K左右,发送和接收都很顺利。

PS. 人家玩G1都上3G(外国的),而我还在研究2.5G的使用……正如应老板说的:“脑残,就玩别人不玩的东西”。