关于javascript和css的宿主环境以及资源引用相对路径等问题实践总结!

1.javascript引用资源(比如图片)相对路径是以宿主环境(所被引用的网页比如user.html)所处位置为基准

2.css引用资源(比如图片)相对路径是以.css文件所处位置为基准!

已经实践证明过!

--2009aicheaizi
------images
---------index_02.jpg
------test.htm

--css
------css
----------test.css

--js
------js
----------test.js

引用代码如下:
test.css

#imgtest 
{ 
background-image:url(。。/。。/2009aicheaizi/images/index_02.jpg);//.换成。以防cnblogs转换 
width:500px; 
height:50px; 
border:solid 1px red; 
}

test.js

function writeimg() 
{ 
  document.write("<img src='images/index_02.jpg' />"); 
}

test.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" > 
<head> 
    <title>无标题页</title> 
<script type="text/javascript" src="../js/js/test.js"></script> 
  <link href="../css/css/test.css" rel="stylesheet" type="text/css" /> 
</head> 
<body> 
<script type="text/javascript"> 
writeimg(); 
</script> 
<div id="imgtest"></div> 
</body> 
</html>

实践是检验真理的唯一途径.

 

另外//d1.abc.com/test.js 这种用法没试过吧,这也是绝对路径,但是没有写前面的http协议头,这样写有什么好处呢,对于需要引用外部脚本的站点来说,如果是https请求,那么上面的地址会请求https://d1.abc.com/test.js  如果是http请求,上面地址则会请求http://d1.abc.com/test.js 这样就避免了跨域安全问题,参见:http://kazge.com/archives/402.html

Continue reading 关于javascript和css的宿主环境以及资源引用相对路径等问题实践总结!

flex缺点与比较

flex漫谈

若干年前,我还在CitiBank工作的时候,全球包括国内IT界就有很多WEB开发者热论Rich Internet思想,众多IT媒体纷纷把RIA当作一个时髦的词汇挂在嘴边,时不时地品评一番。而各网络技术供应商也在暗地里思考着是不是新的机会到来了。当时正是全球java企业级技术开发高速发展的时期,OpenSource运动也在如火如荼的进行着。有一天,头召集我们说Macromedia(当时还没有被Adobe兼并)已经实现了一个实验版本的解决方案,名字叫Flex,让我们关注一下云云,因为下一个项目要用到它。于是从那时起便开始了 Flex之旅了。我想我们是Macromedia Flex最早的客户。Flex1.5精彩的UI组件给我留下了深深的印象. 一直到现在都密切的关注着它的发展,用它实现过很多让很多人激动人心的功能,同时也经历着由于Flex先天的不足所带来的困惑,以及每个困惑后面的解决方案。从第一个Beta版本的脆弱到现在2.0的进步,我能明显地感觉到它在成长和发展。我个人也在成长和发展。想以一个过来人的视角告诉国内这些被 Flex地魅力所打动地人们一些经验和教训。以及怎么发挥Flex最强悍的地方,巧妙地避开它相对不稳定和脆弱的地方。只要注意足够的细节,我的实践和经验告诉我,Flex总能让人激动人心!

现在,我想首先随便举例介绍一些Flex的短处。从最早的版本1.5开始。

1 不支持鼠标双击事件(解决方案是用两次时间间隔100毫秒的单击事件来模拟),2.0有所改观。

2 Flex的FlashSession和IE的标准HttpSession在Tomcat,WebLogic上部署时没有问题,但是在Unix的JRUN上时,Post请求参数不同步(解决方案是在Remote Object实现中手动同步必要的参数,比如如果你把Spring中的Facade Object作为Remote Object)2.0有同样的问题。在WebService作为Server端的通信方式时没有类似问题。

3  前期绑定和官方声称的不一致。组件绑定在Flex中分为前期绑定和后期绑定。当Client端装载编译过的mxml或as码流时首先出发的事件是 Initialize然后是CreationComplete,当我们分别写两个handler相应这两个事件,如果后期绑定可能用到前期绑定时装载的数据,你就会发现数据有可能会没有转载。原因有若干,在下一篇文章中详细介绍。

4 FlashPlayer 9以前的实现,类层次结构太深,实现很机械死板,存在很多重构的可能,比如一个应用中包括若干容器和组件,每个组件的初始化都要调flash类根结点相同的构造器。你配置好Flex自带的Profiler,就可以在Console中看到整个应用在底层的对象创建初始化的所有过程。只要在flex- config.xml中打开开关然后再做些额外的配置就可以了。(解决方案是写一个底层flash类Singleton的类工厂cache所有底层 flash类,此方案非常见效,flex并不是想象中的那么慢!)

5 本身没有好的pattern可以直接利用,容易造成mxml和as混在一起,可以选择cairngorm,这个不错。我将单独写一篇关于CAIRNGORM架构的文章。不过2.0时已经被集成进来。

6 CellRender存在数据类型DataType不匹配的Bug等等。

以上说了这些,有些朋友可能有些失望,其实大可不必。我们要保持一种客观的态度,等我把Flex的优点列出来以后,你又会充满信心了,其实,任何产品都有优势和劣势。另外,以上我所列的东西都是我在实际的开发中碰到的,到后来你会发现,等你做完项目必须的优化动作后,反而是数据传输所消耗的时间比 Flex组件初始化的时间要长一些,那时可以采用在Server端做个Cache以及Client端Lazy Load的策略。想一下Flex都可以做全球各大股票市场行情实时显示和分析,还有什么它不可以做的呢!
==============================================================================================================

支持的:
在Action Script的历代版本中, 没有任何一个UI是支持HTML所有的标签的, 它们只支持HTML一部分的标签.
TextArea这个UI也是一样的, 只支持HTML里少数标签, 比如加粗(<B>内容</B>), 或者斜体等等这些基本标签.
表格标签<table>是不被支持的, 要用表格的话, 我建议你用DataGrid组件, Flex 2里的DG比Flash 8的漂亮很多, bug很少.
不是。java is a programing language!
Flex技术是Micromedia推出的,此公司相续推出了两个版本Flex1.0和Flex1.5,但是由于他们所设计的IDE和生成的flash文件太过于臃肿,所以一直声誉不隆。
2005年,Micromedia被Adobe公司收购,Flex2.0和Flex3.0相继推出,Adobe改良了FlexBuilder和SDk,使得开发Flex变得简单,而且生成的.swf文件变的更小。于是这门技术才开始在国外盛行起来。
总的来说,flex是大势所趋,flex+java的J2EE开发在此后一段时间将是主角
oracle是主流数据库, ajax,既然有了flex,ajax可以不用学了
flex资料确实少,但flex3的中文书还是有几本的,况且现在flex4快要出了,赶紧学习吧。
另外,于Flex竞争的还有微软的SilverLight.最新消息,Sun公司也推出了javaFX,其实都是RIA。
不过由于Flex率先占领了市场,所以支援Flex的开源的东西也相对多很多,所以此后一段时间当主推Flex。

票数: 0

sdihei 2009-3-13 下午12:52:24 218.93.127.* 举报

