<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="http://feeds.qzone.qq.com/rss.xsl" version="1.0"?>
<rss version="2.0" xmlns:qz="http://qzone.qq.com">
<channel>
<title><![CDATA[ぺ城市蚂蚁ǎ]]></title>
<description><![CDATA[想做就做，没什么好说的~~！]]></description>
<link>http://270549948.qzone.qq.com</link>
<lastBuildDate>Sun, 29 Nov 2009 09:43:51 GMT</lastBuildDate>
<generator>Qzone</generator>
<language>zh-cn</language>
<copyright>Copyright (C), 2005-2008, Tencent Tech. Co., Ltd.</copyright>
<pubDate>Wed, 18 Apr 2007 04:24:08 GMT</pubDate>

<item>
<title><![CDATA[Delphi开发串口通信程序]]></title>
<link>http://270549948.qzone.qq.com/blog/7</link>
<description><![CDATA[Delphi 是新一代可视化开发工具，它具有功能强大、简便易用和代码执行速度快等特点，Delphi系列开发工具在国际各媒体上曾获得过三十多项大奖，是全球公认的快速应用开发工具技术的先驱者，他越来越在构架企业信息系统方面发挥着重要作用。<br>它的功能很强大，但在对串口通信的控制上Delphi的帮助文档和其他书籍中很少提及，可这是在开发应用系统时会经常遇到却又令人头痛的事情。下面介绍三种解决方案，以实现接收和发送数据的功能。<br><br>一、 使用ActiveX控件<br>由于Delphi中没有串口控件可用，所以首先需要把ActiveX控件MSCOMM加到元件选项板上。这是一个非常好的控件它不仅能对串口进行操作，而且还可以对Modem进行控制。下面结合一个具体的实例来说明如何用MSCOMM控件开发出串口通信程序。<br>创建一个Communication.dpr工程，把窗体的Name属性变为CommForm，将标题改为The Communication Test，选择File/Save As将新的窗体存储为CommFrm.pas，接下来参照图1和图2将控件添加到主窗体中。<br><br>图1 图2<br>由图1和图2我们可以看出，通过设置页可选定进行数据传输的通信端口和端口的波特率、奇偶校验、数据位和停止位，通信时每传输一个字符都将触发响应事件，在通信页“传输显示”位置可看到当前正在进行传输的数据。同时当出现回车换行符时将整行内容显示在memDisplay新的一行中，而全部接收的内容还将存在一个文件中。部分源代码如下：<br>变量说明<br>var<br>CommForm: TCommForm;<br>ss :string;<br>savef,readf :file of char;<br>i,j :longint;<br><br>初始化<br>procedure TCommForm.FormCreate(Sender: TObject);<br>begin<br>mscomm.commport:=1;<br>mscomm.settings:='9600,n,8,1';<br>mscomm.inputlen:=1;<br>mscomm.inbuffercount:=0;<br>mscomm.portopen:=true;<br>ss:='';<br>i:=0;<br>j:=0;<br>assignfile(savef,'save1');<br>rewrite(savef);<br>assignfile(readf,'read1');<br>reset(readf);<br>end;<br><br>设置确定<br>procedure TCommForm.btnConfirmClick(Sender: TObject);<br>begin<br>if mscomm.portopen then<br>mscomm.portopen:=false;<br>mscomm.commport:=strtoint(edtCommport.text);<br>mscomm.settings:=edtCommsetting.Text;<br>end;<br><br>传输事件<br>procedure TCommForm.MSCommComm(Sender: TObject);<br>var<br>filenrc :char;<br>buffer :variant;<br>s1:string;<br>c :char;<br>begin<br>case mscomm.commEvent of<br>comEvSend:<br>begin<br>while not(eof(readf)) do<br>begin<br>read(readf,filenrc);<br>mscomm.output:=filenrc;<br>j:=j+1;<br>lblDisplay.caption:=inttostr(j);<br>if mscomm.outbuffercount&gt;=2 then<br>break;<br>end;<br>end;<br>comEvReceive:<br>begin<br>buffer:=mscomm.Input;<br>s1:=buffer;<br>c:=s1[1];<br>ss:=ss+c;<br>i:=i+1;<br>lblDisplay.caption:=c+inttostr(i);<br>write(savef,c);<br>if (c=chr(10))or(c=chr(13)) then<br>begin<br>lblDisplay.caption:='cr'+inttostr(i);<br>memDisplay.lines.add(ss);<br>ss:='';<br>end;<br>end;<br>end;<br>end;<br><br>当然还有许多串口控制的ActiveX控件，有控件用是方便，但是是否说没有控件就不能用Delphi本身解决问题呢。那么就请来看一下下面的解决方案：<br><br>二、使用行间汇编<br>对于硬件的控制，汇编语言是最方便的了，而Delphi中又允许使用行间汇编那么来看一下怎样使用行间汇编接收下位机传来的数据，在下面的例子中我们简化了问题，比如我们通过COM2接收400个传来的字符并将这些内容保存在AAA.DAT文件中当接收完毕后显示‘Receive end’。但是为什么说我们简化了问题呢，因为实际情况中双方通信可能是约定传送字符的个数，也可能约定的是规定好的起始字符和结束字符，或是多种条件同时约定待各种条件全部满足时才表示完成一次成功的接收否则如有一个条件未满足都表示接收失败需要重新传送。这些约定在使用了行间汇编的Delphi程序中都可实现。下面的程序就是按一个按钮进入的一个简化的串口接收程序。<br>procedure TForm1.Button1Click(Sender: TObject);<br>var ca:array[1..400]of char;<br>c:char;<br>i,j:integer;<br>f1:file of char;<br>label loop1;<br>begin<br>i:=1;<br>asm<br>mov dx,0001<br>mov ax,005eh<br>int 14h<br>end;<br>for j:=1 to 400 do<br>begin<br>asm<br>loop1: mov dx,0001<br>mov ah,02<br>int 14h<br>test ah,80h<br>jnz loop1<br>mov c,al<br>end;<br>ca<span style="font-style:italic"><wbr />:=c;<br>i:=i+1;<br>end;<br>assignfile(f1,'aaa.dat');<br>rewrite(f1);<br>for j:=1 to i-1 do<br>write(f1,ca[j]);<br>closefile(f1);<br>label1.caption:='receive end';<br>end;<br><br>三、用Delphi调用可执行应用程序<br>采用其它编程技术编制的串口通信程序在完成数据传输后将数据保存到磁盘上，然后用Delphi对数据内容进行处理。通过在Delphi中与其他编程技术协同工作也不失为一种解决问题的好方法。 <!--v:3.2--> ]]></description>
<category><![CDATA[编程技术]]></category>
<author><![CDATA[270549948@qq.com(ぺ城市蚂蚁ǎ)]]></author>
<comments>http://270549948.qzone.qq.com/blog/7#comment</comments>
<qz:effect>512</qz:effect>
<pubDate>Wed, 18 Apr 2007 04:24:08 GMT</pubDate>
<guid>http://270549948.qzone.qq.com/blog/7</guid>
</item>

