“未来的世界:方向比努力重要,能力比知识重要,健康比成绩重要,生活比文凭重要,情商比智商重要! ”    ——清华大学校长留给毕业生的一段话

发布新日志

  • 外企英语面试常见问题

    2007-08-13 17:25:31

    在英语面试中给面试官留下一个非常好的印象吗?首先要听懂对方的问题。为了避免误解面试官的问题,我们为你准备了一张问题清单,不妨先来看看。   Tell us about yourself.  
      这是一个有关你个性、背景、学习以及工作经历的非常宽泛的问题。你可以准备一个简洁的回答。
      
      Why should we hire you?
       招聘者正在问有关你的特点和强项的问题。当然,对求职的公司也要有所了解,你的加入要给对方带来效益才好。   
      Why did you leave your last job?
      面试人员想要知道你是辞职的,还是被辞退的,或是下岗的,并希望了解原因。你最好实话实说,职场讲究诚信。   
      Are you willing to relocate?
      这代表着你是否愿意移居另一个城市或国家。   
      Tell me about your scholastic record.
      这是指你在学校及大学所学的学科和成绩。  Tell me about your extra-cur-ricular activities and interests.
      这是在问你业余都做些什么和你的兴趣,例如运动、音乐或旅游等。一个热爱生活的人也会以很好的热情投入工作。现在,很多企业都比较注意了解求职者的爱好,从外围来考察一个人的综合素质。   
      How would your last boss describe you?
       这句话的意思是你的上个老板是如何看待你的。最好作客观陈述,包括前任老板对你的工作和为人的评价。   
      What salary are you expecting?
      招聘者想要知道你对薪资的最低要求。恭喜你,话谈到这里,说明对方对你已经很有兴趣了。别狮子大开口,也别委屈了自己。给自己和对方都留点余地。
  • 常见问题 解决

    2007-08-13 02:21:16

  • 提示:ActiveX 部件不能创建对象: Scripting.FileSystemObject

    2007-08-13 02:20:02

    解决方法:

    开启/关闭系统FSO支持方法
    windows98系统

    在DOS命令行状态输入以下命令:

    关闭命令:RegSvr32 /u C:\WINDOWS\SYSTEM\scrrun.dll

    打开命令:RegSvr32 C:\WINDOWS\SYSTEM\scrrun.dll

    win2000系统:

    在CMD命令行状态输入以下命令:

    关闭命令:RegSvr32 /u C:\WINNT\SYSTEM32\scrrun.dll

    打开命令:RegSvr32 C:\WINNT\SYSTEM32\scrrun.dll


    我的设置步骤:IIS中“属性”--目录安全性--匿名访问和验证控制--编辑---匿名访问--编辑--用户名:Administrator--允许IIS控制密码前打勾

    win2003
    运行regsvr32 scrrun.dll即可。

    如果想关闭FSO组件,请运行 regsvr32 /u scrrun.dll即可。

  • VBScript语法简介

    2007-08-12 23:14:26

    VBscrīpt语句是一种基于VB的一种脚本语言,主要用于WEB服务器端的程序开发,我们
    这里只介绍一些简单的语句,主要是操作数据库的几种常见的语句
    <1>.vbscrīpt的标识
    <%
    语句
    ……
    %>
    <2>定义变量dim语句
    <%
    dim a,b
    a=10
    b=”ok!”
    %>
    注意:注意:定义的变量可以是数值型,也可以是字符或者其他类型的
    <3>简单的控制流程语句
    1. If 条件1 then
    语句1
    elseif 条件2 then
    语句2
    else
    语句3
    endif
    2.while 条件
    语句
    wend
    3.for count=1 to n step m
    语句1
    exit for
    语句2
    next
    二.ASP数据库简单操作教程
    <1>.数据库连接(用来单独编制连接文件conn.asp)
    <%
    Set conn = Server.CreateObject(”ADODB.Connection”)
    conn.Open “DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=” & Server.MapPath(”\bbs\db1\user.mdb”)
    %>
    (用来连接bbs\db1\目录下的user.mdb数据库)
    <2>显示数据库记录
    原理:将数据库中的记录一一显示到客户端浏览器,依次读出数据库中的每一条记录
    如果是从头到尾:用循环并判断指针是否到末 使用: not rs.eof
    如果是从尾到头:用循环并判断指针是否到开始 使用:not rs.bof

    <!–#include file=conn.asp–> (包含conn.asp用来打开bbs\db1\目录下的user.mdb数据库)
    <%
    set rs=server.CreateObject(”adodb.recordset”) (建立recordset对象)
    sqlstr=”select * from message” —->(message为数据库中的一个数据表,即你要显示的数据所存放的数据表)
    rs.open sqlstr,conn,1,3 —->(表示打开数据库的方式)
    rs.movefirst —->(将指针移到第一条记录)
    while not rs.eof —->(判断指针是否到末尾)
    response.write(rs(”name”)) —->(显示数据表message中的name字段)
    rs.movenext —->(将指针移动到下一条记录)
    wend —->(循环结束)
    ——————————————————
    rs.close
    conn.close 这几句是用来关闭数据库
    set rs=nothing
    set conn=nothing
    ——————————————————-
    %>
    其中response对象是服务器向客户端浏览器发送的信息
    <3>增加数据库记录
    增加数据库记录用到rs.addnew,rs.update两个函数
    <!–#include file=conn.asp–> (包含conn.asp用来打开bbs\db1\目录下的user.mdb数据库)
    <%
    set rs=server.CreateObject(”adodb.recordset”) (建立recordset对象)
    sqlstr=”select * from message” —->(message为数据库中的一个数据表,即你要显示的数据所存放的数据表)
    rs.open sqlstr,conn,1,3 —->(表示打开数据库的方式)
    rs.addnew 新增加一条记录
    rs(”name”)=”xx” 将xx的值传给name字段
    rs.update 刷新数据库
    ——————————————————
    rs.close
    conn.close 这几句是用来关闭数据库
    set rs=nothing
    set conn=nothing
    ——————————————————-

    %>
    <4>删除一条记录
    删除数据库记录主要用到rs.delete,rs.update
    <!–#include file=conn.asp–> (包含conn.asp用来打开bbs\db1\目录下的user.mdb数据库)
    <%
    dim name
    name=”xx”
    set rs=server.CreateObject(”adodb.recordset”) (建立recordset对象)
    sqlstr=”select * from message” —->(message为数据库中的一个数据表,即你要显示的数据所存放的数据表)
    rs.open sqlstr,conn,1,3 —->(表示打开数据库的方式)
    ——————————————————-
    while not rs.eof
    if rs.(”name”)=name then
    rs.delete
    rs.update 查询数据表中的name字段的值是否等于变量name的值”xx”,如果符合就执行删除,
    else 否则继续查询,直到指针到末尾为止
    rs.movenext
    end if
    wend
    ——————————————————
    ——————————————————
    rs.close
    conn.close 这几句是用来关闭数据库
    set rs=nothing
    set conn=nothing
    ——————————————————-
    %>
    <5>关于数据库的查询
    (a) 查询字段为字符型
    <%
    dim user,pass,qq,mail,message
    user=request.Form(”user”)
    pass=request.Form(”pass”)
    qq=request.Form(”qq”)
    mail=request.Form(”mail”)
    message=request.Form(”message”)
    if trim(user)&”x”=”x” or trim(pass)&”x”=”x” then (检测user值和pass值是否为空,可以检测到空格)
    response.write(”注册信息不能为空”)
    else
    set rs=server.CreateObject(”adodb.recordset”)
    sqlstr=”select * from user where user=’”&user&”‘” (查询user数据表中的user字段其中user字段为字符型)
    rs.open sqlstr,conn,1,3
    if rs.eof then
    rs.addnew
    rs(”user”)=user
    rs(”pass”)=pass
    rs(”qq”)=qq
    rs(”mail”)=mail
    rs(”message”)=message
    rs.update
    rs.close
    conn.close
    set rs=nothing
    set conn=nothing
    response.write(”注册成功”)
    end if
    rs.close
    conn.close
    set rs=nothing
    set conn=nothing
    response.write(”注册重名”)
    %>
    (b)查询字段为数字型
    <%
    dim num
    num=request.Form(”num”)
    set rs=server.CreateObject(”adodb.recordset”)
    sqlstr=”select * from message where id=”&num (查询message数据表中id字段的值是否与num相等,其中id为数字型)
    rs.open sqlstr,conn,1,3
    if not rs.eof then
    rs.delete
    rs.update
    rs.close
    conn.close
    set rs=nothing
    set conn=nothing
    response.write(”删除成功”)
    end if
    rs.close
    conn.close
    set rs=nothing
    set conn=nothing
    response.write(”删除失败”)
    %>
    <6>几个简单的asp对象的讲解
    response对象:服务器端向客户端发送的信息对象,包括直接发送信息给浏览器,重新定向URL,或设置cookie值
    request对象:客户端向服务器提出的请求
    session对象:作为一个全局变量,在整个站点都生效
    server对象:提供对服务器上方法和属性的访问
    (a) response对象的一般使用方法
    比如:
    <%
    response
    .write(”hello, welcome to asp!”)
    %>
    在客户端浏览器就会看到 hello, welcome to asp! 这一段文字
    <%
    response.Redirect(”www.sohu.com“)
    %>
    如果执行这一段,则浏览器就会自动连接到 “搜狐” 的网址
    关于response对象的用法还有很多,大家可以研究研究
    request对象的一般使用方法
    比如客户端向服务器提出的请求就是通过request对象来传递的
    列如 :你在申请邮箱的所填写的个人信息就是通过该对象来将
    你所填写的信息传递给服务器的
    比如:这是一段表单的代码,这是提供给客户填写信息的,填写完了按
    “提交”传递给request.asp文件处理后再存入服务器数据库
    <form name=”form1″ method=”post” action=”request.asp”>
    <p>
    <input type=”text” name=”user”>
    </p>
    <p>
    <input type=”text” name=”pass”>
    </p>
    <p>
    <input type=”submit” name=”Submit” value=”提交”>
    </p>
    </form>
    那么request.asp该如何将其中的信息读入,在写入数据库,在这里就要用到
    request对象了,下面我们就来分析request.asp的写法
    <%
    dim name,password (定义user和password两个变量)
    name=request.form(“user”) (将表单中的user信息传给变量name)
    password=request.form(“pass”) (将表单中的pass信息传给变量password)
    %>
    通过以上的几句代码我们就将表单中的数据读进来了,接下来我们要做的就是将
    信息写入数据库了,写入数据库的方法上面都介绍了,这里就不一一复述了。
  • QTP一些基础代码

    2007-08-12 22:41:04


    1 生产随机数列
    第一种方法-----------------------------------
    randomize'更新反回的数据
    funcation rand(k,n)
    n=int((k-1)*rnd+1)
    rand=n
    end funcation
    第二种方法
    n=randomnumber.value(1,255)
    2  当运行到表中的某一行,自动导出表中的所有数据
    row=datatable.getcurrentrow
    if row="5" then
      datatable.export("d:\data.xml")
    end if
    3  webedit("txtpass").setsecure"sdsdf...."
    如果参数化密码,可以直接在数据表中写入未加密的密码,它会自动识别,即不用把setsecure改为set
    4 如果弹出对话框就获取上面提示信息并与表中的信息对比,不统一证明弹出的提示出错,主要用来验证
     if browser("web_name".dialog("dialog_name").exist(1) then'如果不出现=false
         error_message=browser("web_name".dialog("diaglog_name".static("用户密码错误!").getRoproperty("text")
       if error_message<>(datatable.value("error_info"))then
             msgbox(error_message)
          end if
         browser("web_name").dialog("diaglog_name").close
      end if
    这里我总结了两点技巧:
     一是:对于dialog中,虽然提示信息对象名称是"用户密码错误",但如果信息对象名称是“该用户不存在”,不用更改会自动识别,我想主要是录制第一遍时,“用户密码错误”只是让运行时能找到这个控制,而不管它是什么内容,因为在对象仓库中,text不是决定该对象的属性
        二是:如果对于提示信息比较长的,可以用mid(error_message,n,m)取一部份特征提示信息进行验证,这样我想可以节省处理时间,又可以避免长度以及空格等字符的处理
    5 在运行时,向某一个单元格赋值: datatable.value("kai",dtlocalsheet)="nanjing"
    datatable.value("num")只在global形式下的一种省略形式;完整形式
    是datatable.value("num",dtlocalsheet)
    -----取得某一具体行的值:
    datatable.setcurrentrow(n);
    msgbox(datatable.getsheet("global").getparameter("kai").Rawvalue)
    或者kk=datatable.Rawvalue("kai","action1")
    -----在run-time期间,添加一个action和参数
    kk=datatable.addsheet("name").addparameter("kai","ddd").name'/value
    6 with dialog("name")'可以省好多代码,看着也简洁
         content=.wintreeview
       end with
    7  wintreeview.select(item)(根是0,列表第一个也是0)
       wintreeview.getcontent
       wintreeview.getitem(整行)+";"+
       winlistview.getitem(行中的第一个字符段)
       wincheckbox("").set"off"'/on
    8  数据库检查点:
    sub getdata
    set con=createobject("adodb.connection")
    con.open("descrīption=mod;driver=sqlserver;server=hp\sqlserver;uid=sa;"&_
             "pwd=11111;APP=qtp;WSID=hp;database=MOD31"  '用sqlserver方式
    Con.open "DRIVER = {Microsoft Access Driver (*.mdb)};DBQ=D:\Testdb.mdb" '用access方式
    set record=createobject("adodb.recordset")
    sql="select * from m3_program"       '选择具体满足一条件的:sql="select* from m3_program where "
    record.open sql,con          
    if(not record.eof) then
    record.movenext
    msgbox("p_name")
    end if
    record.close
    set record=nothing
    con.close
    set con=nothing
    end sub
    '如果没有查到内容,在结果中不会报错,也不会弹出窗口
    9 vbcr----chr(13)回车符
      vblf----chr(10)换行符
    vbcrlf----chr(13)+chr(10)结合
    10 从step run has two ways(一是在key-driven页面,另一个是在代码页面,前者走完项目,后者只是本acton第一行
    11 对于时间,日期等的格式检查(一种是正则表达式,另一种是输出对比,如果
     不好对比,用mid截取一部分对比)
    12对于一些列表框或树结构,如果发生结点名称发生变化,此时如果报没有彼配的对象,此时可以把更改后面的名称如_2"
    13;对于动态变化的对象,要分清是对像还是属性;对于属性可以用gettoproperty("ddd");得到;而对于由于动态无法识别对
    像可以用描述性脚本:
     如:Set ōbject= Descrīption.Create()
    Object("regexpwndclass").Value="HtmlButton"
    Object("regexpwndtitle").Value="登陆"
    browser("ss").page("a").button(Object).click
    14:对于属性是变化的,有时可以把该属性从识别对象里删除
    15:从系统的文件中获取信息及删除文件
      get_file_infor("c:\she.mpg")
       function get_file_infor(url)
        dim fso,f
        set fso=createobject("scrīpting.filesystemobject")
        set f=fso.getfile(url)
        msgbox(f.datecreated)
        f.name:f.size:f.type
        fso.deletefile(url)'/////删除文件
       end function
    --------获取文件夹里所有文件信息
    get_folder_infor("c:\kai")
    function get_folder_infor(folder)
    dim fso,f,f1,n
    set fso=createobject("scrīpting,filesystemobject")
    set f=fso.getfolder(folder)
    set fc=f.files
    for each f1 in fc
    select case f1.name
    case"kai.mpg","she.mpg","dd.mp3"
    end select
    next
    end function

    16,四舍五入可以在后面+0.5,进行自动解决
    17,y=-------waitproperty("visible",true,10000)
    18,on error resume next
       on error goto o
    19 window("").wintreeview("systreeview32").TYpe micctrldown+"p"+micctrlup
    20,定义数组 name=array(1,2,"aa","bb");name(0)=1
    21进行日期YYYY-MM-DD的格式检查 :
    Function RegExpTest(patrn, strng)
      Dim regEx, Match, Matches      ' Create variable.
      Set regEx = New RegExp         ' Create a regular expression.
      regEx.Pattern = patrn         ' Set pattern.
      regEx.IgnoreCase = True         ' Set case insensitivity.
      regEx.Global = True         ' Set global applicability.
      Set Matches = regEx.Execute(strng)   ' Execute search.
      For Each Match in Matches      ' Iterate Matches collection.
        RetStr = RetStr & "Match found at position "
        RetStr = RetStr & Match.FirstIndex & ". Match Value is '"
        RetStr = RetStr & Match.Value & "'." & vbCRLF
      Next
      RegExpTest = RetStr
    End Function
    date_pattern="^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((01,3-9])|(1[0-2]))-(29|30)))))$"
    result_message=RegExpTest(date_pattern, inputbox("请你输入要检查的时间:"))
    Select case result_message
    Case ""
    msgbox("你输入的日期格式与标准不匹配")
    case else  MsgBox(result_message)
    end select

     

     

  • 一个字符串反转的方法

    2007-08-12 16:45:47



    public String revese(String s)
    {
        StringBuffer sb=new StringBuffer();
        for(int i=s.length()-1;i>=0;i--)
        {
          sb.append(s.charAt(i));
        }
        return sb.toString();
    }

  • 数据库并发处理

    2007-08-12 16:38:00

     一、并发处理

    数据库的特点就是数据的集中管理和共享。在通常情况下总是有若干个事务并发地运行,这些并行的事务可能并发地存取相同的数据。因此,数据库管理系统的一个重要任务就是要有一种机制去保证这种并发的存取和修改不破坏数据的完整性,确保这些事务能正确地运行并取得正确的结果。

    我们知道,事务并发执行时若不加控制的话,将导致不正确的结果和数据库的不一致状态。为保证数据库数据正确地反映所有事务的更新,以及在一事务修改数据时其它事务不同时修改这个数据,数据库系统用锁来控制对数据的并发存取。

    二、ORACLE的并发处理机制

    无需任何说明,ORACLE自动提供行级锁,它允许用户在没有冲突的情况下更新表中不同的行。行级锁对联机事务处理非常有用。

    1ORACLE

    ORACLE锁的类型在正常情况下,ORACLE会自动锁住需要加锁的资源以保护数据,

    这种锁是隐含的,叫隐含锁。然而,在一些条件下,这些自动的锁在实际应用时并不能满足需要,必须人工加一些锁。这些人工加的锁叫显示锁。

    下面指明了会产生隐含锁的SQL语句:

    INSERT

    UPDATE

    DELETE

    DDL/DCL语句。

    下面指明了会产生显示锁的SQL语句:

    SELECT FOR UPDATE

    LOCK TABLE INXXX MODE

    解决读的不可重复性可以用下面的方法。在ORACLE中,用SELECT FOR UPDATE对预期要修改的记录加行排它锁(X),对表加行共享锁(RS)。它常用于要锁住一行,但不去真的修改这一行。锁之间是有相互作用的。

    例如,更新时会对表加RX锁,对行加X锁,而只有RS锁和RX锁允许再加RX锁。因此,当存在RSRX锁时,表允许更新。再比如,当执行DDLDCL语句时,会对表加排它锁X,而在存在XRSSRXRXS锁的前提下,都不能再加X锁。因此,当存在XRSSRXRSS锁时,不能对表做DCLDDL操作。这样,数据库会自动防止一个用户更新表中的数据,而其他用户在同时修改表的结构。

    2ORACLE只读事务

    ORACLE支持只读事务。只读事务有以下特点:

    *在事务中只允许查询

    *其它事务可修改和查询数据

    *在事务中,其它用户的任何修改都看不见

    只读事务的写法为:

    SET TRANS ACTION READONLY

    SQL语句

    COMMITROLLBACKDDL结束只读事务

    3、事务一致性的级别

    事 务是定义和维护一致性的单位,封锁就是要保证这种一致性。如果对封锁的要求高会增加开销,降低并发性和效率;有的事务并不严格要求结果的质量(如用于统计 的事务),如果加上严格的封锁则是不必要和不经济的。因此有必要进行进一步的分析,考察不同级别的一致性对数据库数据的质量及并行能力的影响。

    一致性级别定义为如下的几个条件:

    1)        事务不修改其它任何事务的脏数据。脏数据是被其它事务修改过,但尚未提交的数据。

    2)        在事务结束前不对被修改的资源解锁。

    3)        事务不读其它任何事务的脏数据。

    4)        在读前对数据加共享锁(RS)和行排它锁,直至事务结束。

    *满足条件1的事务叫第0级事务。

    *满足条件12的事务叫第1级一致性事务。

    *满足条件123的事务为2级一致性事务。

    ORACLE的读一致性保证了事务不读其它事务的脏数据。

    *满足条件1234的事务叫第3级一致性事务。

    ORACLE的三个性质:自动加隐式锁、在事务结束时释放锁和读一致性,使ORACLE成为自动满足以上的012级一致性事务。因此,ORACLE自动防止了脏读(写-读依赖)。但是,ORACLE不能自动防止丢失修改(写-写依赖),读的不可重复性(读-写依赖),彻底解决并发性中的问题还需满足第4个条件(3级一致性事务),这需要程序员根据实际情况编程。

    方法如下:

    *如果想在一段时间内使一些数据不被其它事务改变,且在本事务内仅仅查询数据,则可用SETTRANSACTIONREADONLY语句达到这一目的。

    *如果想在一事务内修改一数据,且避免丢失修改,则应在读这一数据前用SELECTFORUPDATE对该数据加锁。

    *如果想在一事务内读一数据,且想基于这一数据对其它数据修改,则应在读数据前对此数据用SELECTFORUPDATE加锁。对此种类型的应用,用这条SQL语句加锁最恰当。

    *如果想避免不可重复读现象,可在读前用SELECTFORUPDATE对数据加锁,或用SET TRANS ACTION READONLY设置只读事务。

    三、SYBASE的并发处理机制

    SYBASE的并发处理方法与ORACLE类似,但在很多方面不一样。SYBASE有两种粒度的封锁,一种的粒度是页,另一种的粒度是表。SYBASE根据SQL语句的情况决定用页封锁还是用表封锁。

    1、页级锁

    页级锁有以下所始的三类:

    *SHARED:在读操作时加共享锁。在缺省状态下,在读操作完成后释放共享锁。

    *EXCLUSIVE:在更新操作时加排它锁。在缺省状态下,在事务完成后释放排它锁。

    *UPDATE:在修改和删除操作的初期(读到被修改或删除的页时)加修改锁。在表上加了修改锁之后,还可以再加共享锁,但不能再加修改和排它锁。在进行修改和删除操作时,如果没有共享锁存在,修改锁则转化为排它锁。此锁的目的是为了防止死锁。SYBASE仅当在WHERE子句中包含索引列时才会使用页级的排它锁和修改锁。

    2、表级锁

    表级锁有以下所示的三类:

    *INTENT:当表中存在页级的排它锁和共享锁时,在表上加意向锁。在所有的页级锁释放后,意向锁随着释放。

    *SHARED:在读操作时加共享锁。在缺省状态下,在读操作完成后释放共享锁。

    *EXCLUSIVE:在更新操作时加排它锁。在缺省状态下,在事务完成后释放排它锁。

    3、请求锁

    请求锁用以防止共享锁一个接一个无休止地加在表上,从而写事务(要加排它锁)无法进行。

    4SYBASE的封锁级别

    SYBASE根据ANSI标准定义事务的封锁级别:

    (1)    级别1:脏读

    (2)    (2)级别2:不可重复读

    (3)    (3)光标带来的当前值混乱

    (4)    SYBASE的缺省一致性级别为1

    如果要达到一致性级别23,必须使用HOLDLOCK关键字把共享锁持续到事务的结束。方法如下:

    SELECT*FROM AUTHS HOLDLOCK

    WHERE AUTHOR_CODE='A00001'

    SYBASE还可以通过T-SQLSET命令改变SYBASE的一致性级别,从而使SYBASE自动在SELECT语句中加HOLDLOCK关键字:

    SET TRANS ACTION IS OLATION LEVEL3

    5、在SYBASE中提高并发效率的方法

    *避免在表中特定的页上多个用户过多的封锁。

    *避免在人机交互的应用中定义事务,这样会使某个用户长时间封锁

    住表(如去接电话),使其他用户持续等待。

    *使事务尽量的短。

    *仅当必要时才使用HOLDLOCK关键字。

  • 锁的概述和事务的属性

    2007-08-12 16:34:50

    一. 为什么要引入锁

    多个用户同时对数据库的并发操作时会带来以下数据不一致的问题:

    丢失更新
    A,B两个用户读同一数据并进行修改,其中一个用户的修改结果破坏了另一个修改的结果,比如订票系统

    脏读
    A用户修改了数据,随后B用户又读出该数据,但A用户因为某些原因取消了对数据的修改,数据恢复原值,此时B得到的数据就与数据库内的数据产生了不一致

    不可重复读
    A用户读取数据,随后B用户读出该数据并修改,此时A用户再读取数据时发现前后两次的值不一致

    并发控制的主要方法是封锁,锁就是在一段时间内禁止用户做某些操作以避免产生数据不一致

    二  锁的分类

    锁的类别有两种分法:
    1. 从数据库系统的角度来看:分为独占锁(即排它锁),共享锁和更新锁

    MS-SQL Server 使用以下资源锁模式。

    锁模式      描述 
    共享        (S) 用于不更改或不更新数据的操作(只读操作),如 SELECT 语句。 
    更新 (U)     用于可更新的资源中。防止当多个会话在读取、锁定以及随后可能进行的资源更新时发生常见形式的死锁。 
    排它 (X)     用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。确保不会同时同一资源进行多重更新。 
    意向锁       用于建立锁的层次结构。意向锁的类型为:意向共享 (IS)、意向排它 (IX) 以及与意向排它共享 (SIX)。 
    架构锁        在执行依赖于表架构的操作时使用。架构锁的类型为:架构修改 (Sch-M) 和架构稳定性 (Sch-S)。 
    大容量更新 (BU) 向表中大容量复制数据并指定了 TABLOCK 提示时使用。 

    共享锁
    共 享 (S) 锁允许并发事务读取 (SELECT) 一个资源。资源上存在共享 (S) 锁时,任何其它事务都不能修改数据。一旦已经读取数据,便立即释 放资源上的共享 (S) 锁,除非将事务隔离级别设置为可重复读或更高级别,或者在事务生存周期内用锁定提示保留共享 (S) 锁。
    更新锁
    更 新 (U) 锁可以防止通常形式的死锁。一般更新模式由一个事务组成,此事务读取记录,获取资源(页或行)的共享 (S) 锁,然后修改行,此操作要求锁 转换为排它 (X) 锁。如果两个事务获得了资源上的共享模式锁,然后试图同时更新数据,则一个事务尝试将锁转换为排它 (X) 锁。共享模式到排它锁的 转换必须等待一段时间,因为一个事务的排它锁与其它事务的共享模式锁不兼容;发生锁等待。第二个事务试图获取排它 (X) 锁以进行更新。由于两个事务都 要转换为排它 (X) 锁,并且每个事务都等待另一个事务释放共享模式锁,因此发生死锁。

    若要避免这种潜在的死锁问题,请使用更新 (U) 锁。一次只有一个事务可以获得资源的更新 (U) 锁。如果事务修改资源,则更新 (U) 锁转换为排它 (X) 锁。否则,锁转换为共享锁。

    排它锁
    排它 (X) 锁可以防止并发事务对资源进行访问。其它事务不能读取或修改排它 (X) 锁锁定的数据。

    意向锁
    意 向锁表示 SQL Server 需要在层次结构中的某些底层资源上获取共享 (S) 锁或排它 (X) 锁。例如,放置在表级的共享意向锁表示事务打算 在表中的页或行上放置共享 (S) 锁。在表级设置意向锁可防止另一个事务随后在包含那一页的表上获取排它 (X) 锁。意向锁可以提高性能,因为  SQL Server 仅在表级检查意向锁来确定事务是否可以安全地获取该表上的锁。而无须检查表中的每行或每页上的锁以确定事务是否可以锁定整个表。

    意向锁包括意向共享 (IS)、意向排它 (IX) 以及与意向排它共享 (SIX)。

    锁模式 描述 
    意向共享 (IS) 通过在各资源上放置 S 锁,表明事务的意向是读取层次结构中的部分(而不是全部)底层资源。 
    意向排它 (IX) 通过在各资源上放置 X 锁,表明事务的意向是修改层次结构中的部分(而不是全部)底层资源。IX 是 IS 的超集。 
    与 意向排它共享 (SIX) 通过在各资源上放置 IX 锁,表明事务的意向是读取层次结构中的全部底层资源并修改部分(而不是全部)底层资源。允许顶层资 源上的并发 IS 锁。例如,表的 SIX 锁在表上放置一个 SIX 锁(允许并发 IS 锁),在当前所修改页上放置 IX 锁(在已修改行上放置  X 锁)。虽然每个资源在一段时间内只能有一个 SIX 锁,以防止其它事务对资源进行更新,但是其它事务可以通过获取表级的 IS 锁来读取层次结构 中的底层资源。 

    独占锁:只允许进行锁定操作的程序使用,其他任何对他的操作均不会被接受。执行数据更新命令时,SQL Server会自动使用独占锁。当对象上有其他锁存在时,无法对其加独占锁。
    共享锁:共享锁锁定的资源可以被其他用户读取,但其他用户无法修改它,在执行Select时,SQL Server会对对象加共享锁。
    更新锁:当SQL Server准备更新数据时,它首先对数据对象作更新锁锁定,这样数据将不能被修改,但可以读取。等到SQL Server确定要进行更新数据操作时,他会自动将更新锁换为独占锁,当对象上有其他锁存在时,无法对其加更新锁。
    2. 从程序员的角度看:分为乐观锁和悲观锁。
    乐观锁:完全依靠数据库来管理锁的工作。
    悲观锁:程序员自己管理数据或对象上的锁处理。

    MS-SQLSERVER 使用锁在多个同时在数据库内执行修改的用户间实现悲观并发控制


    三  锁的粒度


        锁粒度是被封锁目标的大小,封锁粒度小则并发性高,但开销大,封锁粒度大则并发性低但开销小

    SQL Server支持的锁粒度可以分为为行、页、键、键范围、索引、表或数据库获取锁

    资源         描述 
    RID         行标识符。用于单独锁定表中的一行。 
    键           索引中的行锁。用于保护可串行事务中的键范围。 
    页           8 千字节 (KB) 的数据页或索引页。 
    扩展盘区     相邻的八个数据页或索引页构成的一组。 
    表           包括所有数据和索引在内的整个表。 
    DB          数据库。 


    四  锁定时间的长短

    锁保持的时间长度为保护所请求级别上的资源所需的时间长度。 

    用 于保护读取操作的共享锁的保持时间取决于事务隔离级别。采用 READ COMMITTED 的默认事务隔离级别时,只在读取页的期间内控制共享锁。在扫 描中,直到在扫描内的下一页上获取锁时才释放锁。如果指定 HOLDLOCK 提示或者将事务隔离级别设置为 REPEATABLE READ 或  SERIALIZABLE,则直到事务结束才释放锁。

    根据为游标设置的并发选项,游标可以获取共享模式的滚动锁以保护提取。当需要滚动锁时,直到下一次提取或关闭游标(以先发生者为准)时才释放滚动锁。但是,如果指定 HOLDLOCK,则直到事务结束才释放滚动锁。

    用于保护更新的排它锁将直到事务结束才释放。 
    如果一个连接试图获取一个锁,而该锁与另一个连接所控制的锁冲突,则试图获取锁的连接将一直阻塞到: 

    将冲突锁释放而且连接获取了所请求的锁。

    连接的超时间隔已到期。默认情况下没有超时间隔,但是一些应用程序设置超时间隔以防止无限期等待

    1.1.        事务的属性

    事务具有ACID属性

    Atomic原子性, Consistent一致性, Isolated隔离性, Durable永久性

     

    原子性 

       就是事务应作为一个工作单元,事务处理完成,所有的工作要么都在数据库中保存下来,要么完全回滚,全部不保留

     

    一致性

       事务完成或者撤销后,都应该处于一致的状态

     

    隔离性

       多个事务同时进行,它们之间应该互不干扰.应该防止一个事务处理其他事务也要修改的数据时,不合理的存取和不完整的读取数据

     

    永久性

       事务提交以后,所做的工作就被永久的保存下来

    1.2.        事务并发处理会产生的问题

    丢失更新

        当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题、每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。

     

    脏读

         当第二个事务选择其它事务正在更新的行时,会发生未确认的相关性问题。

         第二个事务正在读取的数据还没有确认并且可能由更新此行的事务所更改。

     

    不可重复读

         当第二个事务多次访问同一行而且每次读取不同的数据时,会发生不一致的分析问题。

         不一致的分析与未确认的相关性类似,因为其它事务也是正在更改第二个事务正在读取的数据。

         然而,在不一致的分析中,第二个事务读取的数据是由已进行了更改的事务提交的。而且,不一致的分析涉及多次(两次或更多)读取同一行,而且每次信息都由其它事务更改;因而该行被非重复读取。

     

    幻像读

          当对某行执行插入或删除操作,而该行属于某个事务正在读取的行的范围时,会发生幻像读问题。

          事务第一次读的行范围显示出其中一行已不复存在于第二次读或后续读中,因为该行已被其它事务删除。同样,由于其它事务的插入操作,事务的第二次或后续读显示有一行已不存在于原始读中。

    1.3.        事务处理类型

    自动处理事务

       系统默认每个TSQL命令都是事务处理  由系统自动开始并提交

     

    隐式事务

        当有大量的DDL DML命令执行时会自动开始,并一直保持到用户明确提交为止,切换隐式事务可以用SET IMPLICIT_TRANSACTIONS为连接设置隐性事务模式.当设置为 ON 时,SET IMPLICIT_TRANSACTIONS 将连接设置为隐性事务模式。当设置为 OFF 时,则使连接返回到自动提交事务模式

     

    用户定义事务

         由用户来控制事务的开始和结束  命令有: begin tran commit tran  rollback tran 命令

     

    分布式事务

         跨越多个服务器的事务称为分布式事务,sql server 可以由DTc microsoft distributed transaction coordinator来支持处理分布式事务,可以使用 BEgin distributed transaction 命令启动一个分布式事务处理。

    1.4.        事务处理的隔离级别

    使用SET TRANSACTION ISOLATION LEVEL来控制由连接发出的所有语句的默认事务锁定行为

    从低到高依次是:

     

    READ UNCOMMITTED

    执行脏读或 0 级隔离锁定,这表示不发出共享锁,也不接受排它锁。当设置该选项时,可以对数据执行未提交读或脏读;在事务结束前可以更改数据内的数值,行也可以出现在数据集中或从数据集消失。该选项的作用与在事务内所有语句中的所有表上设置 NOLOCK 相同。这是四个隔离级别中限制最小的级别。

    举例

    table1(A,B,C)

    A    B    C

    a1   b1   c1

    a2   b2   c2

    a3   b3   c3

     

    新建两个连接

    在第一个连接中执行以下语句

    select * from table1

    begin tran

    update table1 set c='c'

    select * from table1

    waitfor delay '00:00:10'  --等待10秒

    rollback tran

    select * from table1

     

    在第二个连接中执行以下语句

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

    print '脏读'

    select * from table1

    if @@rowcount>0

    begin

     waitfor delay '00:00:10'

     print '不重复读'

     select * from table1

    en

    第二个连接的结果

    脏读

    A    B    C

    a1   b1   c

    a2   b2   c

    a3   b3   c

     

    '不重复读'

    A    B    C

    a1   b1   c1

    a2   b2   c2

    a3   b3   c3

     

    READ COMMITTED

    指定在读取数据时控制共享锁以避免脏读,但数据可在事务结束前更改,从而产生不可重复读取或幻像数据。该选项是 SQL Server 的默认值。

     

    在第一个连接中执行以下语句

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED

    begin tran

    print '初始'

    select * from table1

    waitfor delay '00:00:10'  --等待10秒

    print '不重复读'

    select * from table1

    rollback tran

    在第二个连接中执行以下语句

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED

    update table1 set c='c'

    第一个连接的结果

    初始

    A    B    C

    a1   b1   c1

    a2   b2   c2

    a3   b3   c3

     

    不重复读

    A    B    C

    a1   b1   c

    a2   b2   c

    a3   b3   c

     

    REPEATABLE READ

    锁定查询中使用的所有数据以防止其他用户更新数据,但是其他用户可以将新的幻像行插入数据集,且幻像行包括在当前事务的后续读取中。因为并发低于默认隔离级别,所以应只在必要时才使用该选项。

     

    在第一个连接中执行以下语句

    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

    begin tran

    print '初始'

    select * from table1

    waitfor delay '00:00:10'  --等待10秒

    print '幻像读'

    select * from table1

    rollback tran

    在第二个连接中执行以下语句

    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

    insert  table1 select 'a4','b4','c4'

    第一个连接的结果

    初始

    A    B    C

    a1   b1   c1

    a2   b2   c2

    a3   b3   c3

     

    幻像读

    A    B    C

    a1   b1   c1

    a2   b2   c2

    a3   b3   c3

    a4   b4   c4

     

     

    SERIALIZABLE

    在数据集上放置一个范围锁,以防止其他用户在事务完成之前更新数据集或将行插入数据集内。这是四个隔离级别中限制最大的级别。因为并发级别较低,所以应只在必要时才使用该选项。该选项的作用与在事务内所有 SELECT 语句中的所有表上设置 HOLDLOCK 相同。

     

    在第一个连接中执行以下语句

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

    begin tran

    print '初始'

    select * from table1

    waitfor delay '00:00:10'  --等待10秒

    print '没有变化'

    select * from table1

    rollback tran

     

     

    在第二个连接中执行以下语句

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

    insert  table1 select 'a4','b4','c4'

     

    第一个连接的结果

    初始

    A    B    C

    a1   b1   c1

    a2   b2   c2

    a3   b3   c3

     

    没有变化

    A    B    C

    a1   b1   c1

    a2   b2   c2

    a3   b3   c3

    1.5.        事务处理嵌套语法和对@@TRANCOUNT的影响

    l         Ø   BEGIN TRAN           @@TRANCOUNT1

    l         Ø   COMMIT TRAN        @@TRANCOUNT1

    l         Ø   ROLLBACK TRAN     使@@TRANCOUNT回归0

    l         Ø   SAVE TRAN             不影响@@TRANCOUNT

    例一

    SELECT '事务处理前', @@TRANCOUNT      --值为 0

    BEGIN TRAN

      SELECT '第一个事务', @@TRANCOUNT      --值为 1

        SELECT * FROM table1

        BEGIN TRAN

           SELECT '第二个事务', @@TRANCOUNT  --值为 2

             DELETE table1

        COMMIT TRAN

        SELECT '递交第二个事务', @@TRANCOUNT --值为 1

    ROLLBACK TRAN

    SELECT '回滚第一个事务', @@TRANCOUNT --值为 0

     

    例二

    SELECT '事务处理前', @@TRANCOUNT      --值为 0

    BEGIN TRAN

      SELECT '第一个事务', @@TRANCOUNT    --值为 1

        SELECT * FROM table1

      SAVE TRAN t1

      SELECT '保存第一个事务后', @@TRANCOUNT --值为 1

        BEGIN TRAN

           SELECT '第二个事务', @@TRANCOUNT  --值为 2

             DELETE table1

       ROLLBACK TRAN t1

        SELECT '回滚到保存点t1', @@TRANCOUNT --注意这里的值为 2

    IF @@TRANCOUNT>0

    ROLLBACK TRAN

    SELECT '处理结束', @@TRANCOUNT --为 0

     

    SET XACT_ABORT

    控制语句产生运行时错误时,是否自动回滚当前事务

    比如

    SET XACT_ABORT ON

    BEGIN TRAN

      SELECT * FROM 一个不存在的表

    ROLL BACKTRAN

    PRINT '处理完毕'  --执行结果没有到这一步

    go

    SELECT @@TRANCOUNT  --值为1 产生孤立事务

    1.6.        事务调试语句

    DBCC OPENTRAN

    如果在指定数据库内存在最旧的活动事务和最旧的分布和非分布式复制事务,则显示与之相关的信息。

    示例

    下例获得当前数据库和 pubs 数据库的事务信息。

    -- Display transaction information only for the current database.

    DBCC OPENTRAN

    GO

    -- Display transaction information for the pubs database.

    DBCC OPENTRAN('pubs')

    GO

    1.7.        事务嵌套的例子

    1) 如果内层事务出错就取消所有事务

    BEGIN TRAN t1

     

       UPDATE tablename SET colname='37775' WHERE id='140'

          

     BEGIN TRAN  t2

     

       UPDATE tablename SET colname='37775' WHERE id='140' --id不存在

     

         IF (@@rowcount=0)

             BEING

               ROLLBAKC TRAN

              END

          ELSE

              BEGIN

                COMMIT TRAN  t2

                COMMIT TRAN  t1

              END

    2) 事务处理中只要有一个出错就回滚

    BEGIN TRAN

          UPDATE tablename SET colname='37775' WHERE id=170

  • 使用java操作excel文件

    2007-08-12 16:29:51

    package com.heyi.test;import java.io.IOException;
    import java.io.File; import jxl.DateCell;
    import jxl.NumberCell;import jxl.Workbook;
    import jxl.Sheet;import jxl.Cell;
    import jxl.read.biff.BiffException;import jxl.write.Label;
    import jxl.write.WritableFont;import jxl.CellType;
    public class TestExcel {  public static void main(String[] args)
     {  TestExcel.readExcel(new File("D:/temp/进出口流程数据结构.xls"));// TestExcel.writeExc
  • 不正确的编写SQL语句会导致系统不安全

    2007-08-12 16:15:02

    在一般的多用户应用系统中,只有拥有正确的用户名和密码的用户才能进入该系统。我们通常需要编写用户登录窗口来控制用户使用该系统,这里以Visual Basic ADO为例:

    一、漏洞的产生

    用于登录的表:

    Users(name,pwd)

    建立一个窗体Frmlogin,其上有两个文本框Text1,Text2和两个命令按钮cmdok,cmdexit。两个文本框分别用于让用户输入用户名和密码,两个命令按钮用于“登录”和“退出”。

    1、定义Ado Connection对象和ADO RecordSet对象:

    Option Explicit

    Dim Adocon As ADODB.Connection

    Dim Adors As ADODB.Recordset

    2、在Form_Load中进行数据库连接:

    Set Adocon = New ADODB.Connection

    Adocon.CursorLocation = adUseClient

    adocon.Open "Provider=Microsoft.jet.
    OLeDB.4.0.1; Data Source=" && _

    App.Path && " est.mdb; "

    cmdok中的代码

    Dim sqlstr As String

    sqlstr = "select * from
    usersswheresname='" && Text1.Text && _

    "' and pwd='" && Text2.Text && "'"

    Set adors = New ADODB.Recordset

    Set Adors=Adocon.Execute(sqlstr)

    if Adors.Recordcount>0 Then
    //或If Not Adors.EOF then

    ....

    MsgBox "Pass" //通过验证

    Else

    ...

    MsgBox "Fail" //未通过验证

    End if

    运行该程序,看起来这样做没有什么问题,但是当在Text1中输入任意字符串(如123),在Text2中输入a' or 'a'='a时,我们来看sqlstr此时的值:

    select * from usersswheresname='123'
    and pwd='a' or 'a'='a'

    执行这样一个SQL语句,由于or之后的'a'='a'为真值,只要users表中有记录,则它的返回的eof值一定为False,这样就轻易地绕过了系统对于用户和密码的验证。

    这样的问题将会出现在所有使用
    select * from usersswheresname='"
    && name && "' and pwd='" && password &&"'
    的各种系统中,无论你是使用那种编程语言。

    二、漏洞的特点

    在网络上,以上问题尤其明显,笔者在许多网站中都发现能使用这种方式进入需要进行用户名和密码验证的系统。这样的一个SQL漏洞具有如下的特点:

    1、与编程语言或技术无关

    无论是使用VB、Delphi还是ASP、JSP。

    2、隐蔽性

    现有的系统中有相当一部分存在着这个漏洞,而且不易觉察。

    3、危害性

    不需要进行用户名或密码的猜测即可轻易进入系统。

    三、解决漏洞的方法

    1、控制密码中不能出现空格。

    2、对密码采用加密方式。

    这里要提及一点,加密不能采用过于简单的算法,因为过于简单的算法会让人能够构造出形如a' or 'a'='a的密文,从而进入系统。

    3、将用户验证和密码验证分开来做,先进行用户验证,如果用户存在,再进行密码验证,这样一来也能解决问题。

  • 图像在网络中的传输机制

    2007-08-12 15:40:51

    图像在网络上传输,一般都是传输编码压缩后的图像。例如在本地将一张图像编码压缩成JPEG格式后通过网络传输出去,接收端接收到之后再将其解码,用于显 示,或者直接存储到存储介质上。当然,如果不考虑传输数据量,或者有一些特殊需求也可以直接将图像对象序列化后传输。本文只讨论前者,关于图像对象序列化 可以参考我的另一篇文章《图像序列化》。

    那么整理一下,这个过程也就分为3个步骤:
    1、发送端图像编码。
    2、以字节流的方式在网络上传输;
    3、接收端解码。

    图像编码
    因为图像编码解码主要目的是针对图像在网络中的传输,所以编码之后的图像不必保存在硬盘上,可以直接放入一个字节数组。

        public byte[] getCompressedImage(BufferedImage image){
            
    byte[] imageData = null;
            
            
    try {
                ByteArrayOutputStream baos 
    = new ByteArrayOutputStream();
                ImageIO.write(image, 
    "jpg", baos);
                imageData 
    = baos.toByteArray();
            }
     catch (IOException ex) {
                imageData 
    = null;
            }

            
            
    return imageData;
        }


    图像解码
    接收端接收到表示图像数据的字节数组后,对其进行解码,得到图像对象。因为我们在发送端将其编码成JPEG格式,所以可以直接在接收端使用ImageIO对其进行解码。

        public BufferedImage getDecompressedImage(byte[] imageData){
            
    try {
                ByteArrayInputStream bais 
    = new ByteArrayInputStream(imageData);
                
    return ImageIO.read(bais);
            }
     catch (IOException ex) {
                
    return null;
            }

        }

    网络传输
    因为图像编码之后是一个存在于内存中的字节数组,所以可以使用IO流的方式将其发送到网络的接收端,接收端建立链接将其接收。最常用的例如建立 Socket 连接等等。这部分代码讲IO的书里都有,我就不在这里写了。

  • Javascript中最常用的55个经典技巧

    2007-08-12 15:17:59

    1. ōncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键
    <table border ōncontextmenu=return(false)><td>no</table> 可用于Table

    2. <body ōnselectstart="return false"> 取消选取、防止复制

    3. ōnpaste="return false" 不准粘贴

    4. ōncopy="return false;" ōncut="return false;" 防止复制

    5. <link rel="Shortcut Icon" href="favicon.ico"> IE地址栏前换成自己的图标

    6. <link rel="Bookmark" href="favicon.ico"> 可以在收藏夹中显示出你的图标


    7. <input style="ime-mode:disabled"> 关闭输入法


    8. 永远都会带着框架
    <scrīpt language="Javascrīpt"><!--
    if (window == top)top.location.href = "frames.htm"; //frames.htm为框架网页
    // --></scrīpt>


    9. 防止被人frame
    <scrīpt LANGUAGE=JAVAscrīpt><!--
    if (top.location != self.location)top.location=self.location;
    // --></scrīpt>


    10. 网页将不能被另存为
    <noscrīpt><*** src="/*.html>";</***></noscrīpt>


    11. <input type=button value="/查看网页源代码
    onclick="window.location = "view-source:"+ "http://www.pconline.com.cn"">
    12.删除时确认
    <a href=""javascrīpt :if(confirm("确实要删除吗?"))location="boos.asp?&areyou=删除&page=1"">删除</a>


    13. 取得控件的绝对位置
    //Javascrīpt
    <scrīpt language="Javascrīpt">
    function getIE(e){
    var t=e.offsetTop;
    var l=e.offsetLeft;
    while(e=e.offsetParent){
    t+=e.offsetTop;
    l+=e.offsetLeft;
    }
    alert("top="+t+"/nleft="+l);
    }
    </scrīpt>
    //VBscrīpt
    <scrīpt language="VBscrīpt"><!--
    function getIE()
    dim t,l,a,b
    set a=document.all.img1
    t=document.all.img1.offsetTop
    l=document.all.img1.offsetLeft
    while a.tagName<>"BODY"
    set a = a.offsetParent
    t=t+a.offsetTop
    l=l+a.offsetLeft
    wend
    msgbox "top="&t&chr(13)&"left="&l,64,"得到控件的位置"
    end function
    --></scrīpt>


    14. 光标是停在文本框文字的最后
    <scrīpt language="javascrīpt">
    function cc()
    {
    var e = event.srcElement;
    var r =e.createTextRange();
    r.moveStart("character",e.value.length);
    r.collapse(true);
    r.select();
    }
    </scrīpt>
    <input type=text name=text1 value="123" ōnfocus="cc()">


    15. 判断上一页的来源
    javascrīpt :
    document.referrer


    16. 最小化、最大化、关闭窗口
    <object id=hh1 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11">
    <param name="Command" value="Minimize"></object>
    <object id=hh2 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11">
    <param name="Command" value="Maximize"></object>
    <OBJECT id=hh3 classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11">
    <PARAM NAME="Command" value="/Close"></OBJECT>
    <input type=button value="/最小化 ōnclick=hh1.Click()>
    <input type=button value="/blog/最大化 ōnclick=hh2.Click()>
    <input type=button value=关闭 ōnclick=hh3.Click()>
    本例适用于IE


    17.屏蔽功能键Shift,Alt,Ctrl
    <scrīpt>
    function look(){
    if(event.shiftKey)
    alert("禁止按Shift键!"); //可以换成ALT CTRL
    }
    document.onkeydown=look;
    </scrīpt>


    18. 网页不会被缓存
    <META HTTP-EQUIV="pragma" CONTENT="no-cache">
    <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
    <META HTTP-EQUIV="expires" CONTENT="Wed, 26 Feb 1997 08:21:57 GMT">
    或者<META HTTP-EQUIV="expires" CONTENT="0">


    19.怎样让表单没有凹凸感?
    <input type=text style="""border:1 solid #000000">

    <input type=text style="border-left:none; border-right:none; border-top:none; border-bottom:
    1 solid #000000"></textarea>


    20.<div><span>&<layer>的区别?
    <div>(division)用来定义大段的页面元素,会产生转行
    <span>用来定义同一行内的元素,跟<div>的唯一区别是不产生转行
    <layer>是ns的标记,ie不支持,相当于<div>


    21.让弹出窗口总是在最上面:
    <body ōnblur="this.focus();">


    22.不要滚动条?
    让竖条没有:
    <body style="overflow:scroll;overflow-y:hidden">
    </body>
    让横条没有:
    <body style="overflow:scroll;overflow-x:hidden">
    </body>
    两个都去掉?更简单了
    <body scroll="no">
    </body>


    23.怎样去掉图片链接点击后,图片周围的虚线?
    <a href="#" ōnFocus="this.blur()"><img src="/logo.jpg" border=0></a>


    24.电子邮件处理提交表单
    <form name="form1" method="post" action=mailto:****@***.com
    enctype="text/plain">
    <input type=submit>
    </form>


    25.在打开的子窗口刷新父窗口的代码里如何写?
    window.opener.location.reload()


    26.如何设定打开页面的大小
    <body ōnload="top.resizeTo(300,200);">
    打开页面的位置<body ōnload="top.moveBy(300,200);">


    27.在页面中如何加入不是满铺的背景图片,拉动页面时背景图不动
    <STYLE>
    body
    {background-image:url(/logo.gif); background-repeat:no-repeat;
    background-position:center;background-attachment: fixed}
    </STYLE>


    28. 检查一段字符串是否全由数字组成
    <scrīpt language="Javascrīpt"><!--
    function checkNum(str){return str.match(//D/)==null}
    alert(checkNum("1232142141"))
    alert(checkNum("123214214a1"))
    // --></scrīpt>


    29. 获得一个窗口的大小
    document.body.clientWidth; document.body.clientHeight


    30. 怎么判断是否是字符
    if (/[^/x00-/xff]/g.test(s)) alert("含有汉字");
    else alert("全是字符");


    31.TEXTAREA自适应文字行数的多少
    <textarea rows=1 name=s1 cols=27 onpropertychange
    ="this.style.posHeight=this.scrollHeight">
    </textarea>


    32. 日期减去天数等于第二个日期
    <scrīpt language=Javascrīpt>
    function cc(dd,dadd)
    {
    //可以加上错误处理
    var a = new Date(dd)
    a = a.valueOf()
    a = a - dadd * 24 * 60 * 60 * 1000
    a = new Date(a)
    alert(a.getFullYear() + "年" + (a.getMonth() + 1) + "月" + a.getDate() + "日")
    }
    cc("12/23/2002",2)
    </scrīpt>


    33. 选择了哪一个Radio
    <HTML><scrīpt language="vbscrīpt">
    function checkme()
    for each ob in radio1
    if ob.checked then
    window.alert ob.value
    next
    end function
    </scrīpt><BODY>
    <INPUT name="radio1" type="radio" value="/style" checked>Style
    <INPUT name="radio1" type="radio" value="/blog/barcode">Barcode
    <INPUT type="button" value="check" ōnclick="checkme()">
    </BODY></HTML>


    34.脚本永不出错
    <scrīpt LANGUAGE="Javascrīpt">
    <!-- Hide
    function killErrors() {
    return true;
    }
    window.onerror = killErrors;
    // -->
    </scrīpt>


    35.ENTER键可以让光标移到下一个输入框
    <input ōnkeydown="if(event.keyCode==13)event.keyCode=9">


    36. 检测某个网站的链接速度:
    把如下代码加入<body>区域中:
    <scrīpt language=Javascrīpt>
    tim=1
    setInterval("tim++",100)
    b=1
    var autourl=new Array()
    autourl[1]=1000){this.resized=true;this.style.width=1000;}" align=absMiddle border=0>www.njcatv.net"
    autourl[2]="javacool.3322.net"
    autourl[3]=1000){this.resized=true;this.style.width=1000;}" align=absMiddle border=0>www.sina.com.cn"
    autourl[4]="www.nuaa.edu.cn"
    autourl[5]=1000){this.resized=true;this.style.width=1000;}" align=absMiddle border=0>www.cctv.com"
    function butt(){
    ***("<form name=autof>")
    for(var i=1;i<autourl.length;i++)
    ***("<input type=text name=txt"+i+" size=10 value="/测试中……> =》<input type=text
    name=url"+i+" size=40> =》<input type=button value="/blog/GO
    onclick=window.open(this.form.url"+i+".value)><br>")
    ***("<input type=submit value=刷新></form>")
    }
    butt()
    function auto(url){
    document.forms[0]["url"+b].value=url
    if(tim>200)
    {document.forms[0]["txt"+b].value="/链接超时"}
    else
    {document.forms[0]["txt"+b].value="/blog/时间"+tim/10+"秒"}
    b++
    }
    function run(){for(var i=1;i<autourl.length;i++)***("<img src=http://"+autourl+"/"+Math.random()+" width=1 height=1
    onerror=auto("http://"+autourl+"")>")}
    run()</scrīpt>


    37. 各种样式的光标
    auto :标准光标
    default :标准箭头
    hand :手形光标
    wait :等待光标
    text :I形光标
    vertical-text :水平I形光标
    no-drop :不可拖动光标
    not-allowed :无效光标
    help :?帮助光标
    all-scroll :三角方向标
    move :移动标
    crosshair :十字标
    e-resize
    n-resize
    nw-resize
    w-resize
    s-resize
    se-resize
    sw-resize


    38.页面进入和退出的特效
    进入页面<meta http-equiv="Page-Enter" content="revealTrans(duration=x, transition=y)">
    推出页面<meta http-equiv="Page-Exit" content="revealTrans(duration=x, transition=y)">  
    这个是页面被载入和调出时的一些特效。duration表示特效的持续时间,以秒为单位。transition表示使用哪种特效,取值为1-23:
      0 矩形缩小
      1 矩形扩大
      2 圆形缩小
      3 圆形扩大
      4 下到上刷新
      5 上到下刷新
      6 左到右刷新
      7 右到左刷新
      8 竖百叶窗
      9 横百叶窗
      10 错位横百叶窗
      11 错位竖百叶窗
      12 点扩散
      13 左右到中间刷新
      14 中间到左右刷新
      15 中间到上下
      16 上下到中间
      17 右下到左上
      18 右上到左下
      19 左上到右下
      20 左下到右上
      21 横条
      22 竖条
      23 以上22种随机选择一种


    39.在规定时间内跳转
    <META http-equiv=V="REFRESH" content="5;URL=http://www.51js.com">


    40.网页是否被检索
    <meta name="ROBOTS" content="属性值">
      其中属性值有以下一些:
      属性值为"all": 文件将被检索,且页上链接可被查询;
      属性值为"none": 文件不被检索,而且不查询页上的链接;
      属性值为"index": 文件将被检索;
      属性值为"follow": 查询页上的链接;
      属性值为"noindex": 文件不检索,但可被查询链接;
      属性值为"nofollow": 文件不被检索,但可查询页上的链接。


    41、email地址的分割
    把如下代码加入<body>区域中
    <a href="mailto:webmaster@sina.com">webmaster@sina.com</a>


    42、流动边框效果的表格
    把如下代码加入<body>区域中
    <scrīpt>
    l=Array(6,7,8,9,'a','b','b','c','d','e','f')
    Nx=5;Ny=35
    t="<table border=0 cellspacing=0 cellpadding=0 height="+((Nx+2)*16)+"><tr>"
    for(x=Nx;x<Nx+Ny;x++)
    t+="<td width=16 id=a_mo"+x+"> </td>"
    t+="</tr><tr><td width=10 id=a_mo"+(Nx-1)+"> </td><td colspan="+(Ny-2)+" rowspan="+(Nx)+"> </td><td width=16 id=a_mo"+(Nx+Ny)+"></td></tr>"
    for(x=2;x<=Nx;x++)
    t+="<tr><td width=16 id=a_mo"+(Nx-x)+"> </td><td width=16 id=a_mo"+(Ny+Nx+x-1)+"> </td></tr>"
    t+="<tr>"
    for(x=Ny;x>0;x--)
    t+="<td width=16 id=a_mo"+(x+Nx*2+Ny-1)+"> </td>"
    ***(t+"</tr></table>")
    var N=Nx*2+Ny*2
    function f1(y){
    for(i=0;i<N;i++){
    c=(i+y)%20;if(c>10)c=20-c
    document.all["a_mo"+(i)].bgColor=""""#0000"+l[c]+l[c]+"'"}
    y++
    setTimeout('f1('+y+')','1')}
    f1(1)
    </scrīpt>


    43、Javascrīpt主页弹出窗口技巧
    窗口中间弹出
    <scrīpt>
    window.open("http://www.cctv.com","","width=400,height=240,top="+(screen.availHeight-240)/2+",left="+(screen.availWidth-400)/2);
    </scrīpt>
    ============
    <html>
    <head>
    <scrīpt language="Livescrīpt">
    function WinOpen() {
        msg=open("","DisplayWindow","toolbar=no,directories=no,menubar=no");
        msg.***("<HEAD><TITLE>哈 罗!</TITLE></HEAD>");
        msg.***("<CENTER><H1>酷 毙 了!</H1><h2>这 是<B>Javascrīpt</B>所 开 的 视 窗!</h2></CENTER>");
    }
    </scrīpt>
    </head>
    <body>
    <form>
    <input type="button" name="Button1" value="Push me" ōnclick="WinOpen()">
    </form>
    </body>
    </html>
    ==============
    一、在下面的代码中,你只要单击打开一个窗口,即可链接到赛迪网。而当你想关闭时,只要单击一下即可关闭刚才打开的窗口。
      代码如下:
      <scrīpt language="Javascrīpt">
      <!--
      function openclk() {
      another=open('1000){this.resized=true;this.style.width=1000;}" align=absMiddle border=0>http://www.ccidnet.com','NewWindow');
      }
      function closeclk() {
      another.close();
      }
      //-->
      </scrīpt>
      <FORM>
      <INPUT TYPE="BUTTON" NAME="open" value="/打开一个窗口" ōnClick="openclk()">
      <BR>
      <INPUT TYPE="BUTTON" NAME="close" value="/blog/关闭这个窗口" ōnClick="closeclk()">
      </FORM>
      二、上面的代码也太静了,为何不来点动感呢?如果能给页面来个降落效果那该多好啊!
      代码如下:
      <scrīpt>
      function drop(n) {
      if(self.moveBy){
      self.moveBy (0,-900);
      for(i = n; i > 0; i--){
      self.moveBy(0,3);
      }
      for(j = 8; j > 0; j--){
      self.moveBy(0,j);
      self.moveBy(j,0);
      self.moveBy(0,-j);
      self.moveBy(-j,0);
      }
      }
      }
      </scrīpt>
      <body ōnLoad="drop(300)">
      三、讨厌很多网站总是按照默认窗口打开,如果你能随心所欲控制打开的窗口那该多好。
      代码如下:
      <scrīpt LANGUAGE="Javascrīpt">
      <!-- Begin
      function popupPage(l, t, w, h) {
      var windowprops = "location=no,scrollbars=no,menubars=no,toolbars=no,resizable=yes" +
      ",left=" + l + ",top=" + t + ",width=" + w + ",height=" + h;
      var URL = "http://www.80cn.com";
      popup = window.open(URL,"MenuPopup",windowprops);
      }
      // End -->
      </scrīpt>
      <table>
      <tr>
      <td>
      <form name=popupform>
      <pre>
      打开页面的参数<br>
      离开左边的距离: <input type=text name=left size=2 maxlength=4> pixels
      离开右边的距离: <input type=text name=top size=2 maxlength=4> pixels
      窗口的宽度: <input type=text name=width size=2 maxlength=4> pixels
      窗口的高度: <input type=text name=height size=2 maxlength=4> pixels
      </pre>
      <center>
      <input type=button value="打开这个窗口!" ōnClick="popupPage(this.form.left.value, this.form.top.value, this.form.width.value,
    this.form.height.value)">
      </center>
      </form>
      </td>
      </tr>
      </table>你只要在相对应的对话框中输入一个数值即可,将要打开的页面的窗口控制得很好。


    44、页面的打开移动
    把如下代码加入<body>区域中
    <scrīpt LANGUAGE="Javascrīpt">
    <!-- Begin
    for (t = 2; t > 0; t--) {
    for (x = 20; x > 0; x--) {
    for (y = 10; y > 0; y--) {
    parent.moveBy(0,-x);
       }
    }
    for (x = 20; x > 0; x--) {
    for (y = 10; y > 0; y--) {
    parent.moveBy(0,x);
       }
    }
    for (x = 20; x > 0; x--) {
    for (y = 10; y > 0; y--) {
    parent.moveBy(x,0);
       }
    }
    for (x = 20; x > 0; x--) {
    for (y = 10; y > 0; y--) {
    parent.moveBy(-x,0);
         }
       }
    }
    //-->
    //   End -->
    </scrīpt>


    45、显示个人客户端机器的日期和时间
    <scrīpt language="Livescrīpt">
    <!-- Hiding
       today = new Date()
       ***("现 在 时 间 是: ",today.getHours(),":",today.getMinutes())
       ***("<br>今 天 日 期 为: ", today.getMonth()+1,"/",today.getDate(),"/",today.getYear());
    // end hiding contents -->
    </scrīpt>


    46、自动的为你每次产生最後修改的日期了:
    <html>
    <body>
    This is a simple HTML- page.
    <br>
    Last changes:
       <scrīpt language="Livescrīpt">
       <!--   hide scrīpt from old browsers
         ***(document.lastModified)
       // end hiding contents -->
       </scrīpt>
    </body>
    </html>


    47、不能为空和邮件地址的约束:
    <html>
    <head>
    <scrīpt language="Javascrīpt">
    <!-- Hide
    function test1(form) {
       if (form.text1.value == "")
         alert("您 没 写 上 任 何 东 西, 请 再 输 入 一 次 !")
       else {
        alert("嗨 "+form.text1.value+"! 您 已 输 入 完 成 !");
       }
    }
    function test2(form) {
       if (form.text2.value == "" ||
           form.text2.value.indexOf('@', 0) == -1)
             alert("这 不 是 正 确 的 e-mail address! 请 再 输 入 一 次 !");
       else alert("您 已 输 入 完 成 !");
    }
    // -->
    </scrīpt>
    </head>
    <body>
    <form name="first">
    Enter your name:<br>
    <input type="text" name="text1">
    <input type="button" name="button1" value="输 入 测 试" ōnClick="test1(this.form)">
    <P>
    Enter your e-mail address:<br>
    <input type="text" name="text2">
    <input type="button" name="button2" value="输 入 测 试" ōnClick="test2(this.form)">
    </body>


    48、跑马灯
    <html>
    <head>
    <scrīpt language="Javascrīpt">
    <!-- Hide
    var scrtxt="怎麽样 ! 很酷吧 ! 您也可以试试."+"Here goes your message the visitors to your
    page will "+"look at for hours in pure fascination...";
    var lentxt=scrtxt.length;
    var width=100;
    var pos=1-width;
    function scroll() {
       pos++;
       var scroller="";
       if (pos==lentxt) {
         pos=1-width;
       }
       if (pos<0) {
         for (var i=1; i<=Math.abs(pos); i++) {
           scroller=scroller+" ";}
         scroller=scroller+scrtxt.substring(0,width-i+1);
       }
       else {
         scroller=scroller+scrtxt.substring(pos,width+pos);
       }
       window.status = scroller;
       setTimeout("scroll()",150);
       }
    //-->
    </scrīpt>
    </head>
    <body ōnLoad="scroll();return true;">
    这里可显示您的网页 !
    </body>
    </html>


    49、在网页中用按钮来控制前页,后页和主页的显示。
    <html>
    <body>
    <FORM NAME="buttonbar">
          <INPUT TYPE="button" VALUE="Back" ōnClick="history.back()">
          <INPUT TYPE="button" VALUE="JS- Home" ōnClick="location='scrīpt.html'">
          <INPUT TYPE="button" VALUE="Next" ōnCLick="history.forward()">
    </FORM>
    </body>
    </html>
    50、查看某网址的源代码
    把如下代码加入<body>区域中
    <scrīpt>
    function add()
    {
    var ress=document.forms[0].luxiaoqing.value
    window.location="view-source:"+ress;
    }
    </scrīpt>
    输入要查看源代码的URL地址:
    <FORM><input type="text" name="luxiaoqing" size=40 value="http://"></FORM>
    <FORM><br>
    <INPUT type="button" value="查看源代码" ōnClick=add()>
    </FORM>


    51、title显示日期
    把如下代码加入<body>区域中:
    <scrīpt language="Javascrīpt1.2">
    <!--hide
    var isnMonth = new
    Array("1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月");
    var isnDay = new
    Array("星期日","星期一","星期二","星期三","星期四","星期五","星期六","星期日");
    today = new Date () ;
    Year=today.getYear();
    Date=today.getDate();
    if (document.all)
    document.title="今天是: "+Year+"年"+isnMonth[today.getMonth()]+Date+"日"+isnDay[today.getDay()]
    //--hide-->
    </scrīpt>


    52、显示所有链接
    把如下代码加入<body>区域中
    <scrīpt language="Javascrīpt1.2">
    <!--
    function extractlinks(){
    var links=document.all.tags("A")
    var total=links.length
    var win2=window.open("","","menubar,scrollbars,toolbar")
    win2.***("<font size='2'>一共有"+total+"个连接</font><br>")
    for (i=0;i<total;i++){
    win2.***("<font size='2'>"+links[i].outerHTML+"</font><br>")
    }
    }
    //-->
    </scrīpt>
    <input type="button" ōnClick="extractlinks()" value="显示所有的连接">


    53、回车键换行
    把如下代码加入<body>区域中
    <scrīpt type="text/javascrīpt">                
    function handleEnter (field, event) {
       var keyCode = event.keyCode ? event.keyCode : event.which ?
    event.which : event.charCode;
       if (keyCode == 13) {
        var i;
        for (i = 0; i < field.form.elements.length; i++)
         if (field == field.form.elements[i])
          break;
        i = (i + 1) % field.form.elements.length;
        field.form.elements[i].focus();
        return false;
       }
       else
       return true;
    }      
    </scrīpt>
    <form>
    <input type="text" ōnkeypress="return handleEnter(this, event)"><br>
    <input type="text" ōnkeypress="return handleEnter(this, event)"><br>
    <textarea>回车换行


    54、确认后提交
    把如下代码加入<body>区域中
    <scrīpt LANGUAGE="Javascrīpt">
    <!--
    function msg(){
    if (confirm("你确认要提交嘛!"))
    document.lnman.submit()
    }
    //-->
    </scrīpt>
    <form name="lnman" method="post" action="">
       <p>
         <input type="text" name="textfield" value="确认后提交">
       </p>
       <p>
         <input type="button" name="Submit" value="提交" ōnclick="msg();">
       </p>
    </form>


    55、改变表格的内容
    把如下代码加入<body>区域中
    <scrīpt ***scrīpt>
    var arr=new Array()
    arr[0]="一一一一一";
    arr[1]="二二二二二";
    arr[2]="三三三三三";
    </scrīpt>
    <select ōnchange="zz.cells[this.selectedIndex].innerHTML=arr[this.selectedIndex]">
       <option value=a>改变第一格</option>
       <option value=a>改变第二格</option>
       <option value=a>改变第三格</option>
    </select>
    <table id=zz border=1>
       <tr height=20>
         <td width=150>第一格</td>
    <td width=150>第二格</td>
    <td width=150>第三格</td>
       </tr>
    </table>

  • 关于C编程的一点感受

    2007-08-12 15:17:12

    刚毕业的时候用了两个多月的C语言编程,总的来说对它还是很有感受的,C是一个过程式语言,没有像C++,Java等OOP语言这样那样的一系列的 规则和限制;它比较灵活,简洁,高效;这些是给我的印象最深的。这是很久以前写的东西了,现在贴出来,希望对正在学习C语言的人有所帮助。

    关于C编程的一些感受。

    a. 现在写程序的人很多,但大部分都是用的高级语言,其实一个优秀的程序员,一个优秀的软件工程师,都应该从底层做起,例如从汇编,从Dos;就像我的一个领 导说的那样,计算机像一个海洋,而硬件就是海底,汇编和Dos是海床,是它们支撑了这个庞大的海洋;而高级语言则如同海里的船,等我们有了基础再去造各种 各样的船那就很简单了。
    b.  由于我们写的程序不能只有自己一个人来读,因此写代码期间移一定要有加详细注释的习惯,这样既可以增强程序的可读性,方便与别人交流合作;也会为自己调试程序带来方便。加注释要尽量用英文,因为有的编译器可能不支持汉字,例如Turboc,BorlandC++。
    c .  指针是C语言的核心,因此在使用它时一定要格外小心,使用它时要尽量这样定义char p[],而不用这种形式 char * p; 后一种定义有时会给你带来意想不到的麻烦和错误。
    d.  对于我们这些刚入门的人来说,写程序一定要养成良好的风格:例如函数定义,变量声明要让人们很容易能联想到它的作用,大括号上下要严格对齐,语句和它的子集语句要有明显的间隔,通常以一个Tab键的距离为准;等等这些吧。
    e.  如果有能力的话,自己定义函数,而不是每次都被动的去使用编译器提供的库函数,因为我觉得使用自己定义的函数更放心。C++里面就不是这样了,在C++里面则要求尽量使用它自己的类库,而不是自己重新定义。
    f.  你的东西做出来以后,一定要请多个人去调试,因为人们往往受定性思维的限制,这使得有些潜在的异常你很难发现,但别人也许会轻而易举的找到它,从而能帮你尽快完善你的程序。
    g. 写程序一定要注意它的可扩充性和通用性,例如同样的一个绘制编辑框函数,有的可以绘制很多种不同大小的框,而有的则只能画固定长宽的框,这就是区别;所以不论写什么函数都要考虑它的通用性,定义好入口参数。

    //附加:如果想以后转向C++或java编程的话,建议C语言不要学的太精,因为有这样一句话“C语言学的越精,就越不容易发挥C++语言的优势”。^_^!

  • VBS创建多级目录

    2007-08-09 00:53:43

    Dim WshShell
    Set WshShell = CreateObject("wscrīpt.Shell")
    WshShell.Run "cmd.exe /c md c:\1\2\3\4"
    Set WshShell = Nothing
  • Songfun老师郁闷后的成果。^ . ^

    2007-08-09 00:25:00

    摘录自songfun老师文库。。。


    QTP下,测试脚本不能录制的解决方法


    前一阵子,加入了测试联盟的QQ群(现在被郁闷的踢出了,天呐,我这种真正搞测试的都被踢了),那个群还真热闹,不过一般都是讲些废话,开开玩笑。有个朋友在群里问了一个问题:为什么他装了QTP以后,总是不能录制脚本?出于好奇,我又弄了一下N年前装的QTP8.2,经过整整一天的折腾,终于明白这是怎么一回事了。现总结一下,以便遇到同样问题的朋友能得到一点帮助。

    问题起因:
    在安装QTP后,或者禁用IE浏览器里的一些ActiveX控件后,正常录制QTP事,不能产生相应的录制脚本,脚本内容为空。

    解决方法:根据实践,我发现QTP在IE中录制脚本是依靠一个叫BHOManager Class的动态链接库来完成的。当这个控件没有被加载,或者被禁用时,就会出现上述症状。于是,解决方法就很简单了,重新加载,或启用这个控件,一切就OK啦。

    具体步骤:
    打开IE,在菜单中选择[工具]/[Internet选项]进入Internet配置界面。选择[程序]/[管理加载项],查看目前加载的ActiveX的情况。

    当看到存在BHOManager Class并且其状态是“禁用”时,点击“启用”开启这个功能,并保存后退出即可解决问题。
    当在管理加载项里找不到BHOManger Class这个加载项时,如果你安装了QTP,那么在C:\WINDOWS\system32下会存在一个叫BHOManager.dll的动态链接库,或者可以直接在计算机里搜索BHOManager.dll,然后查看其路径。加载这个dll,加载方法为:点击[开始]/[运行],输入cmd,然后定位到dll所在目录,键入regsvr32 BHOManager.dll命令,即可注册此dll。
  • fso文件操作大全

    2007-08-09 00:21:30

    创建文件
    dim fso, f
    set fso = server.CreateObject("scrīpting.FileSystemObject")
    set f = fso.CreateTextFile("C:\test.txt", true) '第二个参数表示目标文件存在时是否覆盖
    f.Write("写入内容")
    f.WriteLine("写入内容并换行")
    f.WriteBlankLines(3) '写入三个空白行(相当于在文本编辑器中按三次回车)
    f.Close()
    set f = nothing
    set fso = nothing

    打开并读文件
    dim fso, f
    set fso = server.CreateObject("scrīpting.FileSystemObject")
    set f = fso.OpenTextFile("C:\test.txt", 1, false) '第二个参数 1 表示只读打开,第三个参数表示目标文件不存在时是否创建
    f.Skip(3) '将当前位置向后移三个字符
    f.SkipLine() '将当前位置移动到下一行的第一个字符,注意:无参数
    response.Write f.Read(3) '从当前位置向后读取三个字符,并将当前位置向后移三个字符
    response.Write f.ReadLine() '从当前位置向后读取直到遇到换行符(不读取换行符),并将当前位置移动到下一行的第一个字符,注意:无参数
    response.Write f.ReadAll() '从当前位置向后读取,直到文件结束,并将当前位置移动到文件的最后
    if f.atEndOfLine then
        response.Write("一行的结尾!")
    end if
    if f.atEndOfStream then
        response.Write("文件的结尾!")
    end if
    f.Close()
    set f = nothing
    set fso = nothing

    打开并写文件
    dim fso, f
    set fso = server.CreateObject("scrīpting.FileSystemObject")
    set f = fso.OpenTextFile("C:\test.txt", 2, false) '第二个参数 2 表示重写,如果是 8 表示追加
    f.Write("写入内容")
    f.WriteLine("写入内容并换行")
    f.WriteBlankLines(3) '写入三个空白行(相当于在文本编辑器中按三次回车)
    f.Close()
    set f = nothing
    set fso = nothing

    判断文件是否存在
    dim fso
    set fso = server.CreateObject("scrīpting.FileSystemObject")
    if fso.FileExists("C:\test.txt") then
        response.Write("目标文件存在")
    else
        response.Write("目标文件不存在")
    end if
    set fso = nothing

    移动文件
    dim fso
    set fso = server.CreateObject("scrīpting.FileSystemObject")
    call fso.MoveFile("C:\test.txt", "D:\test111.txt") '两个参数的文件名部分可以不同
    set fso = nothing

    复制文件
    dim fso
    set fso = server.CreateObject("scrīpting.FileSystemObject")
    call fso.CopyFile("C:\test.txt", "D:\test111.txt") '两个参数的文件名部分可以不同
    set fso = nothing

    删除文件
    dim fso
    set fso = server.CreateObject("scrīpting.FileSystemObject")
    fso.DeleteFile("C:\test.txt")
    set fso = nothing

    创建文件夹
    dim fso
    set fso = server.CreateObject("scrīpting.FileSystemObject")
    fso.CreateFolder("C:\test") '目标文件夹的父文件夹必须存在
    set fso = nothing

    判断文件夹是否存在
    dim fso
    set fso = server.CreateObject("scrīpting.FileSystemObject")
    if fso.FolderExists("C:\Windows") then
        response.Write("目标文件夹存在")
    else
        response.Write("目标文件夹不存在")
    end if
    set fso = nothing

    删除文件夹
    dim fso
    set fso = server.CreateObject("scrīpting.FileSystemObject")
    fso.DeleteFolder("C:\test") '文件夹不必为空
    set fso = nothing

    ====
    'path为要删除目录路径
    sub delfolder(path)
    Dim WshShell, oExec
    Set WshShell = CreateObject("Wscrīpt.Shell")
    Set ōExec = WshShell.Exec("cmd /c del /s /q "+path)
    set ōexec = wshshell.exec("cmd /c rd /s /q "+path)
    end sub
    =========

    Dim fso, msg
       Set fso = CreateObject("scrīpting.FileSystemObject")
       If (fso.FileExists("c:\testfile.txt")) Then
    'update the exist the file
          msg = " exists."
       Else
    'create the new file
          msg = " doesn't exist."
       End If
    msgbox msg


    ==========
  • QTP关于.java系统的启动方法

    2007-08-09 00:15:54

    自己上课学到的,总结下:
    ①。构造.bat文件,将启动命令(DOS命令行)写在批处理文件中。如:cd c:\ &java  *(系统名)  &exit

    ②。通过创建WSH对象,调用程序
    如:set mycmd = Create Object("Wscrīpt shell")
    mycmd.Run "cmd/c cd c\&java *(系统名) &exit"
  • 性能测试--瓶颈分析方法(转)

    2007-07-30 14:34:03

    1。内存分析方法

      内存分析用于判断系统有无内存瓶颈,是否需要通过增加内存等手段提高系统性能表现。

      内存分析需要使用的计数器:Memory类别和Physical Disk类别的计数器。内存分析的主要方法和步骤:

     (1)首先查看Memory\Available Mbytes指标

      如果该指标的数据比较小,系统可能出现了内存方面的问题,需要继续下面步骤进一步分析。

    注:  在UNIX/LINUX中,对应指标是FREE(KB)

      (2)注意Pages/sec、Pages Read/sec和Page Faults/sec的值

     操作系统回利用磁盘较好的方式提高系统可用内存量或者提高内存的使用效率。这三个指标直接反应了操作系统进行磁盘交换的频度。

      如果Pages/sec的技术持 续高于几百,可能有内存问题。Pages/sec值不一定大九表明有内存问题,可能是运行使用内存映射文件的程序所致。Page Faults/sec说明每秒发生页面失效次数,页面失效次数越多,说明操作系统向内存读取的次数越多。此事需要查看Pages Read/sec的计数值,该计数器的阀值为5,如果计数值超过5,则可以判断存在内存方面的问题。

      注:在UNIX/LINUX系统中,对于指标是(page)si和(page)so.

      (3)根据Physical Disk计数器的值分析性能瓶颈

      对Physical Disk计数器的分析包括对Page Reads/sec和%Disk Time及Aerage Disk Queue Length的分析。如果Pages Read/sec很低,同时%Disk Time和Average Disk Queue Length的值很高,则可能有磁盘瓶颈。但是,如果队列长度增加的同时Pages Read/sec并未降低,则是内存不足。

     注:在 UNIX/LINUX系统中,对应的指标是Reads(Writes)per sec、Percent of time the disk is busy和Average number of transactions waiting for service.

      2.处理器分析法

    (1)首先看System\%Total Processor Time 性能计数器的计数值

       该计数器的值体现服务器整体处理器利用率,对多处理器的系统而言,该计数器提醒所有CPU的平均利用率。如果该值持续超过90%,则说明整个系统面临着处理器方面的瓶颈,需要通过增加处理器来提高性能。

      注:多处理器系统中,该数据本身不大,但PUT直接负载状况极不均衡,也应该视作系统产生处理器方面瓶颈。

    (2)其次查看每个CPU的Processor\%Processor Time 和 Processor\%User  Time 和 Processor\%Privileged Time

       Processor\%User  Time 是系统非核心操作消耗的CPU时间,如果该值较大,可以考虑是否能通过友好算法等方法降低这个值。如果该服务器是数据库服务器, Processor\%User  Time 值大的原因很可能是数据库的排序或是函数操作消耗了过多的CPU时间,此时可以考虑对数据库系统进行优化。

    (3)研究系统处理器瓶颈

     查看 System\Processor Queue Length 计数器的值,当该计数器的值大于CPU数量的总数+1时,说明产生了处理器阻塞。在处理器的%Process Time很高时,一般都随处理器阻塞,但产生处理器阻塞时,Processor\%Process Time 计数器的值并不一定很大,此时就必须查找处理器阻塞的原因。

     %DOC Time 是另一个需要关注的内容,该计数器越低越好。在多处理器系统中,如果这个值大于50%,并且Processor\%Precessor Time非常高,加入一个网卡可能回提高性能。

    3。磁盘I/O分析方法

    (1)计算梅磁盘的I/O数

      梅磁盘的I/O数可用来与磁盘的I/O能力进行对比,如果经过计算得到的每磁盘I/O数超过了磁盘标称的I/O能力,则说明确实存在磁盘的性能瓶颈。

      每磁盘I/O计算方法

     RAID0计算方法:(Reads +Writes)/Number of Disks

     RAID0计算方法:(Reads +2*Writes)/2

     RAID0计算方法:[Reads +(4*Writes)]/Number of Disks

     RAID0计算方法:[Reads +(2*Writes)]/Number of Disks

      (2)与Processor\Privileged Time 合并进行分析

      如果在Physical Disk 计数器中,只有%Disk Time 比较大,其他值都比较适中,硬盘可能会是瓶颈。若几个值都比较大,且数值持续超过80%,则可能是内存泄漏。

      (3)根据Disk sec/Transfer进行分析

        一般来说,定义该数值小于15ms为Excellent,介于15~30ms之间为良好,30~60ms之间为可以接受,超过60ms则需要考虑更换硬盘或是硬盘的RAID方式了。

     4。进程分析方法

    (1)查看进程的%Processor Time值

      每个进程的%Processor Time反映进程所消耗的处理器时间。用不同进程所消耗的处理器时间进行对比,可以看出具体哪个进程在性能测试过程中消耗了最多的处理器时间,从而可以据此针对应用进行优化。

    (2)查看每个进程产生的页面失效

       可以用每个进程产生的页面失效(通过PRCESS\PAGE FAILURES/SEC计数器获得)和系统页面失效(可以通过MEMORY\PAGE FAILURES/SEC计数器获得)的比值,来判断哪个进程产生了最多的页面失效,这个进程要么是需要大量内存的进程,要么是非常活跃的进程,可以对其 进行重点分析。

      (3)了解进程的Process/Private Bytes

        Process/Private Bytes是指进程所分配的无法与其他进程共享的当前字节数量。该计数器主要用来判断进程在性能测试过程中有无内存泄漏。例如:对于一个IIS之上的 WEB应用,我们可以重点监控inetinfo进程的Private Bytes,如果在性能测试过程中,该进程的Private Bytes计数器值不断增加,或是性能测试停止后一段时间,该进程的Private Bytes仍然持续在高水平,则说明应用存在内存泄漏。

      注:在UNIX/LINUX系统中,对应的指标是Resident Size

      5。网络分析方法

      Network Interface\Bytes Total/sec为发送和接收字节的速率,可以通过该计数器值来判断网络链接速度是否是瓶颈,具体操作方法是用该计数器的值和目前网络的带宽进行比较。

     RAID0计算方法:[Reads +(2*Writes)]/Number of Disks

      (2)与Processor\Privileged Time 合并进行分析

      如果在Physical Disk 计数器中,只有%Disk Time 比较大,其他值都比较适中,硬盘可能会是瓶颈。若几个值都比较大,且数值持续超过80%,则可能是内存泄漏。

      (3)根据Disk sec/Transfer进行分析

        一般来说,定义该数值小于15ms为Excellent,介于15~30ms之间为良好,30~60ms之间为可以接受,超过60ms则需要考虑更换硬盘或是硬盘的RAID方式了。

     4。进程分析方法

    (1)查看进程的%Processor Time值

      每个进程的%Processor Time反映进程所消耗的处理器时间。用不同进程所消耗的处理器时间进行对比,可以看出具体哪个进程在性能测试过程中消耗了最多的处理器时间,从而可以据此针对应用进行优化。

    (2)查看每个进程产生的页面失效

       可以用每个进程产生的页面失效(通过PRCESS\PAGE FAILURES/SEC计数器获得)和系统页面失效(可以通过MEMORY\PAGE FAILURES/SEC计数器获得)的比值,来判断哪个进程产生了最多的页面失效,这个进程要么是需要大量内存的进程,要么是非常活跃的进程,可以对其 进行重点分析。

      (3)了解进程的Process/Private Bytes

        Process/Private Bytes是指进程所分配的无法与其他进程共享的当前字节数量。该计数器主要用来判断进程在性能测试过程中有无内存泄漏。例如:对于一个IIS之上的 WEB应用,我们可以重点监控inetinfo进程的Private Bytes,如果在性能测试过程中,该进程的Private Bytes计数器值不断增加,或是性能测试停止后一段时间,该进程的Private Bytes仍然持续在高水平,则说明应用存在内存泄漏。

      注:在UNIX/LINUX系统中,对应的指标是Resident Size

      5。网络分析方法

      Network Interface\Bytes Total/sec为发送和接收字节的速率,可以通过该计数器值来判断网络链接速度是否是瓶颈,具体操作方法是用该计数器的值和目前网络的带宽进行比较。

     RAID0计算方法:[Reads +(2*Writes)]/Number of Disks

      (2)与Processor\Privileged Time 合并进行分析

      如果在Physical Disk 计数器中,只有%Disk Time 比较大,其他值都比较适中,硬盘可能会是瓶颈。若几个值都比较大,且数值持续超过80%,则可能是内存泄漏。

      (3)根据Disk sec/Transfer进行分析

        一般来说,定义该数值小于15ms为Excellent,介于15~30ms之间为良好,30~60ms之间为可以接受,超过60ms则需要考虑更换硬盘或是硬盘的RAID方式了。

     4。进程分析方法

    (1)查看进程的%Processor Time值

      每个进程的%Processor Time反映进程所消耗的处理器时间。用不同进程所消耗的处理器时间进行对比,可以看出具体哪个进程在性能测试过程中消耗了最多的处理器时间,从而可以据此针对应用进行优化。

    (2)查看每个进程产生的页面失效

       可以用每个进程产生的页面失效(通过PRCESS\PAGE FAILURES/SEC计数器获得)和系统页面失效(可以通过MEMORY\PAGE FAILURES/SEC计数器获得)的比值,来判断哪个进程产生了最多的页面失效,这个进程要么是需要大量内存的进程,要么是非常活跃的进程,可以对其 进行重点分析。

      (3)了解进程的Process/Private Bytes

        Process/Private Bytes是指进程所分配的无法与其他进程共享的当前字节数量。该计数器主要用来判断进程在性能测试过程中有无内存泄漏。例如:对于一个IIS之上的 WEB应用,我们可以重点监控inetinfo进程的Private Bytes,如果在性能测试过程中,该进程的Private Bytes计数器值不断增加,或是性能测试停止后一段时间,该进程的Private Bytes仍然持续在高水平,则说明应用存在内存泄漏。

      注:在UNIX/LINUX系统中,对应的指标是Resident Size

      5。网络分析方法

      Network Interface\Bytes Total/sec为发送和接收字节的速率,可以通过该计数器值来判断网络链接速度是否是瓶颈,具体操作方法是用该计数器的值和目前网络的带宽进行比较。

  • 性能测试(转)

    2007-07-30 14:33:21

    由于性能测试功能测试有很大的区别,所以讨论出的结果可能与预先的设想有一定的区别
    性能测试的目的:
    为了验证系统是否达到用户提出的性能指标,同时发现系统中存在的性能瓶颈,起到优化系统的目的
    性能测试指标的来源:
    用户对各项指标提出的明确需求;如果用户没有提出性能指标则根据用户需求、测试设计人员的经验来设计各项测试指标。(需求+经验)
    主要的性能指标:
    服务器的各项指标(CPU、内存占用率等)、后台数据库的各项指标、网络流量、响应时间。
    BUG观点:
    1、性能测试就象人在无风情况下跑步(正常情况下的性能指标);
    2、压力测试就象人在微风中跑步(在正常的基础上加大多少百分比压力的性能指标);
    3、负载测试就象人在强风中跑步(不断加压,直到系统崩溃);
    HTTP观点:
    1、 负载测试是正常情况下持续的加压;
    2、 压力测试是直接加压达到一个极限值。 
    大家统一的观点:
    性能测试、压力测试、负载测试密不可分,可统称为性能测试。
    性能测试要点:
       1、 性能测试是在功能测试完成之后进行。
      2、 性能测试计划、方案一般与测试用例统一在一个文档里。
      3、 测试环境应尽量与用户环境保持一致。
      4、 性能测试一般使用测试工具和测试人员编制测试脚本来完成,性能测试的环境应单独运行尽量避免与其他软件同时使用。
      5、 性能测试的重点在于前期数据的设计与后期数据的分析。
       6、性能测试的用例主要涉及到整个系统架构的问题,所以测试用例一旦生成,改动一般不大,所以做性能测试的重复使用率一般比较高。(说明:当系统中出现 的某个功能点需要修改,它一般只会影响到功能测试的设计用例,而对于性能测试,很少影响到性能测试的设计用例。但是如果某个功能有较大的修改,性能测试也 应该进行重新测试。)
  • 手机软件测试

    2007-07-10 00:58:38

     手机作为专用的消费类电子产品需要进行以下测试:可靠性测试(对于硬件则是RQT;对于软件则是field trial);标准符合性测试(FTA);互操作性测试(IOT);安全性测试(安规测试);强度测试等。

        其中,有些种类的测试,例如FTA,有严格的标准(GSM、3GPP等)来明确被测的功能点,测试人员所要做的是在测试用例的编写中体现出这些功能点,并且尽量营造这些测试用例所需的运行环境来完成测试,并反馈测试结果。但是对于性能测试, 就没有这样的规范供测试人员来参考,因此性能测试需要进行哪些用例以及用例通过的指标的高低都有很大弹性,在很大程度上受限于测试人员的经验和项目的资源 和进度压力。如何在资源、进度和质量之间找到平衡点是产品负责人需要考虑的问题,测试人员可以左右的是划定性能测试的范围、明确与性能测试相关的设计需求 (提高产品的可测试性)以及通过自动化测试工具等手段来进行更加有效的性能测试,提高产品的质量。

        一、手机性能测试的范围

        性能测试强调长时间、重复或者高强度的进行某些操作,来验证产品在各种极限条件下的表现。性能测试隶属于软件测试中的系统测试,它对软件在集成系统中运行的性能行为进行测试,旨在及早确定和消除软件中与构架有关的性能瓶颈。通过对测试数据和log的分析,还可能找出被测系统隐藏的缺陷。终端作为移动通讯类电子产品,其性能测试又主要和其实现的功能相关,大致可分为以下几类:

        1. 时间相关。

        时间相关的性能测试可分为长时间保持测试和限定时间反应测试。

         长时间保持测试主要是测试终端长时间稳定进行某项功能的能力。主要包括长时间待机能力、长时间CS域业务保持能力、长时间PS域业务保持能力、长时间组合 业务保持能力等。长时间待机测试,就是根据手机电池的能力连续不间断待机一定时间(例如4天),之后验证手机是否还能够发起主叫和被叫业务,能够发起主 叫,表示终端在长时间待机后自身还处于正常状态,能够发起被叫,说明终端在睡眠模式下可以正常接收寻呼。长时间CS域业务保持测试,就是根据手机电池的能 力连续不间断进行语音通话或者视频通话一定时间(例如2小时),测试通话期间图象声音是否连续、清晰,是否有单通现象出现,是否会有手机板子过热现象。长 时间PS域业务保持测试,主要是通过持续进行WWW业务、ftp业务或者流媒体业务一定时间(例如2小时),测试进行数据业务期间上下行数据传输率是否稳 定,网页显示是否流畅,流媒体播放是否连续等。长时间组合业务保持测试,就是同时保持CS和PS域业务一段时间,以验证终端长时间进行组合业务的能力。

         限定时间反应测试主要是测试终端在规定时间内对用户的操作作出反应,给出操作结果的能力。主要包括开机驻留时延、关机时延、CS域业务接入时延、PS域业 务接入时延、本地应用的操作时延等。开机驻留时延,是指从用户按下开机键(终端上电、系统引导、启动任务、搜索网络、完成位置更新)到终端进入待机界面, 提示用户可以进行正常服务的总时间。关机时延,是指从用户按下关机键(终端完成网络detach、将RAM中修改过的数据写回flash)到终端完全下电 所需的总时间。CS域业务接入时延,是指在进行语音或视频电话时从按下拨号键到听到对方回铃声所需总时间,由于该过程需要在网络侧分配资源,所以测试结果 可能会受到当前网络资源可用程度的影响,例如在网络负荷高的时候申请CS 64k业务时,网络侧需要重新组织或合并无线资源来满足业务要求,所需时间相对会长一些。PS域业务接入时延,是指在进行数据业务时从开始连接到能正常进 行数据业务所需总时间。本地应用的操作时延,是指完成某些本地操作维护功能所需的时间,例如打开电话薄,在电话薄里查找联系人,存储新建的联系人,存储短 信,存储多媒体文件,打开浏览器,播放多媒体文件等所需时延,这些时延如果过长,也会极大地降低用户体验的满意度。

        2. 次数相关。

         次数相关的性能测试是测试终端重复稳定地进行某项功能的能力。包括开关机成功率、小区初搜成功率、小区重选成功率、CS域业务成功率、PS域业务成功率、 组合业务成功率、切换成功率、本地应用的成功率等。这种重复操作包括很多对象被多次创建和释放,因此可能会发现潜在的内存泄漏等问题。开关机成功率测试, 主要是检验多次开机是否会有物理层不能正确收到初搜命令的情况,关机不完全也可能会导致下一次开机失败,以及在某些情况下系统死机后只能通过插拔电池板来 重新开机。CS域业务成功率的测试,是指通过进行一定次数的主叫或者被叫,统计失败的次数,对失败原因进行归类,分析是否能够找到和终端相关的失败原因。 PS域业务成功率、组合业务成功率、切换成功率的测试方法也类似。本地应用的成功率包括多次存储再删除文件、联系人、短信等操作,以及多次打开某个应用或 执行某类操作来对该应用的稳定性进行测试,找出瓶颈。

        3. 并发业务。

        并发测试主要是测试终端同时进行多项业务时表现出的处理能力。例如同时进行CS域语音业务和PS域下载业务,或者在MP3播放的同时进行WWW上网业务,以测试协议栈、操作系统和处理器对并发业务的支持能力。

        4. 负载测试。

        负载测试主要是验证系统的负载工作能力。系统配置不变的条件下,在一定时间内,终端在高负载情况下的性能行为表现。例如同时进行多个ftp下载,使下行传输率接近极限值,观察终端是否可以正常工作。

        二、手机性能测试的方法

        手机性能测试的方法按照自动化程度不同可分为手工测试和自动测试。

         手工测试主要是通过测试人员手动操作,并借助某些监测仪器和工具,来验证手机性能。但由于手机功能众多,并且性能测试工作量大,如果单个测试工程师靠手动 按键来执行所有测试用例,花费的时间少则几小时,多则需要几天的时间,这样耗费大量测试时间的同时也容易让测试工程师产生疲倦甚至是厌倦心理,很容易造成 测试的遗漏。手机测试中 常碰到很多重复性高的工作,如发送数条 SMS 或者 MMS 以验证其收发成功率以及稳定性、连续进行多次呼叫、多次对文件系统进行添加删除操作、多任务多进程情况下的冲突测试以及极限测试等等,都是重复性高的工 作,手动执行的话费时费力,如果能有一套自动执行的机制,将能大大提高测试的效率。

        由此产生了对手机自动化测试工具的需求。手机这种板机的MMI功能测试不同于基于PC上的MMI测试,后者借助PC平台,目前市场上已有非常多功能强大且通用的自动测试工具支持其测试,如比较典型的有Winrunner, Robot, Loadrunner等等,但这些工具通常不能兼容到象手机这种嵌入式系统中来。这就要求测试人员能够基于当前平台进行二次开发,来满足自动化测试的需求。

        手机的自动化性能测试一般分为以下几个步骤进行:

        1. 系统分析

        将系统的性能指标转化为性能测试的具体目标。通常在这一步骤里,要分析被测系统结构,结合性能指标,制定具体的性能测试实施方案。这要求测试人员对被测系统结构和实施业务的全面掌握。

        2. 建立虚拟用户脚本

         将业务流程转化为测试脚本,通常指的是虚拟用户脚本或虚拟用户。虚拟用户通过驱动一个真正的客户程序来模拟真实用户。在这一步骤里,要将各类被测业务流程 从头至尾进行确认和记录,弄清这些过程可以帮助分析到每步操作的细节和时间,并能精确地转化为脚本。此过程类似制造一个能够模仿人的行为和动作的机器人过 程。这个步骤非常重要,在这里将现实世界中的单个用户行为比较精确地转化为计算机程序语言。如果对现实世界的行为模仿失真,不能反映真实世界,性能测试的 有效性和必要性也就失去了意义。

        3. 根据用户性能指标创建测试场景

        根据真实业务场景,对生成的测试脚 本进行复制和控制,转化为满足性能测试指标的测试用例集。在这个步骤里,对脚本的执行制定规则和约束关系。具体涉及到对业务类型,并发时序等参数的设置。 这好比是指挥脚本运行的司令部。这个步骤十分关键,往往需要结合用户性能指标进行细致地分析。

        4. 运行测试场景,同步监测应用性能

        在性能测试运行中,实时监测能让测试人员在测试过程中的任何时刻都可以了解应用程序的性能优劣。系统的每一部件都需要监测:协议栈,MMI应用程序,内存占用情况,驱动程序运行状态等。实时监测可以在测试执行中及早发现性能瓶颈。

        5. 性能测试的结果分析和性能评价

         结合测试结果数据,分析出系统性能行为表现的规律,并准确定位系统的性能瓶颈所在。在这个步骤里,可以利用数学手段对大批量数据进行计算和统计,使结果更 加具有客观性。在性能测试中,需要注意的是,能够执行的性能测试方案并不一定是成功的,成败的关键在于其是否精确地对真实世界进行了模拟。
    在整个性能测试过程中,自动化测试工具的选择只能影响性能测试执行的复杂程度,简便一些或繁杂一些;但人的分析和思考却会直接导致性能测试的成败。所以这里着重于对性能测试思路的整理。测试工具的介绍可以参看有关自动化测试工具的资料。
1033/6<123456>