取这个标题,难免会惹来幼稚和可笑之闲,打心底压根儿没有拿这两者来比过,因为这两者是否具有可比性本身是个疑问.可是最近一些朋友的公司却一直在UI的技术选型上犯愁.一些朋友这么问我,所以我想把自己的想法罗列在此,仅供参考.
先申明,我不是什么牛人,也不是FLEX和EXT方面的高手,甚至对EXT并没有在项目中亲自实践过,写此文之前我问自己,凭什么在此发言? 最后我找到一个说服自己的欠充分的理由.既然有人发问,就应该个答案,既然我不能更清楚地说出答案,何不以此做为源头,让更多的人来揭开这层面纱,此文难免落入俗套,请大家海涵.
不啰嗦了,进入主题吧.
FLEX和EXT该选谁?
一:从项目的风险上来考虑:
项目能否成功, 一定程度上并不关技术鸟事儿.因为不同的技术可能达到同样的效果.而我们往往只选取最有把握的一种技术,这就是让项目归避了风险,那么这两者中哪一种技术你更有把握呢? 大家自己更清楚,我可以大概地分析下两者目前使用现状来做个推测或猜测.不排除有例外.
FLEX在国内已明显比国外慢了半拍,从 FLEX的相关学习资料可以得出这一结论,记得从FLEX2开始我重新开始了对FLEX(以前玩过FLASH)的关注,那时我还在神龙汽车公司里做实施项目用的是SSH架构.项目中有很多有关经销商的数据需要统计和比较,客户非常希望能够直接在系统中看到各经销商特定数据项比较的结果,当时苦于没能说服经理采用FLEX的CHART来实现这一功能,而采用了BO报表这个庞大的系统来”高射炮打蚊子”,当时提出FLEX技术项目组的同志们闻所未闻,我简单地说是FLASH的一种技术,大家听罢都敬而远之.说FLASH依赖于FP.后来学习FLEX变成了我的业余爱好.当然现在在国内大概不会再出现类似的情况了,FLEX以及微软的SL大有山雨欲来风满楼的架势.CSDN的孟岩说”RIA是趋势”,我想倒底是不是趋势大家能感受得到.在这里我想表明一点,是 EXT已经被众多企业以及用户所接受,但FLEX还在考验和推广的路途之中.回到风险的考虑上来讲,你的团队中真正懂FLEX的人不多,或者根本就没有. 因为大家都没有FLEX方面的经验积累,你贸然采用FLEX,一旦在你的项目中遇到FLEX本身或者你的团队不能解决的难题,而又很难在寻求外界的技术支援时,你的项目势必为摇摇欲坠.这种惊心动魄我想大家都不想感受.而EXT听起来虽然是个新名词,但如XX人所说,AJAX只是一个新瓶装老酒的DD,我们几乎不需要额外的学习就可以完美的实现”拿来主义”,我们还可以根据自己的需求来修改内部的代码.所以就目前来讲,EXT的技术风险远低于FLEX.
二:学习和培训的成本:
要上一个项目,你的团队没有FLEX的经验也没有EXT的经验积累.别无它法,一:让团队成员自学交流,二:给团队成员培训一下.而不管是学习还是培训,EXT会更快地让大家所接受,所以EXT的学习培训成本或者说成是使用成本更低.(当然这只是就当前的项目而言,从公司长远的考虑,学习FLEX这个投入可能会得到更高的回报, 这是后话).
三:企业运营的成本:
BS结构的 DD,SERVER是运营时的重头戏,带宽的大小,服务器的负载能力….因素,在项目开发之前技术选型时都要经过深入考究,本着”问题都要在项目开始之先暴露的原则”,我们不能视FLEX项目的更高的带宽要求而不见;FLEX在第一次将整个项目SWF下载到客户端缓存,所以项目大载入会非常慢,鉴于国内的带宽状况似乎还很不乐观,这一点是几乎是FLEX技术选择时最为头疼的问题,这里或许有人会反驳说,有办法解决:我想很严肃地回驳,没办法解决,运用 RSL以及MODULE只能缓解这种尴尬;
针对这一尴尬.ADOBE官方有这么一说,FLEX是为企业级用户准备的,当然你做的是企业级方案,那这一尴尬确实可以不再让其蒙羞;所以FLEX在外网的解决方案的使用上似乎要更加慎重考虑
再回到话题上来,FLEX与EXT相比所需的带宽要求要高得多,最终用户的网络带宽不理想,你用FLEX做再华丽的,再炫,再牛的用户体验,他也体会不到. 当系统的并发数急剧增加时,企业的服务器要相应地提高对用户的响应速度,也需要加大带宽,运用木桶原理,可能需要增加的带宽不小(本人没有数据来说明,因为没有做过测试),支付的费用也会成若干倍增加.
四:开发效率和维护成本
看到上面,好像我更倾向于采用EXT,似乎我把FLEX说得一无是处,不然,FLEX也是时代的英雄,只是他的演出才刚拉开帷幕,从开发效率上来讲EXT根本没法跟FLEX相提并论,

Continue reading flex缺点与比较

Blaze Data Services还是LiveCycle Data Services?

http://www.infoq.com/cn/articles/Blaze-LiveCycle

Blaze Data Services还是LiveCycle Data Services?

作者 Ryan Knight 译者 张龙 发布于 2009年5月5日 下午10时11分

社区 Java 主题 开放源代码, Web 2.0, 数据访问, RIA, 富客户端/桌面 标签 Adobe, Flex, Adobe集成运行时/AIR, Flash

摘要

现在已经有不少文章在谈论各种版本的Data Services,然而却没人能说清楚该如何从这些Data Services中进行选择,同时也没人对端点(end point)和管道(channel)是如何影响着应用性能这个议题进行过详细论述。

尽管Adobe提到4个不同版本的Data Services,但实际上只有2个主要版本。一个是开源的Blaze Data Services,另一个是名为LiveCycle Data Services(LCDS)的私有版本。这两个产品都提供了一个重要特性:借助于Message Broker Servlet连接Flex和Java。他们都可以通过二进制协议,ActionScript消息格式(AMF)使用远程过程调用和消息与服务器端进行通信。此外,Adobe还在这两个核心产品之上提供了支持版本和更具扩展性的产品套件。

从我在Gorilla Logic的工作经历来看,我认为这两个产品之间的主要差异在于支持项与数据管理,而性能和可伸缩性之间的差异则颇具争议。LCDS为客户端通信提供了额外的端点和管道。Adobe宣称这么做的主要好处在于提升了可伸缩性,然而基本的通信方式依然是通过HTTP上的AMF,这样不管服务器端或客户端的配置如何,其性能没什么差别。

LCDS提供的另一个特性是数据管理,它通过实时的冲突调节(conflict resolution)实现Flex客户端和Java服务器端之间的数据同步,同时还提供了数据装配器和适配器以通过JDBC、Hibernate或其他客户化的适配器连接Data Services和持久化存储。

那么这4个不同版本都是什么呢?

  1. Blaze Data Services——免费、开源的版本
  2. LiveCycle Data Services社区版——Blaze DS的一个支持版
  3. LiveCycle Data Service单CPU协议版——商业版的一个免费版本,具有一些额外特性,但只能用在单个CPU上
  4. LiveCycle Data Services——带有支持的商业版的付费版本

同时还有一个Adobe称之为LiveCycle Data Services Enterprise Suite的产品套件。它向核心的Data Services中添加了额外的产品以通过PDF Generation、Forms及Digital Signatures等工具提供内容服务和文档输出功能。

理论上来说,我们可以根据以下三点来选择产品。

  1. 需要支持么?这取决于应用是否需要支持,比如任务关键的应用。
  2. 需要数据管理服务么?这取决于应用对数据同步和管理服务的需求。
  3. 需要额外的LCDS端点和管道么?根据Adobe所述,如果同时有几百个并发连接,那么就需要了,然而这么说还是颇具争议的。服务器能处理的并发连接数取决于多种因素,比如线程和I/O吞吐量等,同时我们还可以通过多个服务器的负载平衡来处理大量的并发连接,就像Java应用服务器那样。

在本文的最后有一张比较图表概览了这4个不同版本。

概览不同的端点——Servlet和NIO

在Data Services中,端点就是服务器监听来自客户端连接的方式。对于Blaze DS和LCDS来说,标准的端点基于Servlet,运行在应用服务器上。端点通过Message Broker Servlet(配置在web.xml中)加入到标准的Servlet过滤器链中,这样我们就可以将Blaze DS和LCDS部署到现有的Java应用中。与Java Servlet端点类似,每个客户端连接都需要服务器上一个单独的线程。

与上面相比,NIO端点的工作方式就完全不同了。NIO表示Java新的输入/输出。NIO端点会创建一个独立的基于NIO的Socket Server。其优势在于单个线程能管理多个I/O流,这样就无需很多线程,同时能处理更多的客户端。

要想使用NIO,我们面临着如下几个挑战:

  • 客户端无法通过客户端代理访问NIO端点。
  • 连接无法通过标准的Servlet链,因为这会打断依赖于Servlet的任何一部分系统。比如我们在项目中使用Servlet处理文件上传。
  • 要想使用NIO,我们必须利用客户化的认证,因为Socket Server运行在与Servlet容器不同的进程中。

尽管我们可以通过配置的方式让NIO服务器监听80端口,但通常它却驻留在其它端口上。这样就给网络配置带来了挑战,我们必须将网络配置成可以接收新端口上的连接。根据服务器内部网络和各种客户端的不同,这可能会产生问题。不过这个问题还是有可能解决的:使用带有sticky sessions的负载平衡器。

然而Java NIO的这些优势却是颇具争议的。开发Java NIO的目的在于让单个线程处理多个连接,这是通过令单个线程遍历连接池以检查是否需要读取或写入新的数据来实现的。但由于NIO是在2002年引入的,那时的JDK版本还是1.4,而现在JVM和Linux中的线程已经得到了极大的改进,因此Java和Linux处理大量线程的能力也已经得到了巨大的提升。

举个例子吧,Linux Kernel 2.6引入了一个新的线程库,也就是本地的POSIX Linux线程库(NPTL)。测试表明,借助于NPTL在IA-32上只需2秒钟1就能启动100,000个线程,而如果不使用NPTL的话,Linux Kernel需要花费15分钟才能启动这么多线程。

更有意思的是Paul Tyma等人发布了一篇博文说到Java NIO实际上是个劣势2, 3, 4。凭借一系列基准,Paul得出了如下一些结论:

  • Java NIO丧失了大约20%到30%的吞吐量
  • 线程上下文切换的代价并不大
  • 同步的代价并不大

Paul 根据这些测试得出如下结论:一个连接对应一个线程完全没问题。在使用JDK 1.6的情况下,JVM可以处理15K到30K的线程数。这意味着Servlet端点已经不再局限于几百个线程了,相反,线程数可以更多,甚至15K个连接以上。当然了,实际的限制取决于硬件配置,比如内存、CPU等等。