<item>
<title><![CDATA[三层架构初探]]></title>
<link>http://270549948.qzone.qq.com/blog/6</link>
<description><![CDATA[       随便说说最近项目中的三层架构吧。讲点实际的东西。我最讨厌空讲道理。网上讲道理的太多了，不喜欢举例子。<br>     大多数文章中都或多或少的讲到了三层架构。表示层，业务层，数据层。又把业务层再细分，分为外观服务层，主业务服务，及数据库库服务层。<br>    今天主要讨论一下业务层吧。举个最简单的例子。客户端获取数据。<br>    业务层要与表示层尽量解藕， 我的方法是：首先我们在中间层TLB_中定义一个接口 IBusinessService, 定义一个方法。getvoList，我要得到一个VO的列表， VO即ValueObject, 例如：<br>TValueObject= class(TPersistent)<br>  private<br>     b_insertFlag :Boolean;<br>     b_updateFlag :Boolean;<br>     b_deleteFlag :Boolean;<br>     d_rowVersion :double;<br>procedure setInsertFlag(pInsertFlag :Boolean);<br>     function getInsertFlag: Boolean;<br>     procedure setUpdateFlag(pUpdateFlag :Boolean);<br>     function getUpdateFlag: Boolean;<br>     procedure setDeleteFlag(pDeleteFlag :Boolean);<br>     function getDeleteFlag: Boolean;<br>     procedure setRowVersion(pRowVersion :double);<br>     function getRowVersion:double;<br>     protected   <br>     function  GetOLEData: OleVariant; virtual;<br>     procedure SetOLEData(const Value: OleVariant); virtual;<br>published<br>     property bInsertFlag: Boolean read getInsertFlag write setInsertFlag;<br>     property bUpdateFlag: Boolean read getUpdateFlag write setUpdateFlag;<br>     property bDeleteFlag: Boolean read getDeleteFlag write setDeleteFlag;<br>     property dRowVersion: double read getRowVersion write setRowVersion;<br>     property POLEData:OleVariant read GetOLEData write SetOLEData;<br>end;<br>  TUserVO = class(TValueObject)<br>private<br>id: string;<br>name: string;<br>password: string;<br>VO的列表：<br>TValueObjectList = Class(TObjectList)<br>private<br>ValueObject: TValueObject;<br>ClassName: TClass;<br>procedure setClassName(pTmpClsName :TClass);<br>function getClassName: TClass;<br>procedure setValueObject(pTmpVO :TValueObject);<br>function getValueObject: TValueObject;<br>protected<br>function GetOLEData: OleVariant; virtual;<br>procedure SetOLEData(const Value: OleVariant); virtual;<br>published<br>function AddItem(index: integer; AObject: TObject ):Integer; virtual;<br>function GetItem(index, itemid: integer ): TObject; virtual;<br>function CountItem:Integer; virtual;<br>public<br>constructor Create; virtual;<br>destructor Destroy; override;<br>procedure AfterConstruction; override;<br>property PClassName: TClass read getClassName write setClassName;<br>property POLEData: OleVariant read GetOLEData write SetOLEData;<br>property PValueObject: TValueObject read getValueObject write setValueObject;<br>end;<br>TValueObjectList就是VO的装载器。在 JAVA中有一个好听的叫法，<br><br>VOList值列表组装器，具体的功能是可以管理VO， 当然你可以进行扩充，比如后来我加入了OLE&lt;-&gt;TOBJECT&lt;-&gt;TDataset互换的功能。<br>  主键生成机制，分页存取功能，生成子集功能，及懒装载功能，压缩传输流功能等，同步数据更新问题等。这要你自己去发挥吧。<br>   说了这么多，话题转回来吧。现在说客户端怎么去存取数据。<br>在前面中间层已经定义了IBusinessService, 定义一个方法。getvoList，这个就是通用存取数据的接口了。<br>下面看看他的完整形式：<br>procedure getvoList(const sBOName: WideString; const sBOService: WideString; <br> out voListObj: OleVariant);   <br>这里有三个参数，sBOName:sBOService:voListObj: <br>干什么用的？第一个就是业务对象名称， 第二个是业务对象服务名称，<br>第三个是传回来的olevariant;<br>   强调一点。sBOName:sBOService:这两个参数并不直接对应中间层的业务对象。之间加了一个转换层。也就是service定位层。这个东西把客户传来的两个参数定位到相应的业务对象中。有什么好处呢。其实就相当于客户端和中间层的一个简单的协议，客户端发一个boname,一个服务名，这都是约定的。也就是不变的。以后该业务要变，就十分方便，只需要在中间层的定位器，配置一下就可以了，如果采用XML或文件配置，不需要修改任何程序，客户的业务已经发生改变。当然会采用名字调用等技术了。相关代码如下：<br>TBOService= class(TServiceObject)<br> private<br>//srvOBName : String;<br>IBasBO: IBaseBO;<br>BOPool: TBOPrototype; //业务对象持久池：<br>public<br>constructor Create;<br>procedure getvoList(const sBOName: WideString; const sBOService: WideString;<br>out voListObj: OleVariant); safecall;<br>  再说说TBOPrototype吧 ，这个东西是管理业务对象池的。由他统一创建业务对象。采用的是单例模式。<br>之后具体的调用，相关代码如下：<br>if FindClass(fClsPer.ClassName) &lt;&gt; nil then<br>begin<br>  tmpPer := TPersistentClass(FindClass(fClsPer.ClassName)).Create;<br>  Supports(tmpPer, StringToGUID('{3AE5EA91-41EA-41E7-B40C-CF00F8B75F8A}'), IBasBO);<br>  try<br>  IBasBO.InitBusinessObj;<br> voListObj := IBasBO.GetDAOValueObject.getDAOValueList;<br> finally<br> IBasBO := nil;<br> end;<br>end<br> else<br> ShowMessage('no found!');<br>其中IBasBO，是一个接口定义，<br>IBaseBO = interface(IUnknown)<br>['{3AE5EA91-41EA-41E7-B40C-CF00F8B75F8A}']<br> function GetObject: TObject;<br>procedure SetObject( value: TObject );<br>function GetDAOValueObject: TDAOValueObject;<br> procedure SetDAOValueObject(tmpDAOVO: TDAOValueObject);<br> procedure InitBusinessObj;<br>end;<br>呵呵，现在可以看到冰山一角了吧。<br>  经过业务对象初始化之后，他就去创建DAO了。。。呵呵。 如果你不了解DAO，看看相关的资料吧。。。。。<br>主要功能就是把数据存储隐藏起来，调用SQL， ORACLE，之类。我主要是用它调用数据库工厂创建。<br> 大致看一下代码吧。<br>//--------------------------------------------------------------------------<br>//1.工厂基类(SQLServer工厂类）<br>//--------------------------------------------------------------------------<br><br>unit ConnDBFactory_SQLServer;<br>interface<br>uses<br>  Classes, ADODB, ConnDB, DB, DBTables, Controls, Dialogs, IConnDB, ConnDBFactory;<br>type<br>TConnBDEDBFactory_SQLServer = class(TConnDBFactory)<br>public<br>  function CreatorConnDB() :IConnDataBase; override;<br>end;<br>TConnADODBFactory_SQLServer = class(TConnDBFactory)<br> public<br> function CreatorConnDB() :IConnDataBase; override;<br> end;<br>又扯远了，还是再回来吧。中间层的定位器通用业务对象管理器创建或获得一个业务对象之后，定位到相应的服务上去。比如数据存取。这里有一点说明：就是业务对象的数据存取和业务服务是分开的。 数据存取就采用DAO的方法。<br>直接一点说就是创建DAO对象。<br> 这是  TDAOValueObject= class(TPersistent, IDAOValueObject)<br> private..<br>.............<br> 上面的是基类。完成基础服务的。看看接口吧。<br>IDAOValueObject = interface(IUnknown)<br> ['{DF03C9E7-2A5B-4E32-8EF5-C4E8FC77E8BB}']<br> function createDAOValue: TValueObject;<br> function insertDAOValue(pValueObject: TValueObject): Integer;<br>function updateDAOValue(pValueObject: TValueObject) :Integer;<br> function deleteDAOValue(pValueObject: TValueObject) :Integer;  <br> function findByPrimaryKey(const pServiceName: WideString;  vKey: OleVariant): TValueObject;<br>  function getDAOValueList: OleVariant;  overload;<br>  function getDAOValueList(sSQL: String): OleVariant;  overload;<br>看看干了什么。。。。<br>inherited Create;<br>sqlAnySrvObj := TSQLAnalyzeService.Create;<br>if not assigned(VOList) then<br> VOList := TValueObjectList;<br> VOList.pVOClassName := ‘TUSERVO’<br>  创建了一个SQL分析器。 一个VOLIST对象， 并且传了一个VO名字。。<br>  TSQLAnalyzeService，SQL分析器可以动态的生成SQL脚本。。<br>再看看<br>    function getDAOValueList: OleVariant;  overload;<br>    function getDAOValueList(sSQL: String): OleVariant;   <br>这两个函式吧。 把生成的VO， olevariant化。  <br>这些基础的工作， 已经由VOLIST做了。 <br>重要的一点：prepareTable，这是VOLIST中的函式，由他动态的生成TDATASET， 当然没必要在中间层生成。但可以打包传给客户端，就OK了。<br>现在在看一下客户端的代码吧：<br> MyInterface2.getvoList('TUserBO', '' , oo);<br> pp := TValueObjectList.Create;<br> pp.OLEToDS(oo);<br>dataSource1.DataSet := pp.pDataSet;<br> 呵呵，PP是公共的TVOLIST，发布到客户端。 通由Ole，自动生成了TDATASET。<br> 想用对象，没问题，看下面：<br>定义：   ss: TVALUEOBJECT;<br>ss := TUserVO(pp.GetItem(1));<br> if ss&lt;&gt;nil then<br> ShowMessage((ss as TUserVO).pName); <br>之后，你想怎么样就怎么样了。。。。。<br> 呵呵，下次再讲讲业务逻辑方面吧，希望给做DELPHI三层的兄弟一个参考<br> <!--v:3.2--> ]]></description>
<category><![CDATA[编程技术]]></category>
<author><![CDATA[270549948@qq.com(ぺ城市蚂蚁ǎ)]]></author>
<comments>http://270549948.qzone.qq.com/blog/6#comment</comments>
<qz:effect>512</qz:effect>
<pubDate>Tue, 17 Apr 2007 07:41:43 GMT</pubDate>
<guid>http://270549948.qzone.qq.com/blog/6</guid>
</item>

<item>
<title><![CDATA[Java程序测试]]></title>
<link>http://270549948.qzone.qq.com/blog/5</link>
<description><![CDATA[随着Internet的日益普及，现在基于B/S结构的大型应用越来越多，可如何对这些应用进行测试成为日益迫切的问题。有许多测试人员来信问我B/S的测试如何做，由于工作较繁忙，对大家提出的问题也是头痛医头脚痛医脚，没有对WEB的测试过程做一个整体的概述。希望通过本篇能够让大家了解大型Web应用是如何来进行测试的。 <br><br>　　B/S下的功能测试比较简单，关键是如何做好性能测试。目前大多数的测试人员认为只要跑一些测试工具证明我的产品是可以达到性能的就ok了，为了证明而去测试是没有任何价值的，关键是要发现产品性能上的缺陷，定位问题，解决问题，这才是测试要做的。 <br><br>　　首先我们从两个方面分析如何进行WEB测试，从技术实现上来讲一般的B/S结构，无论是.NET还是J2EE,都是多层构架，有界面层，业务逻辑层，数据层。而从测试的流程上来说，首先是发现问题，分析问题，定位问题，再由开发人员解决问题。那么B/S的结构的测试如何来做？ <br><br>　　如何发现问题是我首先要介绍的，在做WEB测试之前你需要一些资料，比如产品功能说明书，性能需求说明书，不一定很完善，但一定要有，明确测试目标，这是基本的常识，可是我往往看到的是已经开始动手测了，但还不知自己的系统要达到的性能指标是什么。这里我简单讲一下测试的性能指标： <br><br>　　1、通用指标（指Web应用服务器、数据库服务器必需测试项）: <br><br>　　* ProcessorTime: 指服务器CPU占用率，一般 平均达到70%时，服务就接近饱和； <br><br>　　* Memory Available Mbyte : 可用内存数，如果测试时发现内存有变化情况也要注意，如果是内存泄露则比较严重； <br><br>　　* Physicsdisk Time : 物理磁盘读写时间情况； <br><br>　　2、Web服务器指标： <br>　　 <br>　　* Avg Rps: 平均每秒钟响应次数＝总请求时间 / 秒数； <br><br>　　* Avg time to last byte per terstion （mstes）:平均每秒业务角本的迭代次数 ,有人会把这两者混淆； <br><br>　　* Successful Rounds：成功的请求； <br><br>　　* Failed Rounds ：失败的请求； <br><br>　　* Successful Hits ：成功的点击次数； <br><br>　　* Failed Hits ：失败的点击次数； <br><br>　　* Hits Per Second ：每秒点击次数； <br><br>　　* Successful Hits Per Second ：每秒成功的点击次数； <br><br>　　* Failed Hits Per Second ：每秒失败的点击次数； <br><br>　　* Attempted Connections ：尝试链接数； <br><br>　　3、数据库服务器指标： <br><br>　　* User 0 Connections ：用户连接数，也就是数据库的连接数量； <br><br>　　* Number of deadlocks：数据库死锁； <br><br>　　* Butter Cache hit ：数据库Cache的命中情况； <br><br>　　上面的指标只是一些通用的指标,起到抛砖引玉的作用，对于不同的应用你还必需作相应的调整，比如程序使用的是.NET技术的，则必需加入一些针对性的测试指标。对于这些指标的详细了解，你可以参考Windows 下面的 SystemMonitor的帮助与LoadRunner、ACT的帮助。对于发现问题，指标的设置非常重要，它会帮你定性的发现一些错误。对于定性的压力测试我就不做过多的分析，工具很多，流行的主要有LoadRunner,ACT,WAS,WebLoad,各个工具有它的使用范围，其中我各个认为LoadRunner 最全面，它提供了多种协议的支持，对复杂的压力测试都可以胜任，WAS与ACT则对微软的技术支持的比较好，其中WAS支持分布式机群测试,ACT则是与.NET集成比较好，支持ViewState （.NET 下控件缓存的支持） 的测试，当时我用时，其它测试工具还不支持，现在应该支持了吧。 <br><br>　　在这一阶段测试你要不断的跟据系数的测试目标进行变化，一开始由于系统过于庞大，所以我们要分成若干个子系统，各个子系统的性能目标必需明确，主要是并发指标定一个阀值，同时设定一些与系统相关的测试参数，应用服务器，数据库服务器都要有，对达不到阀值的与一些通用参数有问题的子系统进行深入分析。比如它的并发达不到你的要求，证明子系统性能有问题，或是数据库用户连接过高，程序没有释放用户连接等等。 <br><br>　　这个我们要对子系统进行详细测试，由于B/S 结构下,图片的请求对性能的影响较大，所以我们对子系统测试时要分两个部分进行，一、非程序部分，即图片等等;二、应用程序本身。通过事务或函数的分离，可以把这两块实现单独的测试，具体做法参考各个工具的手册，我这里就不做说明。 <br><br>　　对子系统的测试参数的设置要求则更高，它有助你后面精确的定位问题，比如对异常，死锁，网络流量等等前面没有注意到的情况的增加，同时你要注意增加测试参数的收集对系统的性能影响比较大，所以一般不要超过10个，刚刚介绍的整体的性能测试指标也不要增加很多，这样影响会小一点。最后在这一阶段要说明的是数据库的数据量会很大程度的影响性能，所以要根据前面的性能需求说明书向数据库中模拟相应的数据量，来进行测试，这样才有更高的可信度。 <br><br>　　上面所说的是对问题的发现，下面就是分析问题原因，这一步的要求比较高，一般由测试人员与程序员配合完成，当然如果你有相当的开发经验，再做这方面的测试，就更为难得。下面我们说说如何精确定位问题，出现问题的可能性可能有很多种，大致分以下几种： <br><br>　　一、性能达不到目标； <br><br>　　二、性能达到目标，但有一些其它的问题，比如异常，死锁，缓存命中过低，网络流量较大； <br><br>　　三、服务器稳定性的问题，比如内存泄漏……。 <br><br>　　要发现这些问题起马的要求要有一款使用的比较称心的性能分析与优化工具，比如微软的.NET下就有自己开发的工具，对Borland的Java开发工具中也有类似的工具，但我个人认为更好的工具是Rose下的Purify与Quantify,主要是他对.net 与java ,C++都有支持，而且分析效果特别专业，我们先了解一下Rational Purify, Rational Purify 能自动找出Visual C/C++ 和Java 代码中与内存有关的错误，确保整个应用程序的质量和可靠性。在查找典型的Visual C/C++ 程序中的传统内存访问错误，以及Java，C# 代码中与垃圾内存收集相关的错误方面；Rational Quantity 则是一款针对函数级的性能分析利器，使用它你可以从图形化的界面中得到函数调用的时间，百分比与次数，以及子函数所占时间，使你可以更快的定位性能瓶颈。 <br><br>　　我们先说性能优化与异常的处理，性能优化有一个原则，即用时间比例最大的进行优化，效果才最明显，比如有个函数它的执行时间为30秒，如果你优化了一百倍则执行时间为0.3秒,提升了29.7秒，而如果它的执行时间为0.3秒，优化后为0.003秒，实际提升了0.297秒，提升的效果并不明显，而且写过程序的人都知道，后者性能优化的代价更大。在性能优化的过程中，一般是先数据库，后程序，因为数据库的优化不需要修改程序，修改的风险很小。但如何才能确定是数据库的问题，这就需要技巧，在使用Quantity时，你一路分析下去，大多数最终会发现，是数据库查询函数占用时间比较大，比如什么，SqlCmd.ExecuteNoQuery等等数据库执行函数,这时你就需要分析数据库。 <br><br>　　数据库的分析原则是先索引，后存储过程，最后表结构视图的优化，索引的优化是最简单也是通常最有效的方法，如果合理的使用会带来意想不到不到的效果。在这里我要给大家简单的介绍一下我的最爱，SQLProfile,SQL查询分析器，Precise,SQLProfile是一个SQL语句跟踪器，可以跟踪程序流程使用的SQL语句与存储过程，结合查询分析器对SQL的分析，可以对索引的优化做出很好的判断，但索引也不是万能的，在增删改较多的表，索引过多会引起这些操作的性能下降，所以判断还是需要一定的经验。 <br><br>　　同时针对用户使用频度最高的SQL进行优化也是最行之有效的，这时我则需要Precise，它可以观测某一个较长时间内的SQL语句的执行情况。数据库优化的潜能挖光后，如果还是达不到性能要求或是还有问题，则要从程序来进行优化，这是程序员做的事，测试人员要做的，就是告诉他们，哪个函数执行过多引起了性能下降，比如异常过多，某个循环过多，或是DCOM调用过多等等，但说服程序员也是一件不容易的事，你要在这一阶段做的出色一定要有几年的编程经验，并且要让程序员感到听你的性能会有提升，这是一件很不容易的事情。 <br><br>　　内存的分析，一般是一个长期分析的过程，要做好不容易，首先要有长期奋战的准备，其次内存泄漏的分析最好是放在单元测试之中同步进行，而不是要等到最后再去发现问题，当然出了问题也只好面对，一般这类问题都是在服务器运行了很久才暴露出来，一旦发现问题后，则需要定位问题，分析的原则采用子系统相互独立运行，找到最小问题的系统集,或是借助内存分析工具观察内存对象情况，初步定位问题，再用Purify进行运行时分析，通常C++ 内存问题比较多，Java与.NET比较少，一般由GC不合理引起。C++的内存错误就比较多了，主要常见的有: <br><br>　　1、 Array Bounds Read (ABR) ：数组越界读 <br><br>　　2、 Array Bounds Write (ABW)：数组越界写 <br><br>　　3、 Beyond stack Read (BSR)：堆栈越界读 <br><br>　　4、 Free Memory Read(FMR)：空闲内存读 <br><br>　　5、 Invalid pointer Read(IPR)：非法指针阅读 <br><br>　　6、 Null Pointer Read(NPR)： 空指针阅读 <br><br>　　7、 Uninitialized Memory Read(UMR)：未初始化内存读写 <br><br>　　8、 Memory Leak：内存泄漏  <!--v:3.2--> ]]></description>
<category><![CDATA[编程技术]]></category>
<author><![CDATA[270549948@qq.com(ぺ城市蚂蚁ǎ)]]></author>
<comments>http://270549948.qzone.qq.com/blog/5#comment</comments>
<qz:effect>512</qz:effect>
<pubDate>Sun, 15 Apr 2007 09:10:26 GMT</pubDate>
<guid>http://270549948.qzone.qq.com/blog/5</guid>
</item>

<item>
<title><![CDATA[构造java函数]]></title>
<link>http://270549948.qzone.qq.com/blog/4</link>
<description><![CDATA[每次在创建实例变量，对类中的所有变量都要初始化是很乏味的。即使你对setDim ( ) 这样的方法增加有用的功能时，你也不得不这样做。如果在一个对象最初被创建时就把对它的设置做好，那样的话，程序将更简单并且更简明。因为对初始化的要求是共同的，Java 允许对象在他们被创造时初始化自己。这种自动的初始化是通过使用构造函数来完成的。<br><br>构造函数（constructor ）在对象创建时初始化。它与它的类同名，它的语法与方法类似。一旦定义了构造函数，在对象创建后，在new运算符完成前，构造函数立即自动调用。构造函数看起来有点奇怪，因为它没有任何返回值，即使是void 型的值也不返回。这是因为一个类的构造函数内隐藏的类型是它自己类的类型。构造函数的任务就是初始化一个对象的内部状态，以便使创建的实例变量能够完全初始化，可以被对象马上使用。<br><br>你可以重写Box 例子程序，以便当对象创建时盒子的尺寸能被自动地初始化。为了达到这个目的，用构造函数代替setDim 。让我们由定义仅仅将每个盒子的尺寸设置为同样值的一个简单的构造函数开始。示例如下：<br><br>/* Here，Box uses a constructor to initialize the <br><br>dimensions of a box.<br>*/<br>class Box {<br><br><br>double width; double height; double depth; <br><br>// This is the constructor for Box. <br>Box() { <br>System.out.println(&quot;Constructing Box&quot;); <br><br><br>width = 10;<br>height = 10;<br>depth = 10;<br><br><br>} <br><br>// compute and return volume double volume() { return width * height * depth;}} <br><br>class BoxDemo6 {<br><br>public static void main(String args[]) { // declare，allocate，and initialize Box objectsBox mybox1 = new Box();Box mybox2 = new Box(); <br><br>double vol; <br><br>// get volume of first box<br>vol = mybox1.volume();<br>System.out.println(&quot;Volume is &quot; + vol); <br><br><br>// get volume of second box<br>vol = mybox2.volume();<br>System.out.println(&quot;Volume is &quot; + vol);<br><br><br>}<br>} <br><br><br>运行该程序，产生如下的结果：<br><br>Constructing Box<br>Constructing Box<br>Volume is 1000.0 <br>Volume is 1000.0 <br><br><br>正如你能看到的一样，当mybox1 和mybox2 被创建时，它们两个都被Box 构造函数初始化。因为构造函数将所有的盒子赋为一样的尺寸，长、宽、高都是10，mybox1 和 mybox2 将有一样的体积。在Box( )内的println( ) 语句仅仅是为说明的缘故。大多数构造函数的功能不显示任何东西，他们仅简单地初始化一个对象。<br><br>在继续学习前，让我们再考察new运算符。你已经知道，当分配一个对象时，使用下面的通用格式：<br><br>class-var = new classname( ); <br><br>现在你可以理解为什么在类的名字后面需要圆括号。圆括号的作用是调用该类的构造函数。这样，在下面的这行中<br><br>Box mybox1 = new Box(); <br><br>new Box( ) 调用Box( )构造函数。如果你不显式为类定义一个构造函数，Java 将为该类创建一个默认的构造函数。这就是本行程序在Box早期版本没有定义构造函数工作的原因。<br>默认构造函数自动地将所有的实例变量初始化为零。默认构造函数对简单的类是足够的，但是对更复杂的类它就不能满足要求了。一旦你定义了你自己的构造函数，默认构造函数将不再被使用。<br><br>6.5.1 带自变量的构造函数<br>虽然在前面的例子中，Box构造函数确实初始化了Box对象，但它不是很有用，因为所有的盒子都是一样的尺寸。我们所需要的是一种能够构造各种各样尺寸盒子对象的方法。比较容易的解决办法是对构造函数增加自变量。你可能已经猜到，这将使他们更有用。例如，下面版本的Box程序定义了一个自变量构造函数，它根据自变量设置每个指定盒子的尺寸。特别注意Box 对象是如何被创建的。<br><br>/* Here，Box uses a parameterized constructor to<br><br>initialize the dimensions of a box. <br>*/<br>class Box {<br><br><br>double width; double height; double depth; <br><br>// This is the constructor for Box. <br><br>Box(double w，double h，double d) {width = w;height = h;depth = d;<br><br>} <br><br>// compute and return volume double volume() { return width * height * depth;}} <br><br>class BoxDemo7 {<br><br>public static void main(String args[]) { // declare，allocate，and initialize Box objectsBox mybox1 = new Box(10，20，15);Box mybox2 = new Box(3，6，9); <br><br>double vol; <br><br>// get volume of first box<br>vol = mybox1.volume();<br>System.out.println(&quot;Volume is &quot; + vol); <br><br><br>// get volume of second box<br>vol = mybox2.volume();<br>System.out.println(&quot;Volume is &quot; + vol);<br><br><br>}<br>} <br><br><br>该程序的输出如下：<br><br>Volume is 3000.0 <br>Volume is 162.0 <br><br><br>正如你看到的，每个对象被它的构造函数指定的参数初始化。例如，在下行中，<br><br>Box mybox1 = new Box(10，20，15); <br><br>当new创建对象时，值10，20，15传递到Box() 构造函数。这样，mybox1 的拷贝width 、height 、depth 将分别包含值10、20、15。 <!--v:3.2--> ]]></description>
<category><![CDATA[编程技术]]></category>
<author><![CDATA[270549948@qq.com(ぺ城市蚂蚁ǎ)]]></author>
<comments>http://270549948.qzone.qq.com/blog/4#comment</comments>
<qz:effect>512</qz:effect>
<pubDate>Sun, 15 Apr 2007 09:09:22 GMT</pubDate>
<guid>http://270549948.qzone.qq.com/blog/4</guid>
</item>

<item>
<title><![CDATA[整合Java与XML的新应用]]></title>
<link>http://270549948.qzone.qq.com/blog/2</link>
<description><![CDATA[XML(eXtensible Markup Language，可扩展的标记语言)是万维网联盟（W3C）创建的一组规范，用于在Web上组织、发布各种信息。它不仅可以满足迅速增长的网络应用的需求，还能够确保网络进行交互操作时具有良好的可靠性与互操作性。 <br><br>XML的语法类似HTML，都是用标签来描述数据的。HTML的标签是固定的，我们只能使用，不能修改。XML则不同，它没有预先定义好的标签可以使用，而是依据设计上的需要自行定义标签。XML是一个元语言，根据不同的行业和语义，可以派生出许许多多的协议和规范。目前的基本协议有XSL、XLink/Xpointer、Xpath、XHTML、Schema等。不同的行业和领域都可以制定自己的XML规范，用于横向和纵向的信息交流和数据传输。XML规范有大有小，大的可以为全世界范围内的商务数据制定格式，像ebXML、Biztalk、eCo；小的有专门用于电子钱包的ECML，有为数学制定的MathML；还有为多媒体数据同步的SMIL，像XSL是专门用于显示的，它制定了许多有显示语义的标签；而XLink是描述文档之间关系的语言。像Micrsoft 的CDF(Channel Definition Format)推送频道“PUSH”技术应用、WML(Wireless Market Language)无线商务应用等等都是XML技术的具体应用。XML给基于Web的应用软件赋予了强大的功能和灵活性，因此它给开发者和用户带来了许多好处。利用XML用户可以方便地进行本地计算和处理。XML格式的数据发送给客户后，客户可以用应用软件解析数据并对数据进行编辑和处理。使用者可以用不同的方法处理数据，而不仅仅是显示它。XML文档对象模式(DOM)允许用脚本或其它编程语言处理数据，数据计算不需要回到服务器就能进行。XML可以被利用来分离使用者观看数据的界面，使用简单灵活开放的格式，可以给Web创建功能强大的应用软件。 <br><br>XML核心功能的有关特性和规范如下： <br><br>1. 格式良好的(Well-Formed)XML文档； <br><br>2. 文档类型定义(DTD)； <br><br>3. XML使用样式?CSS(Cascading Style Sheet，层叠样式表单)和XSL(eXtensible Style Language，可扩展样式语言)； <br><br>4. 文档对象模型(DOM)?XML编程接口； <br><br>5. XML 简单API(SAX)?XML编程接口； <br><br>6. XML 命名空间(Namespace)和模式(Schema)； <br><br>7. 链接(XLink)和查询； <br><br>8. XPath(XML Path Language) 和 XPointer(XML Pointer Language)； <br><br>9. 转换XML?XSL和XSLT(XSL Transformation)； <br><br>10. XML 和数据库； <br><br>11. 用于服务器协议? XML-RPC、SOAP(Simple Object Access Protocol，简单对象访问协议)和WDDX(Web Distributed Data Exchange，分布式Web 数据交换)。 <br><br>XML 是一种具有描述数据功能的语言，它十分适合作为知识表示语言或作为组件及文件格式的表示方法。它还可以让数据在不同的来源中，根据通用的语法规则来处理。而Java则是用于Internet、适合于分布式环境、提供了一个跨平台的语言。XML和Java相结合主要原因是基于XML的语法提供了一种灵活的、标准的、健壮的Java编程方案，同时，Java也将一种普遍的语义集合应用于XML数据。既然Java和XML都是可移植的标准，这两种技术结合的结果也是可移植的，可以重用数据和移植行为。单独使用XML或Java所能获得的所有潜力还没有被完全掌握，将它们结合就走进了一个巨大的、新的国度。将XML应用于Java的两个主要的应用是面向表示的出版业和企业中面向消息的中间件技术。 <br><br>Java和XML是在为不同客户开发Web程序时形成得自然的匹配。从传统的电话到最新的智能冰箱，利用和产生的信息都是在不同的系统平台的服务器上交换。XML和Java的方便性和可延展性使它们在新的Web上具有更多的功能： <br><br>1. 结构化?建立有任何复杂层次的数据模型； <br><br>2. 可扩展性?根据需要定义新的标志； <br><br>3. 验证?检查数据在结构上的正确性； <br><br>4. 独立与媒介?以多种方式发布内容； <br><br>5. 独立于供应商和平台?使用标准的商业软件，甚至文本工具处理任何符合(XML标准)的文档。 <br><br>上述这些功能使得XML技术被期望给面向网络的应用，特别是在数据交换领域带来革命性的影响。Java 与XML一起使得新一代Web应用成为可能。<br><br>Java 与 XML 的结合应用<br><br><br>建立一个良构(Well-Formed)的XML 文档及验证的实例 <br><br>对于一个XML文件是否符合Well-Formed 所规定的各项XML 基本语法，必须借助XML 分析器来加以检查。比较常见的XML 分析器有Xerces、JAXP 和MSXML。 <br><br>一个XML 文档是有明显特征的。下面是一个XML 文档的实例People.xml，代码如下： <br><br>&lt;? xml version=&quot;1.0&quot; encoding=&quot;GB2312&quot;? &gt;<br>&lt;PeopleInfo&gt;<br>&lt;People PeopleId=&quot;YOUR&quot;&gt;<br>&lt;PeopleName&gt; 古董 &lt;/PeopleName&gt;<br>&lt;PeopleSex&gt; 男 &lt;/PeopleSex&gt;<br>&lt;PeopleAge&gt; 23 &lt;/PeopleAge&gt;<br>&lt;/People&gt;<br>&lt;People PeopleId=&quot;SHEN&quot;&gt;<br>&lt;PeopleName&gt; 王冠 &lt;/PeopleName&gt;<br>&lt;PeopleSex&gt; 女 &lt;/PeopleSex&gt;<br>&lt;PeopleAge&gt; 25 &lt;/PeopleAge&gt; <br>&lt;/People&gt;<br>&lt;/PeopleInfo&gt;<br>     <br> <br> <!--v:3.2--> ]]></description>
<category><![CDATA[编程技术]]></category>
<author><![CDATA[270549948@qq.com(ぺ城市蚂蚁ǎ)]]></author>
<comments>http://270549948.qzone.qq.com/blog/2#comment</comments>
<qz:effect>512</qz:effect>
<pubDate>Sat, 06 Jan 2007 12:45:52 GMT</pubDate>
<guid>http://270549948.qzone.qq.com/blog/2</guid>
</item>

<item>
<title><![CDATA[心语]]></title>
<link>http://270549948.qzone.qq.com/blog/1</link>
<description><![CDATA[    不知道以我现在的年岁还叫不叫豆蔻年华，但我觉的已经荒废了好多的时间了，人的一生走着一条很奇怪的路线：从无知慢慢变得有知，再从有知慢慢又变得无知。 <br>　　从小受到的教育是要与命运斗争，可长这么大了，也没见过他长的什么样，还是不明白为什么要和他斗，只是觉得很累很累。现在唯一想做的事情，就是不顾一切地逃离这个被夜晚华丽的灯光掩饰的城市，远远地逃开。想做归想做，也仅仅是想一想罢了。所以还是现实一点，唯一能做的也就剩下收拾好东西，明天接着挤公车去上班了。 <br>　　本来打算写一点“努力，奋斗”之类的话，无奈实在是不记得小学中学的语文老师都教过什么了，所以只好作罢，只能乱七八糟的写了一点不知所谓的话。其实，不必说什么为了理想的大话,理想也仅仅是理想罢了。 <br>　　这么多年，多多少少沉淀了一点岁月，只希望接着走的路，少一点浮躁，多一份坚持。 <!--v:3.2--> ]]></description>
<category><![CDATA[个人日记]]></category>
<author><![CDATA[270549948@qq.com(ぺ城市蚂蚁ǎ)]]></author>
<comments>http://270549948.qzone.qq.com/blog/1#comment</comments>
<qz:effect>512</qz:effect>
<pubDate>Fri, 21 Oct 2005 15:57:01 GMT</pubDate>
<guid>http://270549948.qzone.qq.com/blog/1</guid>
</item>

</channel>
</rss>