概览不同类型的管道

我们可以在基本的网络连接之上使用多种不同类型的管道进行客户端与服务器端的通信。基本远程过程调用使用的是标准AMF管道。

另一种通信形式就是消息,这样应用就可以推送来自于服务器端的消息并进行近乎实时的通信。代表性应用就是聊天服务器、拍卖客户端及协作服务。

Data services处理消息的主要方式就是轮询(polling)。由于HTTP上的标准通信并不会一直打开通信管道,这样一个轮询管道就会让客户端请求一直等待服务器端,直到数据可用为止,其等待时间从几毫秒到几分钟不等。这么做就模拟了从服务器端推送数据的过程。

有两种基本的轮询管道:短轮询与长轮询。其主要区别在于服务器端等到客户端数据变得可用时所需时间的多少。

一种更高级的管道是流式AMF(streaming AMF)。它会打开到服务器端的HTTP连接并让服务器以流的方式在该管道上传输消息(消息的数量没有限制)。这么做就无需客户端轮询了,同时还能使用标准的网络配置。该方式最接近于实时流。流式AMF的挑战在于它使用了HTTP 1.1的持续连接,而不同的浏览器对其的实现方式却不同。

最后一种管道就是RTMP(实时消息协议)管道了,目前只有LiveCycle DS对其提供了支持。Adobe最近宣布将要发布RTMP规范,由此我猜想它最终将会得到其他产品的支持。

设计RTMP的目的是在双向管道上以流的方式处理大量多媒体和数据。RTMP的一个主要好处是可以一直打开与客户端的连接,这样就可以推送服务器端的数据了。凭借这一点,RTMP可用于Comet风格的通信和实时的数据推送。

RTMP有三种形式。一种是基于TCP并使用1935端口,其底层实现要求在客户端浏览器上初始化连接。由于使用了非标准的端口,这样客户端防火墙经常会阻止其运行。

RTMP的另两种形式在HTTP请求内封装了RTMP消息,这样协议就可以穿越防火墙并使用标准的端口。这两种形式分别是RTMPT(用在标准的HTTP上)及RTMPTS(用在安全的HTTPS上)。

在 Flex中,所有对服务器的调用都是异步执行的,因此这些管道都不会对客户端性能造成任何影响。然而他们却对服务器端性能有一定的影响,尤其是在同时打开多个客户端连接的情况下更是如此。例如,流式AMF会导致服务器端打开大量并发的客户端连接,这也就意味着会产生多个线程。但如前所述,多个线程的影响微乎其微。

所有的客户端连接都可以配置默认管道和备选管道,如果默认管道失败则可以切换到备选管道上。根据服务器端处理的不同通信类型,我们可以指定不同的管道链。例如,可以指定RTMP管道,但如果该连接失败,就回到长轮询管道。

结论

相对于Blaze DS来说,LiveCycle DS的真正优势在于其支持与数据管理,而额外的端点和管道所带来的优势却是颇具争议的。根据我们在Gorilla Logic所完成的项目来看,根本无需使用NIO端点或是RTMP。但从技术角度来看,没什么是确定的。我倒是想多点项目经历。

特性比较表

table

关于作者

Ryan Knight是Gorilla Logic的高级软件架构师,他主要从事Flex和Java咨询方面的工作,同时还是Anvil Flex的主要贡献者,这是一个开源的项目,用来帮助企业上手Flex开发。他有着12年的Java开发经验,期间经历了从开发到咨询的各种角色变迁。

资源

1 http://www.linuxjournal.com/article/6530

2 http://paultyma.blogspot.com/2008/03/writing-java-multithreaded-servers.html

3 http://www.theserverside.com/discussions/thread.tss?thread_id=26700

4 http://cometdaily.com/2008/11/21/are-raining-comets-and-threads/

来自Adobe的链接

LiveCycle Homepage

LiveCycle Data Services ES FAQ

Comparison of the different LiveCycle Data Services solutions

其他资源

LiveCycle ES vs LiveCycle DS vs BlazeDS - clearing up the confusion

Why are you NOT using LiveCycle DS?

查看英文原文: Blaze Data Services or LiveCycle Data Services?

Continue reading Blaze Data Services还是LiveCycle Data Services?

Delphi 7编译的程序任何系统都正常显示

Delphi 7编译的程序任何系统都正常显示[这个没提供解决方案,可当基础知识]

字符编码的问题。
字符编码在Delphi7中已经得到了很大提高。
Delphi7自己的IDE虽然不能读取Unicode编码的源代码文件,但编译器已经支持
AnsiString和WideString的转换。也就是说,只要定义的时候定义

Technorati 标签:

WideString,
那么在后面直接给他赋值时,AnsiString自动转换为WideString,反之亦然。
这样有好处也有坏处,好处是在快速开发中,不需要考虑更多的字符转换问题,
能够比较平顺地从Win98向NT字符集转换,坏处是混淆了字符界限,深入看下
去,有时候搞不清我的内存里究竟是Ansi还是Wide,特别是希望仅仅使用宽字
符的情况下,更要留意字符格式的定义。
WideString保存为文本文件时,常用的有UTF-8、Unicode、Ansi、Unicode Big Endian,
其中 UTF-8 的格式,从文件读取的时候,需要利用 Delphi7 提供的 Utf8ToUnicode
转换一下全部编码,其他几种编码本身都不需要转换(BigEndian编码是摩托罗拉规范,是
intel 规范的 Unicode (即我们现在说的 WideString)编码的字符按字节反转,这符合摩
托罗拉生产的计算机芯片的构造特点,所以读取后要按 WORD 反转),但保存为相应格式的
文本文件时,必须按要求在文件头部写入一个编码识别记号,他们分别为:
Ansi:不需要
Unicode:$FEFF (十六进制编辑器看到的是高位在前显示$FFFE,以下同)
BigEndian:$FFFE (正好是上面 Unicode 的反转)
UTF-8:$BBEF $BF (三字节,十六进制编辑器里显示 $EFBB BF)
这样,其他编辑器读取时就可以识别出保存者把文本翻译成了什么编码。
Unicode(即WideString)只要写好文件头,后面的就按照保存Ansi文本一样把
文本写入文件,保存为Big Endian,则按WORD逐字节反转写入,保存为UTF-8
要利用UnicodeToUtf8转换后写入。
在XML解析中,如果带有非ASCII编码的文字,MS默认使用UTF-16编码,如果
原始文本是Ansi编码,这时将获得乱码的字符。这个编码不是Delphi造成的,是
MS的XML库所致,所以在使用非ASCII字符前,建议转换成UTF-8编码,上面例
子中我没有使用WideString,所以没有实现编码转换。
编码转换有很多现成的开源代码可以利用,其中影响最深远的就是JEDI的Unicoee.pas,
但这个文件很庞大,大约有250K大小,它还带有一个转换表的资源文件,如果
处理一些小型的字符转换就显得杀鸡用牛刀了。当然我们可以直接利用Delphi7
提供给我们的函数,比如:
function PUCS4Chars(const S: UCS4String): PUCS4Char;
function WideStringToUCS4String(const S: WideString): UCS4String;
function UCS4StringToWidestring(const S: UCS4String): WideString;
function UnicodeToUtf8(Dest: PChar; Source: PWideChar; MaxBytes: Integer): Integer;
function UnicodeToUtf8(Dest: PChar; MaxDestBytes: Cardinal; Source: PWideChar; SourceChars: Cardinal): Cardinal;
function Utf8ToUnicode(Dest: PWideChar; Source: PChar; MaxChars: Integer): Integer;
function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: Cardinal; Source: PChar; SourceBytes: Cardinal): Cardinal;
function Utf8Encode(const WS: WideString): UTF8String;
function Utf8Decode(const S: UTF8String): WideString;
function AnsiToUtf8(const S: string): UTF8string;
function Utf8ToAnsi(const S: UTF8string): string;
等等。这些已经足够使用了。轻量级的代码是OmniXML中的TGpTextStream,
不过这个代码有不少BUG,并且不支持BigEndian的写入(读取部分也因忘了使
用临时变量而错误)。这些都可以利用。
在Delphi7中,Edit等控件不支持WideString,但有一组TnTWare的开源控件可
以直接支持WideString。
所以,了解了这些内容后,就可以明确这么多编码在读入内存后变成了什么。
读入内存中的字符其实已经只剩下二种格式了:
要么是 AnsiString,
要么是WideString。
因此,对于认识字符编码的关键就是理解读取和理解保存,只有这二个地方需
要对编码有了解才能正确地完成工作。
哦,对了,还要补充一下Delphi中比较特殊的一个事情:本来我们全程使用了
WideString后,在NT系统下应该可以不考虑处于哪种语言环境的,但是Delphi
的全部控件都是基于Ansi的,因此,除非使用了象Tnt控件一样的显示控件,
否则都要注意字符集的定义。象Edit,如果要显示WideString,Edit的Line.Text
会自动转换为AnsiString,这个转换的依据是活动文档的键盘定义或者活动文档
的字符集定义(字符集定义优先),因此一定不要忘记把Edit字符集设置为与
文本相适应的标志,比如中文,就设置为GB2313_CHARSET,这样,转换时会
使用936的中文字符集。这个设置与具体使用的字体无关,只要强制把这个属
性设置好了,字体是否支持这个集合由系统自动转换。
因为 WideString 中最需要转换的编码就是 UTF-8,所以演示了 UTF-8 就可以应用到所有
WideString 编码。
下面的演示代码是把 UTF-8 格式的文本装入只能显示 AnsiString 的 Delphi 自带的 Memo
中,并且可以再将这个 Memo 中的 AnsiString 取出来保存为 UTF-8 格式文本,并且支持
在任何语种的 Windows NT 操作系统上显示中文。
unit frmUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, ComCtrls, Menus, StdCtrls;
type
TEncodeFlags = (efUnknown, efAnsi, efUnicode, efUncodeBigEn, efUTF8);
TUniEditFrm = class(TForm)
   MainMenu1: TMainMenu;
   mnuFileItem: TMenuItem;
   mnuOpen: TMenuItem;
   mnuSpace1: TMenuItem;
   mnuSaveAs: TMenuItem;
   mnuSpace2: TMenuItem;
   mnuExit: TMenuItem;
   StatusBar: TStatusBar;
   procedure FormCreate(Sender: TObject);
   procedure FormDestroy(Sender: TObject);
private
   { Private declarations }
   FStream: TStream;
   OpenDlg: TOpenDialog;
   SaveDlg: TSaveDialog;
   UnicoMemo: TMemo;
   procedure SetMemoCharset;
   procedure LoadFromFile(fName: string);
   procedure SaveToFile(fName: string);
   procedure SetStatusMessage(Msg: string);
   procedure MenuItemOnClick(Sender: TObject);
   function ChWideToAnsi(const StrW: WideString): AnsiString;
   function ChAnsiToWide(const StrA: AnsiString): WideString;
   function UTF8ToWideString(const Stream: TStream): WideString;
   procedure TextToUTF8Stream(const Text: string; var Stream: TStream);
   function GetEncodeFromStream(const Stream: TStream): TEncodeFlags;
public
   { Public declarations }
end;
var
UniEditFrm: TUniEditFrm;
implementation
{$R *.dfm}
type
TUTF8Falg = packed record
   EF, BB, BF: Byte;
end;
const
Encode: TUTF8Falg = (EF: $EF; BB: $BB; BF: $BF);
MenuActSpace = 0;
MenuActOpen = 1;
MenuActSaveAs = 2;
MenuActExit = 3;
{ TUniEditFrm }
procedure TUniEditFrm.FormCreate(Sender: TObject);
var
n: integer;
begin
mnuOpen.Tag := MenuActOpen;
mnuSaveAs.Tag := MenuActSaveAs;
mnuExit.Tag := MenuActExit;
for n := 0 to mnuFileItem.Count - 1 do
   if mnuFileItem.Items[n].Caption <> '-' then
     mnuFileItem.Items[n].OnClick := MenuItemOnClick;
OpenDlg := TOpenDialog.Create(Self);
OpenDlg.Filter := 'UTF8 Text File|*.txt';
SaveDlg := TSaveDialog.Create(Self);
SaveDlg.Filter := 'UTF8 Text File|*.txt';
SaveDlg.DefaultExt := '.txt';
UnicoMemo := TMemo.Create(Self);
UnicoMemo.Parent := Self;
UnicoMemo.Align := alClient;
UnicoMemo.ScrollBars := ssVertical;
SetMemoCharset;
end;
procedure TUniEditFrm.FormDestroy(Sender: TObject);
begin
OpenDlg.Free; SaveDlg.Free; UnicoMemo.Free;
if Assigned(FStream) then FStream.Free;
end;
procedure TUniEditFrm.MenuItemOnClick(Sender: TObject);
begin
case TComponent(Sender).tag of
   MenuActOpen: if OpenDlg.Execute then LoadFromFile(OpenDlg.FileName);
   MenuActSaveAs: if SaveDlg.Execute then SaveToFile(SaveDlg.FileName);
   MenuActExit: Close;
end;
end;
procedure TUniEditFrm.SetMemoCharset;
begin
UnicoMemo.Font.Charset := GB2312_CHARSET;
UnicoMemo.Font.Size := 12;
end;
procedure TUniEditFrm.SetStatusMessage(Msg: string);
begin
SendMessage(StatusBar.Handle, WM_USER + 1, 0, DWord(PChar(Msg)));
end;
procedure TUniEditFrm.LoadFromFile(fName: string);
begin
if not Assigned(FStream) then FStream := TMemoryStream.Create;
TMemoryStream(FStream).LoadFromFile(fName);
if GetEncodeFromStream(FStream) = efUTF8 then
begin
   SetStatusMessage(Format('File: %s ,Size:%d Byte', [fName, FStream.Size]));
   UnicoMemo.Lines.BeginUpdate;
   UnicoMemo.Clear;
   try
     UnicoMemo.Lines.Add(ChWideToAnsi(UTF8ToWideString(FStream)));
   finally
     UnicoMemo.Lines.EndUpdate;
   end;
end
else SetStatusMessage(Format('File: %s ,Unknown Encode', [fName]));
FStream.Size := 0;
end;
procedure TUniEditFrm.SaveToFile(fName: string);
begin
try
   if not Assigned(FStream) then FStream := TMemoryStream.Create;
   TextToUTF8Stream(UnicoMemo.Lines.Text, FStream);
   TMemoryStream(FStream).SaveToFile(fName);
   SetStatusMessage(Format('Save File: %s ,Size:%d Byte', [fName, FStream.Size]));
finally
   FStream.Size := 0;
end;
end;
function TUniEditFrm.ChWideToAnsi(const StrW: WideString): AnsiString;
var
nLen: integer;
begin
Result := StrW;
if Result <> '' then
begin
   nLen := WideCharToMultiByte(936, 624, @StrW[1], -1, nil, 0, nil, nil);
   SetLength(Result, nLen - 1);
   if nLen > 1 then
     WideCharToMultiByte(936, 624, @StrW[1], -1, @Result[1], nLen - 1, nil, nil);
end;
end;
function TUniEditFrm.ChAnsiToWide(const StrA: AnsiString): WideString;
var
nLen: integer;
begin
Result := StrA;
if Result <> '' then
begin
   nLen := MultiByteToWideChar(936, 1, PChar(@StrA[1]), -1, nil, 0);
   SetLength(Result, nLen - 1);
   if nLen > 1 then
     MultiByteToWideChar(936, 1, PChar(@StrA[1]), -1, PWideChar(@Result[1]), nLen - 1);
end;
end;
function TUniEditFrm.UTF8ToWideString(const Stream: TStream): WideString;
var
nLen: Cardinal;
begin
try
   SetLength(Result, Stream.Size div SizeOf(WideChar) * 3);
   nLen := Utf8ToUnicode(@Result[1], Length(Result),
     Pointer(DWord(TMemoryStream(Stream).Memory) + Stream.Position),
     Stream.Size - Stream.Position);
   SetLength(Result, nLen);
except
   SetLength(Result, 0);
end;
end;
procedure TUniEditFrm.TextToUTF8Stream(const Text: string; var Stream: TStream);
var
StringW, StrW: WideString;
nLen: Cardinal;
begin
try
   if Text <> '' then
   begin
     StrW := ChAnsiToWide(Text);
     nLen := Length(StrW) * 3;
     SetLength(StringW, nLen);
     nLen := UnicodeToUtf8(@StringW[1], nLen, @StrW[1], Length(StrW));
     SetLength(StringW, nLen);
     Stream.Write(Encode, SizeOf(Encode));
     Stream.Write(StringW[1], Length(StringW));
   end
   else
     Stream.Write(Encode, SizeOf(Encode));
except
   SetLength(StrW, 0);
   SetLength(StringW, 0);
end;
end;
function TUniEditFrm.GetEncodeFromStream(const Stream: TStream): TEncodeFlags;
var
FEncode: TUTF8Falg;
begin
Result := efUnknown;
Stream.Read(FEncode, SizeOf(FEncode));
if (FEncode.EF = Encode.EF) and (FEncode.BB = Encode.BB)
   and (FEncode.BF = Encode.BF) then Result := efUTF8;
end;
end.
代码中有几个控件是动态创建的,其中有对话框和 Memo。这是为了随时改变使用不同控件
库进行测试观察的需要,如果你使用支持宽字符的控件,不用改界面,直接把创建实例改一
改就可以测试观察了。这种写法不是最好的,如果使用接口来描述就会更随意些。
-------------------------------------------------------------------------------------
干净搞定delphi多语言-兼论设计模式    
       随着全球化程度加深,软件越来越像蒲公英,到处飘散、扎根。这其中要解决的是不同语言的显示问题。我们当然希望一套程序,可以不修改代码就可以支持不同的语言,不要去维护很多的版本。
       首先要谈到的一个问题是乱码问题,因为delphi win32到11.x版还是不支持unicode,所以一般使用Ansi码,有这样几种情况会显示乱码:

  1. 使用的语言文字与系统当前设定的语言不一样;比如简体版QQ在繁体操作系统(或简体操作系统的区域设置中“非Unicode程序的语言”设定为 繁体)就是乱码。即使改变Font.Charset,某些元件仍然会出现乱码,如StatusBar。因此,在越南文版的windows显示越南文,在伊 朗文版的windows显示伊朗文,不要在越南文版windows显示伊朗文,在伊朗文版windows显示越南文,这样就能确保没有乱码问题。好在一般 这样的错位用法也不多见。
  2. 系统没有安装你要显示的语言的语言包;

       如果你要保证完全无乱码,必须考虑使用unicode码,使用成套的支持unicode的元件,如tnt,但它在UI变现上比较单一,你不可能不使用别的元件。
       言归正传,首先,看看哪些地方的字串需要实现多语言,并来看看各种实现方法的优劣。
           1、界面上的元件,如TButton的Caption;
           2、主动弹出的消息,如ShowMessage('Are you sure?'),Raise Exception.Create('Error!');
           3、例外错误举发的报告信息,如f/0引起的exception;
           4、第3方元件包内部的上述字串;
       实现多语言的方法很多,列举一二:
           1、delphi自带的Resource生成工具
               此工具把专案的dfm文件里的所有字串以及pas中定义为ResourceString的字串列举出来,按不同的语言编译成不同的Resource,专案编译前先选语言,每种语言编译成一个exe。
                这个工具使用很不方便,不是一个完整的解决方案,跟Borland的Midas的demo一样(TClientDataSet通过 ProviderName连接到RemoteDatamodule的TDataSetProvider,实际开发Erp系统时,谁会放100个 TDataSetProvider连接到100个TDataSet?),只是一个原理尚通的示范。
               首先,由于dfm本身也是资源文件的一部分,因此每次修改都要“Update Resource DLLs...”,如修改Button1为Button2,如果你忘了,运行时就会报“找不到资源Button1的错误”;提供的字典编辑画面中,出了字 串,还有Left/Top等资料;字典不能重用,在一个模组翻译了,在第2个模组还要再翻译相同的词。
              其次,每种语言一个exe/bpl,如果你的系统是Package切割,bpl也是每种语言一个,还要小心别把不同语言的bpl组合在了一起,到时候一个画面显示中文,一个显示德文(有一个可能是乱码)就惨了。
              再次,在作bpl组装的系统时,第3方元件如果没有提供多语言的方案,你就需要修改第3方元件,但一般我们不这样干,因为第3方元件会随时更新,难道每次人家更新你也再更新人家。
              因此,一般都没有人使用Delphi本身提供的这个方案(除了作demo)。
           2、Resource dll方式
              用单独的ResourceDll,用LoadResString等函数获得翻译字串,但你要到处写这个函数来一一替换,特别是Form上的字串,噢,会累死人。字典可以重用。
           3、网上讨论很多的ini文件方式
               此方法是写个替换的引擎,在运行时从ini文件读取语言字串来替换画面元件的显示文字。这个方法比第一种进步很多,不需要每种语言编译一个exe了,只要 提供不同的ini文件就好;画面修改时如果ini没有同步更新也不会出现致命错误,最多就是某个文字没有转换;引擎也提供了字串转换函数,因此也可以处理 主动弹出的消息。这个方法在文件格式上有三种不同的实现:
               (1)、[编号]=[字串]
                     每个字串从1开始编号,1,2,3,4......,很麻烦,代码要修改,当然运行时切换语言没问题。
               (2)、[元件.属性]=[字串]
                     这种实现把元件instance一一对应,用RTTI来判断属性,替换很精确,也可以运行时切换语言。不足之处是,略显呆板,多个元件相同的字串会多次列 出;没有扩展性,表现TListView的Columns等复杂元件时比较吃力。
               (3)、[旧字串]=[新字串]
                     不管元件的instance,ini是纯粹的语言对照表,或者叫字典,扩展性、运行时切换语言可能在引擎里。不足之处是不能处理一词多义。
               总的说来,这种方式有很大进步,但为了用ini文件,大家还要费力的破解64k的限制,更专业的方式是使用自定义的文件格式。
               在简单性方面,无疑是这种自定义的转换引擎,[旧字串]=[新字串]的文件格式来得方便,借助字典管理工具,字典文件可以重复使用,也可以提供给专业翻译 公司翻译。那么剩下的问题在引擎上,如何方便,最好用户不写一行代码;如何扩展性强,支持任意的第三方元件;如何有弹性,同一个画面有多种语言的文字,同 一个词可以转换成不同的意思......
            4、给每个元件类继承一个子类,在子类的Loaded方法里转换文字。由于要处理的都是叶级元件(虽然TLabel、TPanel都是从 TCustomControl来,但不能只处理TCustomControl),工作量比较大;对旧有程序除了换元件无能为力。
           5、为每个元件类注册一个转换函数,引擎遍历Container,为每个元件找到血源最近的转换函数,调用这个函数转换这个元件的文字。这样可以不必处理 叶结点,只需在恰当的元件层上注册函数;不必改动旧有程序。設計時Form上只需要放一個轉換元件,這個元件在Loaded后開始掃描Form上的元件, 從for I:=0 to ComponentCount-1或從for i:=0 to ControlCount-1遞歸,找到一個元件就去查找其血緣最近的註冊函數,然後調用這個函數替換其文字。因爲註冊函數是額外加上去的,所以不會動到 舊的代碼,對任意第方元件都可以擴展支持,且也不用去修改人家第3方元件的代碼。
我认为第5种方法很优雅,看起来比较干净。用GOF的设计模式来套,这属 于Mediator pattern(中介者模式)。多年前,我们使用一个叫TXPMenu的元件来获得XP风格的界面,也是感觉到它很干净,一个元件就搞定一切,不用 TLabel换成TFlatLabel,TButton换成TFlatButton......我记得《程序员》上还有文章专门称赞这个元件。但那个元件 没有使用中介者模式,不能很好的扩展对第3方元件的支持。
        最后,我们畅想一下,如果我是Borland,如何在Delphi里完整支援多语言。Delphi提供了一个区块定义的关键字 “ResourceString”,在这个区块定义的字串常量,编译器会把它编译在exe文件的资源区,运行时用LoadStringA这个 Windows API来读取,因此有些外部转换工具可以直接从exe文件读取这些资源字串,再写入转换后的字串;内嵌的转换引擎也可以拦截这个API函数来转换文字。但 是如果exe里的字串资源化不彻底,就无能为力,这个不彻底恰恰来自Delphi的DFM文件,Delphi把DFM文件整个作为一项资源放在exe里, 其上的字串就没法决定是否要don`t resource(Delphi源码里很多常量字串都有这个提示)了。
        如果除了string,widestring,ansistring等等这些数据类型,delphi增加一种数据类型multistring,然后修改 vcl元件定义(拜托Borland连同Unicode一起解决了吧),像TLabel.Caption定义成MultiString,对 MultiString类型,有一种专门的处理方法,如类似ResourceString用LoadString API来处理,每次读取就转换一次,但应该比这个内容更多,比如要传出instance,然后提供一个全局的ApplicationMulti元件,类似 ApplicationEvent,让外面能捕捉到。至于字典,只能外部用户提供(当然可以制定一个标准格式让delphi人都可以共享交换)。
      此法看起来可行,但还有个效率问题要考虑,(1)每次读取都转换,对频繁 draw的东西效率低;(2)比如一个ToolBar有好多的ToolButton,批次更新时一般都会用 BeginUpdate/EndUpdate,vcl如何告知后代来提高这种效率。(补记:效率看起来不是问题,对多次字串更改导致频繁draw,其实元 件自己已经会用beginupdate/endupdate处理,外部不会涉及)

Continue reading Delphi 7编译的程序任何系统都正常显示

delphi入门笔记

源码资源 : http://subsimple.com/delphi.asp
《从入门到精通》 文档中有备份
《从入门到精通》
一般应该重写free方法而不是destroy方法, D不提供垃圾回收机制,需要自己回收内存。
接口方法用静态方法绑定实现生成代码比虚方法实现要小。
except和finally不能同时使用。
子类隐藏父类虚方法不会起到滞后联编的效果,但是覆盖接口的方法却是可以并且是提倡的。
program pt;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
IT = interface
['{A2E180BC-7372-4894-9FB9-9AD286B700CF}']
procedure M1;
end;
type
TA = class(TInterfacedObject,IT)
public
procedure M1();
end;
procedure TA.M1();
begin
Writeln('Am');
end;
type
TB = class(TA,IT) //重新声明继承IT接口,如果不这样,不会起到滞后联编的效果
public
procedure M1();
end ;
procedure TB.M1() ;
begin
Writeln('Bm');
end;
var t:IT;
begin
t := TB.Create;
t.M1;
Readln;
end.

使用delphi7 lite集成了cnpack,但是代码提示快捷键无法修改(ctrl+space),其他快捷键可在

快捷键:
格式化:ctrl+shift+F
----------------------------------------------------------------------------------------构造函数
每个应用程序将分配给其运行的内存分为四个区域: 

代码区(Code area)
全局数据区(data area)
堆区(heap area)
栈区(stack area)

图2 程序内存空间
代码区:存储程序中程序代码,包括所有的函数代码
全局数据区:存储全局数据。
堆区:又叫“自由存储区”,存储动态数据(在Delphi中包括对象和字符串)。作用域为整个应用程序的整个生命周期直到调用了析构方法。
栈区:又叫“自动存储区”存储程序中的局部数据,在C 中,局部变量实际上是auto类型的变量。作用域为函数内部,函数调用完系统就立即回收栈空间。
在C 中,对象既可创建在堆(heap)上,也可以创建在栈(stack)中,还可以在全局数据中创建对象,故C 有全局对象、局部对象、静态对象和堆对象四种对象之说。而在Delphi中,所有的对象都是建立堆(heap)存储区上,所以Delphi构造函数不能自 动被调用,而必须由程序员自己调用(在设计器拖动组件,此时对象由Delphi创建)。下面的程序说明Delphi和C 中创建对象的区别:
在Delphi中:
Procedure CreateObject(var FooObjRef:TFooObject);
begin
FooObjRef:=TfooObject.create;
//由程序员调用,过程调用完之后,对象依然存在.不需要进行拷贝
FooObject.caption=’I am created in stack of CreateObject()’;
End;
在做popupmanager时
EnumWindows(@popwatcher.ProcessFun, LPARAM(self));//一定要这样写@popwatcher.ProcessFun,网上的都没搞清楚,而且这个函数不能是类的函数(静态和对象都不行),否则虽然会调用但是会抛内存访问错误。
另外LPARAM(self)和LPARAM(@self)都能work,偶不懂。尝试自己转指针,没有成功,直接在参数定义上与传入参数一致就可以了:function ProcessFun(hwnd: HWND; pw:TPopWatcher): boolean; stdcall; 

 

Vista提供的UAC机制,是Vista的新增功能之一。它的主要目的是防止对于操作系统本身的恶意修改。如果想对于Vista的系统设置进行改动,必须通过UAC的验证才能够进行。通过这样的手段,大大提供了系统的安全性。 

关于UAC的利弊,网络上的说法褒贬不一,在这里就不具体讨论了。

对于Delphi程序的影响,UAC主要在于以下几点:

1、由于UAC机制,Delphi对于系统的操作可能无声的失败,而同样的程序,在2000/X下面可能运行正常。譬如注册表的改动。。。

2、为了避免这样的情况,Delphi程序必须支持Vista UAC标注,也就是说,在UAC程序的图标下面显示盾牌标志。这样可以在需要系统更高权限的时候,提醒用户。

为了让程序显示UAC标志,现在看来Vista是通过读取程序的资源(Resource)里面的MANIFEST资源,来决定是否显示“UAC盾牌”。

为了支持Vista,Delphi程序必须在资源里面嵌入MANIFEST信息。

1、首先编辑一个文件,内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

保持为UAC.manifest,这里文件是随意的。特别注意红色的“requireAdministrator”,这个表示程序需要管理员(Administrator)才能正常运行。

2、然后编辑一个RC文件,名为uac.rc

1 24 UAC.manifest

其中:

1-代表资源编号

24-资源类型为RTMAINIFEST

UAC.manifest-前面的文件名称

3、用brcc32编译这个rc文件为res文件

brcc32 uac.rc -fouac.res

4、在程序里面加入

{$R uac.res}  //注意这一步,必须添加。不要以为{$R *.res}中的*是包含所有,它是指对应的意思,对你程序中包含的文件会包含其对应的.res,例如abc.pas会包含abc.res(如果有)

让Delphi编译的时候,把uac.res编译进exe文件

5、把文件放到vista里面运行,就会看程序图标下面显示UAC盾牌标志了。

 

Continue reading delphi入门笔记

nosql笔记

NoSQL 是非关系型数据存储的广义定义。它打破了长久以来关系型数据库与 ACID 理论大一统的局面。NoSQL 数据存储不需要固定的表结构,通常也不存在连接操作。在大数据存取上具备关系型数据库无法比拟的性能优势。该术语在 2009 年初得到了广泛认同。

当今的应用体系结构需要数据存储在横向伸缩性上能够满足需求。而 NoSQL 存储就是为了实现这个需求。Google 的 BigTable Amazon Dynamo 是非常成功的商业 NoSQL 实现。一些开源的 NoSQL 体系,如Facebook 的 Cassandra, Apache 的 HBase,也得到了广泛认同。

如果您刚接触 NoSQL,那有必要学习一些背景知识。下列资料是Kas Thomas,一位国外的技术分析师认为非常有价值的 NoSQL 相关必读资料:

先看看这个吧 http://sebug.net/paper/databases/nosql/Nosql.html

Amazon Dynamo 论文。几乎所有懂 NoSQL 的人都阅读过它。

Google 的 Bigtable 论文。 也许您已经耳熟能详。

Werner Vogels 的 Eventually Consistent (发布于 ACM Queue)。如果您对最终一致性不是非常清晰,请阅读这篇文章。

Brewer 的 CAP 理论(可伸缩性的基础)在这里可以找到非常好的诠释。也可以看看 2000 7 月 PODC 上 Brewer的原始幻灯片

在 2009 年 6 月在 SFO 的 NoSQL 见面会的幻灯片。这些资料可以用经典的、关键的、将影响巨大的、值得纪念的来形容。

SQL Databases Don’t Scale 是一篇简短、基础、直切问题的文章。除非您是一位在伸缩性问题上身经百战的数据库管理员,否则,这篇文章讲述的内容对于您可能是非常关键的。

Jonathan Ellis 的文章 NoSQL Ecosystem 以表格的方式对当今主流的分布式数据库做了比较。类似的比较还有 Quick Reference to Alternative data storages。Ellis 的文章除了表格对比外对于想了解 NoSQL 生态的人来说是非常值得一读的,该文章内涵丰富,短小精悍;而 Quick Reference to Alternative data storages 主要是表格,这些表格对比的内容又比 Ellis 的完整。

【相关国外资源】

http://nosql-databases.org/ 该站点的标语是:非关系型世界的终结向导!,该站点非常确信自己是:在互联网上拥有 NoSQL 相关链接最多的网站。总之,该网站值得关注。

另外,作为 NoSQL 极客(geeks),请 follow @nosqlupdate。另外,请 follow @al3xandruMyNoSQL blog NoSQL Week in Review 的创建者)。NoSQL Week in Review 比较新,希望能保持正常更新,因为它确实很棒!

当然,您还可以看看 Ricky Ho 最近的博文,他总结了一些分布式数据存储技术关键点。他的博文中有两篇非常值得一看的文章:Query Processing for NoSQL Databases,还有 NoSQL Design Patterns(《程序员》杂志有译文)。

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

http://adam.heroku.com/past/2009/7/6/sql_databases_dont_scale/

此文章非常有用,它对之前主流的分布式数据库的概念进行了批判。

a tornado of razorblades

by Adam Wiggins

SQL Databases Don't Scale

databases

Mon Jul 06 12:51:22 -0700 2009

A question I’m often asked about Heroku is: “How do you scale the SQL database?” There’s a lot of things I can say about using caching, sharding, and other techniques to take load off the database. But the actual answer is: we don’t. SQL databases are fundamentally non-scalable, and there is no magical pixie dust that we, or anyone, can sprinkle on them to suddenly make them scale.

What Is Scaling?

To qualify as true scaling, I believe a technique must fit the following criteria:

  1. Horizontal scale: more servers creates more capacity. 水平扩展性(也称Scale out)
  2. Transparent to the application: the business logic of the app should be separated from concerns of scaling server resources. 透明性
  3. No single point of failure: there should be no one server which, if lost, causes downtime of the application. 没有单点故障

 

As an example from the hardware world, a RAID5 disk array offers true scaling:

  1. Horizontal scale: you can run a RAID5 with 4 disks, or 12, or 20; more disks gives you more drive space and (generally) better performance.
  2. Transparent to the application: applications using the RAID as a single device. My text editor doesn’t care that the file it is saving or loading is split across many disks.
  3. No single point of failure: you can pop out a drive and the array will continue to function (albeit with a performance hit, known as “degraded mode”). Replace the drive and it will rebuild itself. All of this happens without the applications using the RAID being aware any interruption of the functioning of the disk storage.

 

So let’s take a look at some of the techniques used to “scale” SQL databases, and why they all fail to achieve the criteria above.

Vertical Scaling 垂直扩展性[关系数据库的扩展方式的问题,相对于水平扩展性,纵向扩展性(也称Scale up)]

One way to scale a SQL database is to buy a bigger box. This is usually called “vertical scaling.” I sometimes call it: Moore’s law scaling. What are the problems with this?

  • It’s a complicated transaction that usually requires manual labor from ops people and substantial downtime.
  • The old machine is useless afterward. This wastes resources and encourages you to overprovision, buying a big server before you know you’re really going to need it.
  • There’s a cap on how big you can go.

 

I know plenty of folks who have bumped their head on the last point (usually somewhere around a 256-core Sun server) and now they are painted into a corner. They find themselves crossing their fingers and hoping that they’ll stop growing - not cool at all.

So yes, you can put a SQL database on a bigger box to buy yourself more headroom. But this fails point #1 on my checklist for true scaling.

之前的分布式也是主要使用水平扩展的,这里是说nosql更好的支持水平扩展。

Partitioning, aka Sharding 分区/分片破坏RDBS数据关系

Sharding divides your data along some kind of application-specific boundary. For example, you might store users whose names start with A-M on one database, and N-Z on another. Or use a modulo of the user id by the number of databases.

This requires deep integration into the application and careful planning of the partitioning scheme relative to the database schema and the kinds of queries you want to do. Summary: big pain in the ass.

So while sharding is a form of horizontal scaling, it fails point #2: it is not transparent to the business logic of the application.

The deeper problem with sharding is that SQL databases are relational databases, and most of the value in a relational database is that it stores relationships. Once you split records across multiple servers, you’re servering many of those relations; they now have to be reconstructed on the client side. Sharding kills most of the value of a relational database.

 

Read Slaves 主从模式的局限性

MySQL’s killer feature is easy configuration of master-slave replication, where you have a read-only slave database that replicates everything coming to the master database in realtime. You can then create a routing proxy between the clients and your database (or build smart routing into the client library) which sends any reads (SELECT) to one of the read slaves, while only sending writes (INSERT, UPDATE, DELETE) to the master.

Postgres has replication via Slony, though it’s much more cumbersome to set up than MySQL’s replication. Years ago I even did basic master-slave replication with a 50-line Perl script that read from the query log and mirrored all write queries over to the slave. So replication is possible just about anywhere, with differing degrees of setup and maintenance headaches.

The read slave technique is the best option for scaling SQL databases. It qualifies as horizontal scaling on the read side, and is transparent to the application. This is the technique that many of the largest MySQL installs use.

And yet, this is still ultimately a limited technique. The master server is a bottleneck, particularly on write-heavy applications. And it fails point #3 on the true scaling definition: there is a single point of failure. This is a problem not only when the database fails, but when you want to perform maintenance on the server. Promoting one of the read slaves to master allows you to recover relatively quickly, but this switcharoo requires hands-on attention from the sysadmins.

主数据库存在瓶颈,因此存在单点故障

And while it qualifies as horizontal scaling for read performance, it does not qualify for writes and capacity. Horizontal scaling should spread out both the load of executing queries and the data storage itself. This is how you can grow the total storage space of a RAID: add enough disks, and you can get a RAID which has a much greater capacity than any single hard drive on the market. Read slaves require complete copies of the database, so you still have a ceiling on how much data you can store.

读-从数据库需要数据的完整复制,因此任然存在存储天花板--硬盘能存多少东西?

A Long-Term Solution

So where do we go from here? Some might reply “keep trying to make SQL databases scale.” I disagree with that notion. When hundreds of companies and thousands of the brightest programmers and sysadmins have been trying to solve a problem for twenty years and still haven’t managed to come up with an obvious solution that everyone adopts, that says to me the problem is unsolvable. Like Kirk facing the Kobayashi Maru, we can only solve this problem by redefining the question.

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

文章 Query Processing for NoSQL Databases

大体意思是nosql有两个局限:

  1. It calls for a more relaxed data consistency model

它是个简单关系的模型

  1. It provides primitive querying and searching capability

他只提供原始的查询能力,例如键值对的键查询

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

孙立文章  不错

在 过去,我们只需要学习和使用一种数据库技术,就能做几乎所有的数据库应用开发。因为成熟稳定的关系数据库产品并不是很多,而供你选择的免费版本就更加少 了,所以互联网领域基本上都选择了免费的MySQL数据库。在高速发展的WEB2.0时代,我们发现关系数据库在性能、扩展性、数据的快速备份和恢复、满 足需求的易用性上并不总是能很好的满足我们的需要,我们越来越趋向于根据业务场景选择合适的数据库,以及进行多种数据库的融合运用。几年前的一篇文章《One Size Fits All - An Idea Whose Time Has Come and Gone》就已经阐述了这个观点。

当我们在讨论是否要使用NoSQL的时候,你还需要理解NoSQL也是分很多种类的,在NoSQL百花齐放的今天,NoSQL的正确选择比选择关系数据库还具有挑战性。虽然NoSQL的使用很简单,但是选择却是个麻烦事,这也正是很多人在观望的一个原因。

NoSQL的分类

NoSQL仅仅是一个概念,NoSQL数据库根据数据的存储模型和特点分为很多种类。

类型部分代表特点
列存储Hbase,Cassandra,

Hypertable

顾名思义,是按列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有非常大的IO优势。
文档存储MongoDB,CouchDB文档存储一般用类似json的格式存储,存储的内容是文档型的。这样也就有有机会对某些字段建立索引,实现关系数据库的某些功能。
key-value存储Tokyo Cabinet / TyrantBerkeley DBMemcacheDBRedis可以通过key快速查询到其value。一般来说,存储不管value的格式,照单全收。(Redis包含了其他功能)
图存储Neo4J,FlockDB图形关系的最佳存储。使用传统关系数据库来解决的话性能低下,而且设计使用不方便。
对象存储db4o,Versant通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据。
xml数据库Berkeley DB XMLBaseX高效的存储XML数据,并支持XML的内部查询语法,比如XQuery,Xpath。

以上NoSQL数据库类型的划分并不是绝对,只是从存储模型上来进行的大体划分。它们之间没有绝对的分界,也有交差的情况,比如Tokyo Cabinet / Tyrant的Table类型存储,就可以理解为是文档型存储,Berkeley DB XML数据库是基于Berkeley DB之上开发的。

NoSQL还是关系数据库

虽然09年出现了比较激进的文章《关系数据库已死》,但是我们心里都清楚,关系数据库其实还活得好好的,你还不能不用关系数据库。但是也说明了一个事实,关系数据库在处理WEB2.0数据的时候,的确已经出现了瓶颈。

那么我们到底是用NoSQL还是关系数据库呢?我想我们没有必要来进行一个绝对的回答。我们需要根据我们的应用场景来决定我们到底用什么。

如 果关系数据库在你的应用场景中,完全能够很好的工作,而你又是非常善于使用和维护关系数据库的,那么我觉得你完全没有必要迁移到NoSQL上面,除非你是 个喜欢折腾的人。如果你是在金融,电信等以数据为王的关键领域,目前使用的是Oracle数据库来提供高可靠性的,除非遇到特别大的瓶颈,不然也别贸然尝 试NoSQL。

然而,在WEB2.0的网站中,关系数据库大部分都出现了瓶颈。在磁盘IO、数据库可扩展上都花费了开发人员相当多的精力来优化,比如做分 表分库 (database sharding)、主从复制、异构复制等等,然而,这些工作需要的技术能力越来越高,也越来越具有挑战性。如果你正在经历这些场合,那么我觉得你应该尝 试一下NoSQL了。

选择合适的NoSQL

如此多类型的NoSQL,而每种类型的NoSQL又有很多,到底选择什么类型的NoSQL来作为我们的存储呢?这并不是一个很好回答的问题,影 响我们选择 的因素有很多,而选择也可能有多种,随着业务场景,需求的变更可能选择又会变化。我们常常需要根据如下情况考虑:

数据结构特点。包括结构化、半结构化、字段是否可能变更、是否有大文本字段、数据字段是否可能变化。

写入特点。包括insert比例、update比例、是否经常更新数据的某一个小字段、原子更新需求。

查询特点。包括查询的条件、查询热点的范围。比如用户信息的查询,可能就是随机的,而新闻的查询就是按照时间,越新的越频繁。

NoSQL和关系数据库结合

其实NoSQL数据库仅仅是关系数据库在某些方面(性能,扩展)的一个弥补,单从功能上讲,NoSQL的几乎所有的功能,在关系数据库上都能够满足,所以选择NoSQL的原因并不在功能上。

所以,我们一般会把NoSQL和关系数据库进行结合使用,各取所长,需要使用关系特性的时候我们使用关系数据库,需要使用NoSQL特性的时候我们使用NoSQL数据库,各得其所。

举 个简单的例子吧,比如用户评论的存储,评论大概有主键id、评论的对象aid、评论内容content、用户uid等字段。我们能确定的是评论内容 content肯定不会在数据库中用where content=’’查询,评论内容也是一个大文本字段。那么我们可以把 主键id、评论对象aid、用户id存储在数据库,评论内容存储在NoSQL,这样数据库就节省了存储content占用的磁盘空间,从而节省大量IO, 对content也更容易做Cache。

//从MySQL中查询出评论主键id列表

commentIds=DB.query("SELECT id FROM comments where aid=’评论对象id’ LIMIT 0,20");

//根据主键id列表,从NoSQL取回评论实体数据

CommentsList=NoSQL.get(commentIds);

NoSQL代替MySQL

在某些应用场合,比如一些配置的关系键值映射存储、用户名和密码的存储、Session会话存储等等,用NoSQL完全可以替代MySQL存储。不但具有更高的性能,而且开发也更加方便。

NoSQL作为缓存服务器

MySQL+Memcached的架构中,我们处处都要精心设计我们的缓存,包括过期时间的设计、缓存的实时性设计、缓存内存大小评估、缓存命中率等等。

NoSQL数据库一般都具有非常高的性能,在大多数场景下面,你不必再考虑在代码层为NoSQL构建一层Memcached缓存。NoSQL数据本身在Cache上已经做了相当多的优化工作。

Memcached这类内存缓存服务器缓存的数据大小受限于内存大小,如果用NoSQL来代替Memcached来缓存数据库的话,就可以不再受限于内存大小。虽然可能有少量的磁盘IO读写,可能比Memcached慢一点,但是完全可以用来缓存数据库的查询操作。

规避风险

由于NoSQL是一个比较新的东西,特别是我们选择的NoSQL数据库还不是非常成熟的产品,所以我们可能会遇到未知的风险。为了得到NoSQL的好处,又要考虑规避风险,鱼与熊掌如何兼得?

现 在业内很多公司的做法就是数据的备份。在往NoSQL里面存储数据的时候还会往MySQL里面存储一份。NoSQL数据库本身也需要进行备份(冷备和热 备)。或者可以考虑使用两种NoSQL数据库,出现问题后可以进行切换(避免出现digg使用Cassandra的悲剧[全盘使用nosql出现问题])。

总结

本文只是简单的从MySQL和NoSQL的角度分析如何选择,以及进行融合使用。其实在选择NoSQL的时候,你可能还会碰到关于CAP原则,最终一致性,BASE思想的考虑。因为使用MySQL架构的时候,你也会碰到上面的问题,所以这里没有阐述。

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

nosql 介绍[孙立]--文章泛泛而谈,nosql--mysql比较

非 常荣幸能受邀在InfoQ开辟这样一个关于NoSQL的专栏,InfoQ是我非常尊重的一家技术媒体,同时我也希望借助InfoQ,在国内推动 NoSQL的发展,希望跟我一样有兴趣的朋友加入进来。这次的NoSQL专栏系列将先整体介绍NoSQL,然后介绍如何把NoSQL运用到自己的项目中合 适的场景中,还会适当地分析一些成功案例,希望有成功使用NoSQL经验的朋友给我提供一些线索和信息。

NoSQL概念

随着web2.0的快速发展,非关系型、分布式数据存储得到了快速的发展,它们不保证关系数据的ACID特性。NoSQL概念在2009年被提了出来。NoSQL最常见的解释是“non-relational”,“Not Only SQL”也被很多人接受。(“NoSQL”一词最早于1998年被用于一个轻量级的关系数据库的名字。)

NoSQL被我们用得最多的当数key-value存储,当然还有其他的文档型的、列存储、图型数据库、xml数据库等。在NoSQL概念提出之前,这些数据库就被用于各种系统当中,但是却很少用于web互联网应用。比如cdb、qdbm、bdb数据库。

传统关系数据库的瓶颈

传统的关系数据库具有不错的性能,高稳定型,久经历史考验,而且使用简单,功能强大,同时也积累了大量的成功案例。在互联网领域,MySQL成为了绝对靠前的王者,毫不夸张的说,MySQL为互联网的发展做出了卓越的贡献。

在90年代,一个网站的访问量一般都不大,用单个数据库完全可以轻松应付。在那个时候,更多的都是静态网页,动态交互类型的网站不多。

到了最近10年,网站开始快速发展。火爆的论坛、博客、sns、微博逐渐引领web领域的潮流。在初期,论坛的流量其实也不大,如果你接触网络比较早,你可能还记得那个时候还有文本型存储的论坛程序,可以想象一般的论坛的流量有多大。

Memcached+MySQL

后 来,随着访问量的上升,几乎大部分使用MySQL架构的网站在数据库上都开始出现了性能问题,web程序不再仅仅专注在功能上,同时也在追求性 能。程序员们开始大量的使用缓存技术来缓解数据库的压力,优化数据库的结构和索引。开始比较流行的是通过文件缓存来缓解数据库压力,但是当访问量继续增大 的时候,多台web机器通过文件缓存不能共享,大量的小文件缓存也带了了比较高的IO压力。在这个时候,Memcached就自然的成为一个非常时尚的技 术产品。

Memcached 作为一个独立的分布式的缓存服务器,为多个web服务器提供了一个共享的高性能缓存服务,在Memcached服务器上,又发展 了根据hash算法来进行多台Memcached缓存服务的扩展,然后又出现了一致性hash来解决增加或减少缓存服务器导致重新hash带来的大量缓存 失效的弊端。当时,如果你去面试,你说你有Memcached经验,肯定会加分的。

Mysql主从读写分离

由于数据库的写入压力增加,Memcached只能缓解数据库的读取压力。读写集中在一个数据库上让数据库不堪重负,大部分网站开始使用主从复制技术来达到读写分离,以提高读写性能和读库的可扩展性。Mysql的master-slave模式成为这个时候的网站标配了。

分表分库

随 着web2.0的继续高速发展,在Memcached的高速缓存,MySQL的主从复制,读写分离的基础之上,这时MySQL主库的写压力开始出 现瓶颈,而数据量的持续猛增,由于MyISAM使用表锁,在高并发下会出现严重的锁问题,大量的高并发MySQL应用开始使用InnoDB引擎代替 MyISAM。同时,开始流行使用分表分库来缓解写压力和数据增长的扩展问题。这个时候,分表分库成了一个热门技术,是面试的热门问题也是业界讨论的热门 技术问题。也就在这个时候,MySQL推出了还不太稳定的表分区,这也给技术实力一般的公司带来了希望。虽然MySQL推出了MySQL Cluster集群,但是由于在互联网几乎没有成功案例,性能也不能满足互联网的要求,只是在高可靠性上提供了非常大的保证。

MySQL的扩展性瓶颈

在 互联网,大部分的MySQL都应该是IO密集型的,事实上,如果你的MySQL是个CPU密集型的话,那么很可能你的MySQL设计得有性能问 题,需要优化了。大数据量高并发环境下的MySQL应用开发越来越复杂,也越来越具有技术挑战性。分表分库的规则把握都是需要经验的。虽然有像淘宝这样技 术实力强大的公司开发了透明的中间件层来屏蔽开发者的复杂性,但是避免不了整个架构的复杂性。分库分表的子库到一定阶段又面临扩展问题。还有就是需求的变 更,可能又需要一种新的分库方式。

MySQL数据库也经常存储一些大文本字段,导致数据库表非常的大,在做数据库恢复的时候就导致非常的慢,不容易快速恢复数据库。比如1000万4KB大小的文本就接近40GB的大小,如果能把这些数据从MySQL省去,MySQL将变得非常的小。

关系数据库很强大,但是它并不能很好的应付所有的应用场景。MySQL的扩展性差(需要复杂的技术来实现),大数据下IO压力大,表结构更改困难,正是当前使用MySQL的开发人员面临的问题。

NOSQL的优势[总结的好]

易扩展

NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之间无关系,这样就非常容易扩展。也无形之间,在架构的层面上带来了可扩展的能力。

大数据量,高性能

NoSQL 数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。这得益于它的无关系性,数据库的结构简单。一般MySQL使用 Query Cache,每次表的更新Cache就失效,是一种大粒度的Cache,在针对web2.0的交互频繁的应用,Cache性能不高。而NoSQL的 Cache是记录级的,是一种细粒度的Cache,所以NoSQL在这个层面上来说就要性能高很多了。

灵活的数据模型

NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。这点在大数据量的web2.0时代尤其明显。

高可用

NoSQL在不太影响性能的情况,就可以方便的实现高可用的架构。比如Cassandra,HBase模型,通过复制模型也能实现高可用。

总结

NoSQL数据库的出现,弥补了关系数据(比如MySQL)在某些方面的不足,在某些方面能极大的节省开发成本和维护成本。

MySQL和NoSQL都有各自的特点和使用的应用场景,两者的紧密结合将会给web2.0的数据库发展带来新的思路。让关系数据库关注在关系上,NoSQL关注在存储上

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

Continue reading nosql笔记

Pagination


Total views.

© 2013 - 2019. All rights reserved.

Powered by Hydejack v6.6.1