发布新日志

  • 解析QTP资源文件(转)

    2010-01-28 20:26:30

    ------------------------------------
    ' 从XML格式的资源文件中获取对象
    '------------------------------------
    Public Function GetResource(Byval XmlFile,byval ResourceFile)
     Dim XmlObj,i,j,curRow
     Dim ObjRoot,Children
     Dim childCnt,Parent
     Dim Layer,CurLayerIndex()
     Dim sourceID,ParentID,sourceClass,sourceName
     
     Dim ExcelApp,Exlsheet,ExcelWorkBook
     Set ExcelApp = CreateObject("Excel.Application")
     ExcelApp.Visible = True
     ExcelApp.DisplayAlerts = False
     Set ExcelWorkBook = ExcelApp.Workbooks.Open(ResourceFile)
     Set Exlsheet = ExcelApp.Sheets("对象库")
     Exlsheet.Activate
     
     Set XmlObj = XMLUtil.CreateXMLFromFile(XmlFile)
     
      '---当前行
     curRow = 1
     '----子对象个数
     childCnt = 1
     
     '---------获取根对象
     Set bjRoot = XmlObj.GetRootElement().ChildElements().ItemByName("qtpRep:Objects")
     set  Children = ObjRoot.ChildElementsByPath( "./qtpRep:Object" )
     
     For i = 1 to Children.count()
      ' 第一层对象
      Layer =  0
      ReDim Preserve CurLayerIndex(Layer)
      CurLayerIndex(Layer )  = i
      j = 1
      Set Child = Children.item(i) 
      curRow = curRow + 1
      Parent = curRow - 1
      Set Children = Child.ChildElementsByPath( "./qtpRep:ChildObjects/qtpRep:Object" )
     
      sourceID =  curRow - 1
      Call GetAttrib(Child,sourceClass,sourceName)
      ParentID = 0
      Exlsheet.cells(curRow,1) = sourceID
      Exlsheet.cells(curRow,2) = sourceName
      Exlsheet.cells(curRow,3) = ParentID
      Exlsheet.cells(curRow,4) = sourceClass
      Exlsheet.cells(curRow,5) = "(" + chr(34) + sourceName + chr(34) + ")"
     
      If Children.count() >0  Then
       Layer = Layer + 1
       ReDim Preserve CurLayerIndex(Layer)
      End If
     
      While Children.count() > 0
        If  Children.count() >= j  Then
         CurLayerIndex(Layer )  = j
         Set Child = Children.item(j)
        
         curRow = curRow + 1
         sourceID =  curRow-1
         Call GetAttrib(Child,sourceClass,sourceName)
         ParentID = Parent
         Exlsheet.cells(curRow,1) = sourceID
         Exlsheet.cells(curRow,2) = sourceName
         Exlsheet.cells(curRow,3) = ParentID
         Exlsheet.cells(curRow,4) = sourceClass
         Exlsheet.cells(curRow,5) = "(" + chr(34) + sourceName + chr(34) + ")"
        
         childCnt = Child.ChildElementsByPath( "./qtpRep:ChildObjects/qtpRep:Object" ).count()
     
         If  childCnt > 0 Then
          Layer = Layer + 1
          ReDim Preserve CurLayerIndex(Layer)
          Set Children = Child.ChildElementsByPath( "./qtpRep:ChildObjects/qtpRep:Object" )
          Parent = curRow - 1
          j = 1
          CurLayerIndex(Layer )  = j
         Else
          j = j + 1
         End If
        Else
         temprow = CurRow
         parent = CInt(Exlsheet.cells(parent + 1,3))
        
         Layer = Layer - 1
         Set Child = Child.Parent.Parent
         Set Children = Child.Parent.Parent.ChildElementsByPath( "./qtpRep:ChildObjects/qtpRep:Object" )
                  
          j = CurLayerIndex(Layer) + 1
        End If
      Wend
      Set Children = Child.Parent.ChildElementsByPath( "./qtpRep:Object" )
     Next
     ExcelWorkBook.save
     ExcelApp.Quit
     Set ExcelApp = Nothing
    End Function


    '--------------------------------------
    ' 获取资源对象的描述
    '--------------------------------------
    Public Function GetAttrib(byval Obj,byref attrClass,byref attrName)
     Dim attrIdx
     GetAttrib = ""
     Set CurPara = Obj
     Set attribs = CurPara.Attributes()
     Set attr = attribs.Item(1)
     attrClass = attr.Value()
     GetAttrib = GetAttrib + attr.name() + "=" + chr(34) + attrClass + chr(34) + " "
     Set attr = attribs.Item(2)
     attrName = attr.Value()
     GetAttrib = GetAttrib + attr.name() + "=" + chr(34) + attrName + chr(34)

    End Function

  • QTP中类的基本使用方法(转)

    2010-01-28 20:24:02

    对于共同开发的自动化测试项目,实例方便的调用是很重要的。QTP采用的是vbscript脚本,所以也支持类,但是应为vbs并不支持类的继承,所以只能算作一种“拟类”。采用类对脚本进行封装,有很多好处,对于测试执行人员,可以通过项目情况对封装的类进行调用,而并不必关心类实现的细节。

    此处对QTP类的使用进行一些总结。

    '类名称

    Class TestCase

          Private DataFile

          

          ' ----用例预置条件

          Private Function CasePrepare()

                 

          End Function

          

          ' ----测试数据输入

          Public Function CaseData(byval RowNum)

                 

          End Function

          

          ' ----测试执行

          Public Function CaseRun()

                 

          End Function

          

          ' ----测试结果检查

          Public Function CaseCheck()

                 

          End Function

          

          '获取测试用例号

          Public Property Get CaseID()

                 CaseID = "TestCase_0001"

          End Property

          

          '获取测试用例名称

          Public Property Get CaseName()

                 CaseName = "用户登录"

          End Property

          

          '----构造函数----

          Private Sub Class_Initialize() 

                 DataFile = "C:\autotest\data.xls"

                 

                 Call CasePrepare()

       End Sub

          

          '----解构函数----

          Private Sub Class_Terminate()

                 

          End Sub

     

    End Class

     

    其中Class_initialize为构造函数,类初始化时调用,此处预设了数据文件,并在此处调用了用例预置函数。

    Class_Terminate为解构函数,一般用于释放类执行过程种占用的内存等

    Property Get用于获取类的属性,此处获取该测试用例类的ID,和名称属性

     

    模拟测试用例,类中包含了测试用例的几个部分:

    CasePrepare测试预置条件,如测试用户登录,此处可以判断登录界面是否已经显示

    Casedata:测试数据准备,如测试用户登录,此处可以载入登录用户、登录密码等数据

    CaseRun:测试执行,如测试用户登录,此处可以执行输入验证码,点击登录按钮等操作

    CaseCheck:执行结果检查,如测试用户登录,此处可以对登录结果进行检查,如页面是否正确跳转,如用户、密码不对,是否正确显示提示信息等。

     

    具体在QTP中的使用如下:

    Dim CaseLogin

    Set CaseLogin = New TestCase

    CaseLogin.CaseData 2载入数据文件中的第2行数据作为测试输入

    CaseLogin.CaseRun

    If CaseLogin.CaseCheck Then

     Case_LogInfo “测试用例”CaseLogin. CaseID & “测试通过!”,MicPass

    Else

    Case_LogError “测试用例”CaseLogin. CaseID & “测试失败!”,MicFail

    End If

  • QTP中时间的处理(转)

    2010-01-28 20:23:22

    自动化测试中,经常遇到页面需要输入时间,而这个时间很多时候是当前时间之后某个范围之类才有效。我们采用数据驱动时如果采用绝对时间,则数据复用性就很差了,数据需要经常修改。所以采用相对时间

     

    下面的函数用于获取相对时间

    '------------------------------------------------------------------------

    '获取以当前时间为参照的偏移时间

    'increTime: 偏移时间量,可使用负数 格式:day:hour:min:sec  如 1:3:8:23

    '------------------------------------------------------------------------

    Public Function GetTime(byval increTime)

           Dim y,m,d,h,n,s,timeArray

          

           timeArray = split(increTime,":",-1,1)

           d= timeArray(0)

           h= timeArray(1)

           n= timeArray(2)

           s= timeArray(3)

          

           GetTime = dateadd("d",d,now)

           GetTime = dateadd("h",h,GetTime)

           GetTime = dateadd("n",n,GetTime)

           GetTime = dateadd("s",s,GetTime)

          

           ' change to GE Time type

           Dim dateArr,timeArr

           timeArray = split(GetTime," ",-1,1)

           dateArr = split(timeArray(0),"-",-1,1)

           y = dateArr(0)

           m = ExpandByZero("L", dateArr(1),2)

           d = ExpandByZero("L", dateArr(2),2)

          

           timeArr = split(timeArray(1),":",-1,1)

           h = ExpandByZero("L", timeArr(0),2)

           n = ExpandByZero("L", timeArr(1),2)

           s = ExpandByZero("L", timeArr(2),2)

          

           GetTime = y  & "-" & m & "-" & d & " " & h & ":" & n & ":" & s

     

    End Function

    '------------------------------------------------------------------------

    '以0扩展当前字符串

    'way: 扩展方式 L-左扩,R-右扩

    'OrigStr: 原字符串

    'HopeLen: 扩展后字符长度

    '------------------------------------------------------------------------

    Public Function ExpandByZero(byval way,byval OrigStr,byval HopeLen)

       Dim i,ZeroStr

       ZeroStr = ""

       For i =1 to HopeLen - len(OrigStr)

                  ZeroStr = ZeroStr & "0"

       Next

       If way = "L" Then

                  ExpandByZero = ZeroStr & OrigStr

           elseif way = "R" Then

                  ExpandByZero = OrigStr & ZeroStr

           else

                  Exit Function

       End If

    End Function

  • QTP中页面的基本异常检查(转)

    2010-01-28 20:22:19

    页面异常输入测试系统测试的一个重要方面,但是因为比较繁杂,人工测试时往往难以完全覆盖,此时采用自动化测试,就有相当的优势了。

    如下图就是一个典型的信息录入页面

    其中就包括很多异常输入测试点:

    名称不能包含特殊字符,固定的电话格式,固定的手机格式,银行账号(必须全为数字),付费号码长度限制,手机号码格式、长度限制,Email格式限制等

     

    其实异常策略是有通用性的,现总结如下:

    1. exp@@SpecialChar(e_chr)    包含特殊字符,e_chr为指定的特殊字符

    2. exp@@StringLenMax(e_len)  字符串超过最大长度,e_len为最大长度值

    3. exp@@StringLenMin(e_len)  字符串不足最小长度,e_len为最小长度值

    4. exp@@String               字符串包含数字(要求全字符)

    5. exp@@Num                字符串包含字符(要求全数字)

    6. exp@@NumMax(e_max)   输入超过指定最大值,e_max,最大值

    6. exp@@NumMin(e_min)   输入不足指定最大值,e_mmin,最小值

    7. exp@@NumLenMax(e_len)   数值长度超限,e_len,长度最大值

    8. exp@@NumLenMin(e_len)   数值长度不足,e_len,长度最小值

    9. exp@@StringPre(e_pre)      字符串不为指定前缀,e_pre,前缀值

    10. exp@@NumPre(e_pre)      数值不使用指定前缀,e_pre,前缀值

    11. exp@@Email              数值不为标准Email格式

    12. exp@@Need              必输入项,提供空字符串

     

     

    具体实现上,在准备数据文件时,提供两种数据:

    1.     每个字段的默认输入值,即正确值。也是自动化程序执行时默认输入的数据

    2.     异常值,针对每个字段,提供该字段可能需要的异常策略,对所有异常进行遍历。

    第一行为默认值,第二行为字段对应的异常策略

     

    分三个函数来处理

    1.     执行函数

     

    Public Sub excep_OpUser()

                 routingname = "企业用户输入-异常测试"

                载入数据表数据的第2

    GE_SetCurRow OppDataFile,"企业用户",2

                 Dim objStr,oScript,i

                 set bjStr = CreateObject("Scripting.Dictionary")

                 set Script. = CreateObject("Scripting.Dictionary")

                 

                 根据数据表字段设置每个字段的QTP执行语句

                 for i = 1 to DataTable.GetSheet("UserData").GetParameterCount

                        if DataTable.GetSheet("UserData").GetParameter(i)="企业名称" Then _

                                objStr.add DataTable.value(i,"UserData"),".WebEdit("opername").set "

                        。。。。

                 Next

                 

                 调用异常数据生成函数,返回值保存在dictionary对象oScript

                 Gen_excepData(objStr,oScript)

                 

    依次对含异常策略的字段进行异常测试

                 For i = 0 to oScript.Count-1

                        Call OpUserSet(1,oScript(i))

                 Next

                 

                 set bjStr = Nothing

                 set Script. = Nothing

          End Sub

     

    2.     异常数据生成函数

     

    Public Function Gen_excepData(byval dObj,byRef oScript)

          异常值,正确值,异常类型,异常参数

    Dim errorValue,CorrectValue,expType,expPara

          Dim objName,scriptstr

          Dim i,j,expItem

          expItem = 0   记录异常数

          Randomize

          

          for i = 1 to DataTable.GetSheet("UserData").GetParameterCount

                 第一行数据为默认正确数值

                 CorrectValue = DataTable.GetSheet("UserData").GetParameter(i).ValueByRow(1)

                 datatable.SetCurrentRow 2

                 

                 if Instr(Datatable.value(i,"UserData"),"exp@@")>0 Then

                        objName = dObj.Item(Datatable.value(i,"UserData"))

                        同一字段多种异常策略的处理

                        arr1 = split (Datatable.value(i,"UserData"),"|",-1,1)

                        For j = 0 to Ubound(arr1)

                              获取异常类型和异常参数

    If RegExpTest("exp@@.{1,}\(.{1,}\)",arr1(j)) Then

                                      exptype = Mid(arr1(j),6,InStr(arr1(j),"(")-6)

                                      expPara = Mid(arr1(j),InStr(arr1(j),"(")+1,InStr(arr1(j),")")-InStr(arr1(j),"(")-1)

                               Else

                                      expType = replace(arr1(j),"exp@@","")

                               End If                  

                               不同策略对应的数据生成

                               select Case expType

                               Case "SpecialChar"

                                      errorValue = Replace(CorrectValue,Right(CorrectValue,1),"%")

                                      scriptstr = objName + chr (34) + errorValue + chr(34)

                                      expItem = expItem + 1

                                      oScript.add "excepData" & expItem,scriptstr

                                      errorValue = Replace(CorrectValue,Right(CorrectValue,1),"'")

                                      scriptstr = objName + chr (34) + errorValue + chr(34)

                                      expItem = expItem + 1

                                      oScript.add "excepData" & expItem,scriptstr

                                      errorValue = Replace(CorrectValue,Right(CorrectValue,1),"/")

                                      scriptstr = objName + chr (34) + errorValue + chr(34)

                                      expItem = expItem + 1

                                      oScript.add "excepData" & expItem,scriptstr

                                      errorValue = Replace(CorrectValue,Right(CorrectValue,1),":")

                                      scriptstr = objName + chr (34) + errorValue + chr(34)

                                      expItem = expItem + 1

                                      oScript.add "excepData" & expItem,scriptstr

                                      errorValue = Replace(CorrectValue,Right(CorrectValue,1),"*")

                                      scriptstr = objName + chr (34) + errorValue + chr(34)

                                      expItem = expItem + 1

                                      oScript.add "excepData" & expItem,scriptstr

                                      errorValue = Replace(CorrectValue,Right(CorrectValue,1),"&")

                                      scriptstr = objName + chr (34) + errorValue + chr(34)

                                      expItem = expItem + 1

                                      oScript.add "excepData" & expItem,scriptstr

                                      errorValue = Replace(CorrectValue,Right(CorrectValue,1),"?")

                                      scriptstr = objName + chr (34) + errorValue + chr(34)

                                      expItem = expItem + 1

                                      oScript.add "excepData" & expItem,scriptstr

                                      errorValue = Replace(CorrectValue,Right(CorrectValue,1),"""")

                                      scriptstr = objName + chr (34) + errorValue + chr(34)

                                      expItem = expItem + 1

                                      oScript.add "excepData" & expItem,scriptstr

                                      errorValue = Replace(CorrectValue,Right(CorrectValue,1),"<")

                                      scriptstr = objName + chr (34) + errorValue + chr(34)

                                      expItem = expItem + 1

                                      oScript.add "excepData" & expItem,scriptstr

                                      errorValue = Replace(CorrectValue,Right(CorrectValue,1),">")

                                      scriptstr = objName + chr (34) + errorValue + chr(34)

                                      expItem = expItem + 1

                                      oScript.add "excepData" & expItem,scriptstr

                                      errorValue = Replace(CorrectValue,Right(CorrectValue,1),"|")

                                      scriptstr = objName + chr (34) + errorValue + chr(34)

                                      expItem = expItem + 1

                                 

  • 汇总(转载)

    2009-12-23 16:07:16

  • LoadRunner案例分析之六(转)

    2009-12-22 19:38:16

    这个案例起源于不久前在51testing上的一个帖子,其实我这里的绝大多数的案例都是来源于51testing论坛,正所谓来源于生活,高于生活嘛(怎么感觉在说艺术,嘿嘿)。其实应该是来源于51,服务于51。

    这个问题大概是这样的:LoadRunner对服务器进行压力测试的时候需要设置检查点,需要检查的内容是从服务器端返回的值,检查的方法是跟一个Excel文件中的内容进行比对。

    从服务器端取值利用关联函数这个当然不用多说,关键是进行比对的方法,如何从Excel中取内容呢?QTP对Excel的支持非常好,QTP的数据都是集成在Excel中的,而且QTP的语言也是VBScript,利用QTP从Excel中取内容当时非常容易。但是LoadRunner对Excel的支持就没有那么好了,而且LoadRunner主要支持C,Java等语言。

    当然我们也可以利用其他的方法解决问题,比如把Excel文件中的内容copy到文本文件,利用LoadRunner本身支持的参数文件进行对照,这样读取的时候就变的非常容易了。当然这里我们是针对C读取Excel文件的问题,所以如何利用C语言读取Excel文件的内容就是问题的关键了,下面就介绍一个利用VC读取Excel文件的方法。

    在开发软件时,经常要将数据输出到Excel 2000中,在Excel 2000中对该数据进行进一步地格式化处理或进行计算处理。在Visual Basic中处理起来较简单,Excel 2000的VB编程帮助中有较为详细的介绍。在Visual C++中如何进行处理了?利用Excel 2000的ActiveX Automate功能,处理起来同VB中类似。但要注意以下几点:
    对于对象的属性值的读取或赋值,需要用GetProperty()或SetProperty(NewValue)函数,不能象VB中直接通过属性名称取值或赋值。例如:Worksheet.GetCount(), Worksheet.SetName(“Sheet1”)。
    对集合对象中的成员对象的引用,必须使用集合对象的GetItem()函数。例如:Worksheets.GetItem(ColeVariant ((long)1))或Worksheets.GetItem(ColeVariant(“Sheet1”))取得第一个工作表。
    在COM接口中,时常用到Variant,BSTR,SafeArray数据类型。Variant数据类型是一个联合,可表示几乎所有的类型的数据,具体用法见MSDN中的相关介绍,类_variant_t是对VARIANT数据类型的封装。在Excel 2000的VB编程帮助中,如果提到某函数或属性需要一个值,该值的数据类型通常是Variant,在封装Excel 2000对象的类定义中,说明了具体需要的数据类型。BSTR是一个包括了字符串和字符串长度的数据结构,类_bstr_t是对BSTR数据类型的封装。在Excel 2000的VB编程帮助中提到的字符串通常指BSTR。具体函数参数或属性的数据类型,见封装该对象的类的定义。SafeArray是一个包括数组和数组边界的结构,数组边界外的内容不允许访问。在Excel 2000的VB编程帮助中提到的数组是指SafeArray。关于SafeArray的处理,请见MSDN的相关帮助。
    对于缺省参数和缺省值。在VB中,函数的参数可以空缺,在VC++中不允许,必须将所有的参数填写完全。如果你希望指定某个参数为缺省值,根据参数数据类型的不同,可指定不同的缺省值。当参数数据类型为字符串时,可以用长度为0的字符串。如果参数是Variant类型,可用常量vtMissing,该常量在comdef.h中定义。也可用_variant_t(DISP_E_PARAMNOTFOUND, VT_ERROR)产生一个Variant对象。
    Excel对象中的集合对象有时包括的子对象是不一定的,例如:Range对象,可以表示Cell的集合,也可以表示Column的集合或Row的集合,Range.GetItem(1)可以返回Cell或Column或Row对象。
    对对象的引用或传递对象,使用IDispatch类对象,有时利用Variant对IDispatch进行包装。
    以下是一段源程序,演示如何启动Excel 2000,利用一个模板文件产生一个新文档,在该文档的”Sheet1”工作表的第一个单元中填写一段文字,设置第一列的列宽,然后调用一个模板中的宏,执行一段程序,最后打印预览该Excel文档。模板文件名称:MyTemplate.xlt。程序在Visual C++ 6.0 sp4,Windows 2000 Professional sp-1下调试通过。
    首先利用Visual C++ 6.0,建立一个MFC基于对话框的工程项目,共享DLL,Win32平台。工程名称ExcelTest。在主对话框中加入一个按钮,
    ID IDC_EXCELTEST
    Caption Test Excel
    双击该按钮,增加成员函数void CExcelTestDlg::OnExceltest()。
    在BOOL CExcelTestApp::InitInstance()中,dlg.DoModal();之前增加代码:
    if (CoInitialize(NULL)!=0)
    {
    AfxMessageBox(”初始化COM支持库失败!”);
    exit(1);
    }
    在return FALSE; 语句前,加入:
    CoUninitialize();
    选择Menu->View->ClassWizade,打开ClassWizade窗口,选择Add Class->From a type library,选择D:\Program Files\Microsoft Office\office\Excel9.OLB(D:\Program Files\Microsoft Office\是本机上Microsoft Office 2000的安装目录,可根据个人机器上的实际安装目录修改)。选择_Application、Workbooks、_Workbook、Worksheets、_Worksheet、 Range,加入新类,分别为_Application、Workbooks、_Workbook、Worksheets、_Worksheet、 Range,头文件Excel9.h,源文件Excel9.cpp。
    在ExcelTestDlg.cpp文件的头部,#include “ExcelTestDlg.h”语句之下,增加 :
    #include “comdef.h”
    #include “Excel9.h”
    在void CExcelTestDlg::OnExceltest() 函数中增加如下代码:
    void CExcelTestDlg::OnExceltest()
    {
    _Application ExcelApp;
    Workbooks wbsMyBooks;
    _Workbook wbMyBook;
    Worksheets wssMysheets;
    _Worksheet wsMysheet;
    Range rgMyRge;
    //创建Excel 2000服务器(启动Excel)
    if (!ExcelApp.CreateDispatch(”Excel.Application”,NULL))
    {
    AfxMessageBox(”创建Excel服务失败!”);
    exit(1);
    }
    //利用模板文件建立新文档
    wbsMyBooks.AttachDispatch(ExcelApp.GetWorkbooks(),true);
    wbMyBook.AttachDispatch(wbsMyBooks.Add(_variant_t(”g:\\exceltest\\MyTemplate.xlt”)));
    //得到Worksheets
    wssMysheets.AttachDispatch(wbMyBook.GetWorksheets(),true);
    //得到sheet1
    wsMysheet.AttachDispatch(wssMysheets.GetItem(_variant_t(”sheet1″)),true);
    //得到全部Cells,此时,rgMyRge是cells的集合
    rgMyRge.AttachDispatch(wsMysheet.GetCells(),true);
    //设置1行1列的单元的值
    rgMyRge.SetItem(_variant_t((long)1),_variant_t((long)1),_variant_t(”This Is A Excel Test Program!”));
    //得到所有的列
    rgMyRge.AttachDispatch(wsMysheet.GetColumns(),true);
    //得到第一列
    rgMyRge.AttachDispatch(rgMyRge.GetItem(_variant_t((long)1),vtMissing).pdispVal,true);
    //设置列宽
    rgMyRge.SetColumnWidth(_variant_t((long)200));
    //调用模板中预先存放的宏
    ExcelApp.Run(_variant_t(”CopyRow”),_variant_t((long)10),vtMissing,vtMissing,
    vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,
    vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,
    vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,
    vtMissing,vtMissing,vtMissing,vtMissing,vtMissing,vtMissing);
    //打印预览
    wbMyBook.SetSaved(true);
    ExcelApp.SetVisible(true);
    wbMyBook.PrintPreview(_variant_t(false));
    //释放对象
    rgMyRge.ReleaseDispatch();
    wsMysheet.ReleaseDispatch();
    wssMysheets.ReleaseDispatch();
    wbMyBook.ReleaseDispatch();
    wbsMyBooks.ReleaseDispatch();
    ExcelApp.ReleaseDispatch();
    }
    添加完以上程序后,可运行看结果。

     

  • LoadRunner案例分析之五(转)

    2009-12-22 19:36:41

    问题源于51testing的一个帖子,一个朋友想要把从服务器端利用关联取回来的值跟预定的值进行对比,以此判断是否执行成功。关联函数当然用的是web_reg_save_param。预定的期望值存储在Excel文件的固定一列。

    我首先想到的就是利用方法读取Excel文件,然后在LoadRunner中利用c函数进行对比。其实Excel提供的接口相当强大,以前我们经常利用一些VBscript提供的API进行编程,解析Excel中的内容。而且Mercury的功能测试工具Quick Test Professinal提供了对Excel的强大支持。测试数据直接就是保存在Excel中,而且编程语言就是VBScript。不过LoadRunner就没有那么幸运,用的是更加通用的C语言。接下来很多朋友就给出了自己的看法。

    后来作者自己给出了一个利用VBScript读取文件并写入文本文件的宏,如下:

    Sub QuoteCommaExport()

    Dim DestFile As String
    Dim FileNum As Integer
    Dim ColumnCount As Integer
    Dim RowCount As Integer
    ‘ 提示用户指定目标文件名。
    DestFile = InputBox(”Enter the destination filename” & Chr(10) & “(with complete path and extension):”, “Quote-Comma Exporter”)
    ‘ 获取下一个可用的文件句柄编号。
    FileNum = FreeFile()
    ‘ 关闭错误检查功能。
    On Error Resume Next
    ‘ 尝试打开目标文件以供输出。
    Open DestFile For Output As #FileNum
    ‘ 如果出现错误,则报告错误并结束程序。
    If Err <> 0 Then MsgBox “Cannot open filename ” & DestFileEnd
    ‘ End If
    ‘ 打开错误检查功能。
    On Error GoTo 0
    ‘ 循环选择的每一行。
    For RowCount = 1 To Selection.Rows.Count
    ‘ 循环选择的每一列。
    For ColumnCount = 1 To Selection.Columns.Count
    ‘ 将当前单元格中的文本写入到文件中,文本用引号括起来。
    Print #FileNum, “”"” & Selection.Cells(RowCount, ColumnCount).Text & “”"”;
    ‘ 检查单元格是否位于最后一列。
    If ColumnCount = Selection.Columns.Count Then
    ‘ 如果是,则写入一个空行。
    Print #FileNum,
    Else
    ‘ 否则,则写入一个逗号。
    Print #FileNum, “,”;
    End If
    ‘ 开始 ColumnCount 循环的下一个迭代。
    Next ColumnCount
    ‘ 开始 RowCount 循环的下一个迭代。
    Next RowCount
    ‘ 关闭目标文件。
    Close #FileNum

    End Sub

    但是这个并不能解决问题。
    后来,这位仁兄又不辞劳苦,找来一篇利用dll访问的例子,下面就是详细内容。

    如果使用DLL不知道可否实现,将查到的一篇比较好的介绍加载DLL的帖子转载过来,供大家研究
    “LoadRunner下DLL的调用”
    原帖地址http://www.softqa.net/bbs/index.php?showtopic=100
    具体内容如下:
    LoadRunner下DLL的调用
    场景介绍
    最近在做类似于QQ的通信工具的性能测试时发现了一些问题,现总结出来与大家分享一下。希望大家在使用LoadRunner时不仅仅停在只是录制/播放角本,而全面提升角本的编程技术,解决复杂场景。
    本次测试中碰到的问题是这样的,在消息的传送过程中遇到了DEC加密的过程,LoadRunner录制到的全是加密的消息,比如我录制了某一个用户的登陆,发送消息,退出,但由于是加密的,只能单个用户使用,但如果我想并发多少个用户就存在很多问题,最直接的一个问题就是用户名是加密的,密码是加密的,当然你可以说让程序那里注掉加密的代码进行明码的测试,当然也是一种办法。但程序组提出了要使用更真实的方法来模拟,这时就必需使用下面介绍的方法。
    一开始是直接把API移植到LoadRunner中来,不过由于加密算法异常复杂,有几层循环,而角本是解释执行的,进行一次加密运算可能需要好几分钟,当然在角本里可以把角本本身运行的时间去掉,但这样做显然没有直接调用DLL来的效率高。由于程序组比较忙,所以无法提供DLL给测试,所以测试完成了DLL的编写,并在LoadRunner中调用成功,高效的完成了用户信息加密,参数关联,成功的完成了测试。
    动态链接库的编写
      在Visual C++6.0开发环境下,打开FileNewProject选项,可以选择Win32 Dynamic-Link Library建立一个空的DLL工程。
      1. Win32 Dynamic-Link Library方式创建Non-MFC DLL动态链接库

      每一个DLL必须有一个入口点,这就象我们用C编写的应用程序一样,必须有一个WINMAIN函数一样。在Non-MFC DLL中DllMain是一个缺省的入口函数,你不需要编写自己的DLL入口函数,用这个缺省的入口函数就能使动态链接库被调用时得到正确的初始化。如果应用程序的DLL需要分配额外的内存或资源时,或者说需要对每个进程或线程初始化和清除操作时,需要在相应的DLL工程的.CPP文件中对DllMain()函数按照下面的格式书写。
     
    BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
    {
    switch( ul_reason_for_call )
    {
    case DLL_PROCESS_ATTACH:
    break;
    case DLL_THREAD_ATTACH:
    break;
    case DLL_THREAD_DETACH:
    break;
    case DLL_PROCESS_DETACH:
    break;
    default:
    break;
    }
    return TRUE;
    }
      
    参数中,hMoudle是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP段的一个选择符);ul_reason_for_call是一个说明动态库被调原因的标志,当进程或线程装入或卸载动态链接库的时候,操作系统调用入口函数,并说明动态链接库被调用的原因,它所有的可能值为:DLL_PROCESS_ATTACH: 进程被调用、DLL_THREAD_ATTACH: 线程被调用、DLL_PROCESS_DETACH: 进程被停止、DLL_THREAD_DETACH: 线程被停止;lpReserved为保留参数。到此为止,DLL的入口函数已经写了,剩下部分的实现也不难,你可以在DLL工程中加入你所想要输出的函数或变量了。

      我们已经知道DLL是包含若干个函数的库文件,应用程序使用DLL中的函数之前,应该先导出这些函数,以便供给应用程序使用。要导出这些函数有两种方法,一是在定义函数时使用导出关键字_declspec(dllexport),另外一种方法是在创建DLL文件时使用模块定义文件.Def。需要读者注意的是在使用第一种方法的时候,不能使用DEF文件。下面通过两个例子来说明如何使用这两种方法创建DLL文件。

      1)使用导出函数关键字_declspec(dllexport)创建MyDll.dll,该动态链接库中有两个函数,分别用来实现得到两个数的最大和最小数。在MyDll.h和MyDLL.cpp文件中分别输入如下原代码:
     
    //MyDLL.h
    extern “C” _declspec(dllexport) int desinit(int mode); 更新为 extern “C” _declspec(dllexport) int desinit(int ,int);
    extern “C” _declspec(dllexport) void desdone(void); 更新为 extern “C” _declspec(dllexport) void desdone(int ,int);
    extern “C” _declspec(dllexport) void des_setkey(char *subkey, char *key);
    extern “C” _declspec(dllexport) void endes(char *block, char *subkey);
    extern “C” _declspec(dllexport) void dedes(char *block, char *subkey);
    //MyDll.cpp
    #include”MyDll.h”
    //这里我用了比较大小的函数代替了我要实现的函数
    int desinit(int a, int b)
    {
    if(a>=b)return a;
    else
    return b;
    }
    int desdone(int a, int b)
    {
    if(a>=b)return b;
    else
    return a;
    }
    该动态链接库编译成功后,打开MyDll工程中的debug目录,可以看到MyDll.dll、MyDll.lib两个文件。LIB文件中包含DLL文件名和DLL文件中的函数名等,该LIB文件只是对应该DLL文件的”映像文件”,与DLL文件中,LIB文件的长度要小的多,在进行隐式链接DLL时要用到它。读者可能已经注意到在MyDll.h中有关键字”extern C”,它可以使其他编程语言访问你编写的DLL中的函数。
    LoadRunner调用动态链接库
    上面完成动态链接库开发后,下面就介绍动态链接库如何被LoadRunner进行调用,其实也是很简单的。在LoadRunner中的DLL调用有局部调用与全局调用,下面介绍局部调用。
    首先把你编译的DLL放在角本路径下面,这里是MyDll.dll,MyDll.lib.然后在Action中使用
    lr_load_dll(”MYDll.dll”),此函数可以把DLL加载进来,让你调用DLL里面的函数,而DLL中的运算是编译级的,所以效率极高,代码样例如下:
    #include “lrs.h”
    Action()
    {
    //
    int nRet = 6;
    char srckey[129];
    memset(srckey, ‘a’, 128);
    lr_message(lr_eval_string(srckey));
    lr_load_dll(”MyDLL.dll”);
    nRet = desinit(5,8);
    lr_message(”比较的结果为%d”,nRet);
    return 0;
    }
    运行结果
    比较的结果为8

    全局的动态链接库的调用则需要修改mdrv.dat,路径在LoadRunner的安装目录下面(LoadRunner/dat directory);在里面修改如例:
    [WinSock]
    ExtPriorityType=protocol
    WINNT_EXT_LIBS=wsrun32.dll
    WIN95_EXT_LIBS=wsrun32.dll
    LINUX_EXT_LIBS=liblrs.so
    SOLARIS_EXT_LIBS=liblrs.so
    HPUX_EXT_LIBS=liblrs.sl
    AIX_EXT_LIBS=liblrs.so
    LibCfgFunc=winsock_exten_conf
    UtilityExt=lrun_api
    ExtMessageQueue=0
    ExtCmdLineOverwrite=-WinInet No
    ExtCmdLineConc=-UsingWinInet No
    WINNT_DLLS=user_dll1.dll, user_dll2.dll, …
    //最后一行是加载你需要的DLL
    这样你就可以在LR中随意的调用程序员写的API函数,进行一些复杂的数据加密,准备的一些操作,进行复杂的测试。同时如果你觉的有大量高复杂的运算也可以放在DLL中进行封装,以提高效率。
  • LoadRunner案例分析之四(转)

    2009-12-22 19:34:53

    最近在论坛上看到几次这样的问题,今天突然想起来,觉得比较典型,有必要分析一下。

    这个问题的具体描述大概是这样的:在web应用下,模拟十个用户并发进行数据的添加,结果每次执行全部成功,但是数据却不是十条,每次数据不一样,但是都比十小。

    乍一看,可能是数据参数化的问题,其实仔细想想,道理其实很简单。是数据库的问题。
    大多数的数据库都有记录锁的问题,第一次的数据操作没有commit之前,第二次对同样表进行的操作可能就没有办法成功。所以每次数据的条数都达不到十条。但是为什么每次都不一样呢?这个问题也容易解释,因为每次的操作服务器的响应时间是不同的,所以不同虚拟用户的提交时间也不是不同的,这样一来,就导致每次提交成功的数据量不一致。导致每次结果的条数可能是不同的。

    其实这个问题,跟LoadRunner的使用并没多大关系,而主要是对数据库的了解和应用执行机制的了解。如何解决这个问题,我现在还没有好的思路,是否对应用程序写数据库的过程作一些改进?大家可以一起探讨。

  • LoadRunner案例分析之三(转)

    2009-12-22 19:33:52

    以前一直没有解决的问题,利用LoadRunner测试一个应用的时候,需要验证域用户,所以即使录制成功,每次回放的时候都提示错误,用户名和密码不对,对此耿耿于怀了很久。今天居然解决了。解决方法就是一个简单的函数调用: web_set_user,此函数的解释和用法如下:

    The web_set_user function is a Service function that specifies a login string and password for a Web server or proxy server. It can be called more than once if several proxy servers require authentication. web_set_user overrides the run-time proxy authentication settings for user name and password.

    When you log onto a server that requires user and password validation, VuGen records a web_set_user statement containing the login details. However, there are some more stringent, authentication methods for which VuGen is unable to insert web_set_user statements. See User Authentication for more detail. In such cases, you can add web_set_user into your script. manually.

    When you run the script, LoadRunner automatically submits the user authorization along with every subsequent request to that server. At the end of the script, LoadRunner resets the authorization.

    This function is supported for all Web Vusers, and for WAP Vusers running in HTTP mode only. It is not supported for WAP Vusers running in Wireless Session Protocol (WSP) replay mode.

    Example 3
    The following example was inserted manually by the user into the script. as the Web server “mansfield” uses NTLM authentication. VuGen cannot record NTLM or Digest authentication. Note that for NTLM authentication the domain name “mansfield” followed by a double backslash must be prepended to the user name:

    web_set_user(”mansfield\\freddy”, “XYZ”, “mansfield:80″);

    原来一直没有想到域的设置,结果一直不行,现在可以了。
    另外一个问题跟之前这个有关系,那就是验证码的问题,之前曾经看过段念(关河大侠)的关于验证码的是三个解决方案,这里是第四种解决方案。对于一些比较简单有规律的验证码可以搞定。对于复杂的比如有干扰的,或者没有规律的则参考关大侠的其他解决方案。

    这个应用经过源代码分析,发现每次客户端请求过来的验证码都可以取到,格式如下固定,是四个数字的组合。经过多次尝试发现如下规律:
    验证码如下: 52|52|52|51|46|47|49|55|
    对应界面的验证码是: 6039
    规律是第2,5,8,9位的值减去46对应的即是验证码。
    有了这个规律,就可以通过关联提前取得服务器的验证码,然后通过简单的计算,得到结果。详细代码如下:

    #include “web_api.h”

    Action()
    {

    // char* str = “52|52|52|51|46|47|49|55|”;
    char result[64];
    int num1;
    int num2;
    int num3;
    int num4;

    int temp1;
    int temp2;
    int temp3;
    int temp4;

    web_set_user(”XXXXDomain\\szXXXX”,
    lr_decrypt(”46246a2633f042c67758b9ddc2b863038aa063c03d7e”),
    “XXXX.XXXX.com.cn:8080″);

    web_reg_save_param(”check”, “LB=Image=”, “RB=\\”, LAST);

    web_url(”Register”,
    “URL=http://XXXX.XXXX.com.cn:8080/xx/main/Register”,
    “Resource=0″,
    “RecContentType=text/html”,
    “Referer=”,
    “Snapshot=t1.inf”,
    “Mode=HTML”,
    LAST);

    lr_think_time( 6 );

    sscanf(lr_eval_string(”{check}”), “%d|%d|%d|%d|%d|%d|%d|%d”, &temp1, &num1, &temp2, &temp3, &num2, &temp4, &num3, &num4);

    num1 -= 46;
    num2 -= 46;
    num3 -= 46;
    num4 -= 46;

    sprintf(result, “%d%d%d%d”, num1, num2, num3, num4);

    lr_log_message(”getvalue : %s”, result);

    web_submit_form(”Register;jsessionid=6726009A7D21963602B166D91C883413″,
    “Snapshot=t2.inf”,
    ITEMDATA,
    “Name=Register.reason”, “Value= “, ENDITEM,
    “Name=set_attach”, “Value=result”, ENDITEM,
    LAST);

    return 0;
    }

  • LoadRunner案例分析之二(转)

    2009-12-19 16:42:24

    一个朋友问起这样一个问题:他们公司的系统上线以后,用户分布在各个不同的地区,而且接入系统的方式和带宽也不同,这种情况下进行性能测试,如何保证更加真实的模拟用户行为?用LoadRunner可以做到吗?

    回答当然是肯定的,其实这些都是简单问题的组合,这样的问题考察的也是你对工具的熟悉和掌握程度。在VUGen里面,是可以通过RTS (runTimeSetting)来模拟一个单个用户更加真实的行为,比如思考时间,网络带宽,是否清除cache等等。同样的设置也可以在场景中进行设置。而且LoadRunner提供设置不同用户组不同RunTimeSetting的功能。以达到模拟不同用户行为的更加真实组合。
    假设有三种不同带宽的用户,而且上传和下载的带宽也有所不同,那么可以录制两个脚本,分别模拟上传和下载的用户行为,再Controller里面,建立六个不同的脚本组,脚本组的用户数可以按照绝对或者百比分的方法分布。比如100,50,200用户或者20%,40%,40%等,这取决于你的业务模型。然后设置不同的带宽和分布情况。这样不同用户组的虚拟用户模拟出来的就是不同带宽的用户实际接入情况。就可以满足之前的问题的要求。参考下图:

  • LoadRunner案例分析之一(转)

    2009-12-19 16:27:38

    第一个问题:是如何利用LoadRunner判断HTTP服务器的返回状态. 两种方法,第一种方法是利用LR的内置函数web_get_int_property, 如下是一个简单的例子:

    Action.c
    {
    int HttpRetCode;
    web_url(”my_home”, “URL=http://my_home”, “TargetFrame=_TOP”, LAST);
    HttpRetCode = web_get_int_property(HTTP_INFO_RETURN_CODE);
    if (HttpRetCode == 200)
    lr_log_message(”The script. successfully accessed the My_home home page”);
    else
    lr_log_message(”The script. failed to access the My_home home page “);
    }

    另外一种就是最原始的办法,也是Zee兄这种高手才最先想到的,自己取HTTP服务器的数据,然后利用关联函数分析啊. (果然是高啊). 其实所有的东西都可以从服务器的返回取,然后自己动手解析,呵呵. 举个不太恰当的例子: 你需要一套家具,可以去家具市场挑,当然也可以自己买木材原料和工具,动手加工. 那才是最合乎自己需要的. 这样一比喻, Zee兄弟似乎成了木匠了,嘻嘻~~

    第二个问题:动态数据参数化的问题.

    其实第一次看到这个问题,我没有马上反应过来,后来仔细想想, 明白了. 就是需要参数化的数据不是静态的,是动态的. 比如从数据库中选出来的.

    针对这个问题,我跟Zee兄弟的看法一致,应该提前从数据源(比如数据库)把数据选取出来,然后在执行的时候直接进行参数化的选取. 反之,如果在程序执行期间,进行数据的选取,将可能带来数据库服务器的强大压力,因为参加并发执行的每个虚拟用户都去数据库搜刮一下,对数据库将是多么严峻的考验啊.

    朋友或者同事之间的探讨是加深对问题理解和增加知识面,扩展视野最直接的途径和方法,加强沟通,keep in touch.

  • 性能测试概念和术语解释(转)

    2009-12-19 16:13:33

    响应时间(response time)

    响应时间,是指系统对用户操作的反馈时间。我们可以举一个163邮箱登录的例子:
    我们如何来测试邮箱的登录响应时间呢?我们首先进入mail.163.com网页,输入合法的用户名和密码,点击“登录”,直到登录后的邮箱界面完全显示出来为止。那么响应时间从什么时候开始计算呢?是我们输入用户名的时候,还是点击“登录”的时候?
    显然,我们应该从按下“登录”按钮的那一瞬间开始计时,到登录后页面完全显示出来为止,这才是真正的用户登录时间,而不包括用户输入用户名和密码的时间以及思考停顿的时间(think time)

    登录响应时间其实包括3个部分:网络传输时间,服务器处理时间,浏览器显示时间
    登录响应时间=网络传输时间*2+服务器处理时间+客户端显示时间
    网络传输是双向的,所以要乘以2。网络传输时间又可以包括接入网的传输时间和互联网中的传输时间,它的大小和你所使用的上网方式有关,比如光纤一般要比adsl要快。
    服务器包括web服务器和数据库服务器,服务器处理时间是我们测试的重点,也是我们能够控制的部分,因为最终用户用什么机器上网,什么接入方式上网我们是控制不了的。我们要重点测试服务器的处理速度如何,以及能否承受较大的压力,我们可以用工具(比如LoadRunner)来模拟大量用户同时登录访问服务器,来查看服务器的承载能力。
    客户端显示时间,如何将服务器传过来的页面尽快地显示到浏览器上,是开发人员需要考虑的问题,这里面涉及到算法优化的问题,这也是开发人员容易忽略的地方。
    由此可见,响应时间是可以分解成若干个时间段的,任何一个环节出问题都会影响到最终的响应时间,这就需要我们在实际工作中结合具体情况加以分析。
    最后再说明一点,响应时间的快慢是一个相对的概念,没有绝对的标准,比如对于163邮箱登录来说,用户可以接受的时间可以在10秒以内,而对于一个实时的军工软件来说,相应时间要精确到毫米级别甚至更低。
    对于普通的web网站来说,一个普遍被接受的响应时间标准是2/5/10,即用户对2秒钟以内的的响应时间非常满意,对于5秒钟以内的响应时间基本满意,对于10秒钟以上的响应时间则无法接受.

    吞吐量(throughput)

    吞吐量,是指单位时间内流经被测系统的数据流量,一般单位为b/s,即每秒钟流经的字节数。
    吞吐量是大型门户网站以及各种电子商务网站衡量自身负载能力的一个很重要的指标,一般吞吐量越大,系统单位时间内处理的数据越多,系统的负载能力也越强。
    吞吐量和很多因素有关,比如服务器的硬件配置,网络的拓扑结构,软件的技术架构等。实际工作中,我们往往对升级客户的硬件配置无能为力,大多数情况下,我们还是在软件的技术架构上做文章:
    比如后台数据库装oracle还是装sql server,显然前者的处理能力更强;
    web服务器是用weblogic还是iis,要看服务器端的语言是jsp还是asp…
    测试的时候多跟项目经理,系统架构师以及用户沟通,来获取系统架构的第一手材料。

    并发(concurrency)

    并发,是指多个同时发生的操作。比如有10个用户同时点击“登录”按钮(注意是同时),来登录163邮箱,我们就说此次登录163邮箱的并发数为10。
    需要注意的是,并发和并行不是一个概念,并发是同时发生,并行是同步运行。10个用户并发登录163邮箱,只是在点击“登录”按钮那一瞬间是并行的,而登录后各个用户的操作则不同步。

    稳定性测试(reliability testing)

    稳定性测试,也叫可靠性测试(reliability testing),是指连续运行被测系统,检查系统运行时的稳定程度

    我们通常用mtbf(mean time between failure,即错误发生的平均时间间隔)来衡量系统的稳定性,mtbf越大,系统的稳定性越强

    稳定性测试的方法也很简单,即采用24*7(24小时*7天)的方式让系统不间断运行,至于具体运行多少天,是一周还是一个月,视项目的实际情况而定。

    负载测试(load testing)

    负载测试,是性能测试的一种,通常是指让被测系统在其能忍受的压力的极限范围之内连续运行,来测试系统的稳定性。
    可以看出负载测试和稳定性测试比较相似,都是让被测系统连续运行,区别就在于负载测试需要给被测系统施加其刚好能承受的压力,比如我们还是测试163邮箱系统的登录模块,我们先用1个用户登录,再用两个用户并发登录,再用5个,10个…在这个过程中,我们每次都需要观察并记录服务器的资源消耗情况(可以通过任务管理器中的性能监视器或者控制面板中的性能监视器),当发现服务器的资源消耗快要达到临界值时(比如cpu的利用率90%以上,内存的占有率达到80%以上),停止增加用户,假如现在的并发用户数为20,我们就用这20个用户同时多次重复登录,直到系统出现故障为止。
    负载测试为我们测试系统在临界状态下运行是否稳定提供了一种办法。

    压力测试(stress testing)

    压力测试,是性能测试的一种,通常是指持续不断的给被测系统增加压力,直到将被测系统压垮为止,用来测试系统所能承受的最大压力。
    比如我们不断增加并发的登录用户数,20,30,50…比如,当增加到70个用户并发登录时,系统崩溃了,我们就可以知道163邮箱所能承载的最大登录并发数为70个左右。

    我们把上面的思路整理一下,编写一下163邮箱登录模块性能测试用例,供大家参考(假设163邮箱要求登录的时间最多不超过10秒,测试环境略)

    关于性能测试的分类,可以举一个比较通俗的例子方便大家理解:
    假设一个人很轻松就能背1袋米,背2袋米很吃力,最多就能背3袋米
    稳定性测试–我让他背1袋米,但是让他去操场上跑圈,看多久累倒。
    负载测试–我让他背2袋米去操场上跑圈,看多久累倒。
    压力测试–我让他背2袋米,3袋米,4袋米…发现他最多就能背3袋

  • 初探jconsole+weblogic9.2(转)

    2009-12-17 15:19:27

    web 项目使用weblogic9.2做为服务器, 出现了out of memory 问题, 这时就引发了需要监控JVM内存使用情况. 本来一开始使用jprofiler ,但是只能免费10天... 10天能干什么,难道我们程序员就不过周末了??万恶的jprofiler公司. 还好JDK1.5有jconsole.

    步骤:

    1. weblogic服务是"startWebLogic.cmd" 程序来启动的 , 要想连接到jconsole必须设置com.sun.management.jmxremote 参数.

    运行->startWebLogic.cmd -Dcom.sun.management.jmxremote

    或者在快捷方式加上也可以:


    2.运行->jconsole

    3.选择监控服务

    4.OK,连接成功,如下图

    记录一点Out Of Memory 原因:

    堆是应用程序使用的主要部分,一旦堆满,应用程序就会抛出Out Of Memory错误。具体关于堆的构成以及垃圾回收算法,可以参考文档:

    http://aleung.blogbus.com/logs/4712392.html

    这个环节的优化:

    1) 增加JVM内存,使得可使用的堆内存尽可能多,延长垃圾回收的时间。需要注意的是,一般来说,回收1G内存所需要的时间是7秒左右,如果这个时间访问量比高,极容易导致应用停止响应,所以并非是越大内存越好。通过增加XX:+PrintGCDetails参数可以观察到垃圾回收的频率和时间

    2) 调整垃圾回收策略,加快JVM的回收,因为Web应用响应高,很多都是无用内存,加快回收可以保证有效堆会更多,这种方式会消耗更多的CPU。

  • Python字符串的encode与decode (转)

    2009-12-01 20:52:18

    首先要搞清楚,字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。

    decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode('gb2312'),表示将gb2312编码的字符串转换成unicode编码。

    encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode('gb2312'),表示将unicode编码的字符串转换成gb2312编码。

    在某些IDE中,字符串的输出总是出现乱码,甚至错误,其实是由于IDE的结果输出控制台自身不能显示字符串的编码,而不是程序本身的问题。

    如在UliPad中运行如下代码:

    s=u"中文"
    print s

    会提示:UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)。这是因为UliPad在英文WindowsXP上的控制台信息输出窗口是按照ascii编码输出的(英文系统的默认编码是ascii),而上面代码中的字符串是Unicode编码的,所以输出时产生了错误。

    将最后一句改为:print s.encode('gb2312')

    则能正确输出“中文”两个字。

    若最后一句改为:print s.encode('utf8')

    则输出:\xe4\xb8\xad\xe6\x96\x87,这是控制台信息输出窗口按照ascii编码输出utf8编码的字符串的结果。

     

    Updated at: 2008.11.05

    另外,代码中字符串的默认编码与代码文件本身的编码一致,如:

    s='中文'

    如果是在utf8的文件中,该字符串就是utf8编码,如果是在gb2312的文件中,则其编码为gb2312。 这种情况下,要进行编码转换,都需要先用decode方法将其转换成unicode编码,再使用encode方法将其转换成其他编码。通常,在没有指定特定的编码方式时,都是使用的系统默认编码创建的代码文件,在这篇文章中可以看到如何获得系统的默认编码。

    如果字符串是这样定义:

    s=u'中文'

    则该字符串的编码就被指定为unicode了,即python的内部编码,而与代码文件本身的编码无关。因此,对于这种情况做编码转换,只需要直接使用encode方法将其转换成指定编码即可。

    如果一个字符串已经是unicode了,再进行解码则将出错,因此通常要对其编码方式是否为unicode进行判断:

    isinstance(s, unicode)  #用来判断是否为unicode

  • QTP DotNetFactory使用解析

    2009-12-01 14:57:41

    QuickTest Professional 9.x 增加了一项新功能DotNetFactory,它能让你创建.NET对象实例,它封装了CreateInstance方法。如果你想使用一个.NET对象作为QuickTest中一个方法的一个参数,你必须使用CreateInstance方法首先为该.NET对象创建一个COM接口:

    Set var_CreateInstance = DotNetFactory.CreateInstance (TypeName [,Assembly] [,args])

    Argument

    Type

    Description

    TypeName
    String
    The full name of the object type, for example, System.Windows.Forms.Form.
    Assembly
    Any
    Optional. If the assembly is preloaded in the registry, you do not need to enter it. Otherwise, you should enter the full path name, for example, System.Windows.Forms. If you want to create an instance of a type in the GAC (Global Assembly Cache), you can enter the short name, for example, Forms.
    Note: If you do not pass this argument, QuickTest assumes that the assembly is resident in memory. If QuickTest does not find the assembly, an error message is displayed during the run session.
    args
    Any
    Optional. The required arguments, if any, for the specified TypeName and/or Assembly.
    支持DotNetFactory这项功能的DLL位于: %programfiles%\HP\QuickTest Professional\bin\DotNetFactory.dll
     
     
    例子:
    1. Set objBtn1 = DotNetFactory.CreateInstance(”System.Windows.Forms.Button”, “System.Windows.Forms”)
    2. Set myList = DotnetFactory.CreateInstance("System.Collections.ArrayList")
    3. Set File = DotNetFactory.CreateInstance("System.IO.File")
    4. Set p1 = DotNetFactory.CreateInstance(”System.Drawing.Point”,”System.Drawing”,x,y)
    5. Set objReader1 = DotNetFactory.CreateInstance(”System.Xml.XmlTextReader”, “System.Xml”,”C:\Documents and Settings\kmohankumar\Desktop\11.xml”)
     
    附录:
    [Description("Enables you to create an instance of a .NET object, and access its methods and properties."), Guid("15494157-E302-4a17-95C7-24C545CA8F53"), ClassInterface(ClassInterfaceType.None), ProgId("Mercury.DotNetFactory.1"), ComVisible(true)]
    public class DotNetFactory : IObjFactory, IReflect, IObjFactoryServices
    {
     // Fields
     private ArrayList _ArgList;
    
     // Methods
     static DotNetFactory()
        {
         Trace.WriteLine("ObjectFactory");
         RegistryKey currentUser = Registry.CurrentUser;
         RegistryKey key2 = currentUser.OpenSubKey(@"Software\Mercury Interactive\QuickTest Professional\MicTest\ReservedObjects\DotNetFactory");//见下图
    string str = (string) key2.GetValue("PreloadAssemblies", null);
         if (str != null)
         {
             string[] strArray = str.Split(new char[] { ';' });
             DotNetFactory factory = new DotNetFactory();
             currentUser.Close();
             key2.Close();
             foreach (string str2 in strArray)
             {
                 try
                 {
                     Trace.WriteLine(str2);
                     factory.LoadAssembly(str2);
                     Trace.WriteLine("Loaded");
                 }
                 catch
                 {
                     Trace.WriteLine("Failed");
                 }
             }
         }
        }
    
     public DotNetFactory();
        {
            this._ArgList = new ArrayList();
        }
    
     private void AddArg(object arg)
        {
             if (arg is DispWrapper)
             {
                 arg = ((DispWrapper) arg)._object;
             }
             this._ArgList.Add(arg);
        }
    
     private void ClearArgs();
     
     public object CreateInstance(string TypeName, object assembly, params object[] CtorArgs)
        {
             object obj3;
             ConstructorInfo[] constructors;
             this._ArgList.Clear();
             if (CtorArgs != null)
             {
                 foreach (object obj2 in CtorArgs)
                 {
                     this.AddArg(obj2);
                 }
             }
             if ((assembly is string) && (((string) assembly).Length > 0))
             {
                 this.LoadAssembly(assembly as string);
             }
             Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();//获取当前应用程序域加载的所有程序集
             Type conversionType = null;
             foreach (Assembly assembly2 in assemblies)
             {
                 conversionType = assembly2.GetType(TypeName);//如果CreateInstance仅有一个参数无须带任何可选参数,帮助里说程序集已在内存中,如例2和例3             
                 if (conversionType != null)
                 {
                     break;
                 }
             }
             if (conversionType == null)
             {
                 throw new Exception("Type '" + TypeName + "' not found in any loaded assembly");
             }
             if (this._ArgList.Count == 0)
             {
                 constructors = conversionType.GetConstructors();//值来自于如果CreateInstance仅有一个参数
                 if ((constructors == null) || (constructors.Length == 0))
                 {
                     if (conversionType.IsValueType)
                     {
                         string str = "0";
                         try
                         {
                             obj3 = Convert.ChangeType(str, conversionType);
                         }
                         catch (InvalidCastException)
                         {
                             obj3 = new DispWrapper(conversionType);
                         }
                     }
                     else
                     {
                         obj3 = new DispWrapper(conversionType);
                     }
                 }
                 else
                 {
                     obj3 = conversionType.Assembly.CreateInstance(TypeName);
                 }
             }
             else
             {
                 object[] args = new object[this._ArgList.Count];
                 for (int i = 0; i < this._ArgList.Count; i++)
                 {
                     args[i] = this._ArgList[i];
                 }
                 this.ClearArgs();
                 constructors = conversionType.GetConstructors();//值来自于如果CreateInstance仅有一个参数
                 if ((constructors == null) || (constructors.Length == 0))
                 {
                     obj3 = new DispWrapper(conversionType);
                 }
                 else
                 {
                     obj3 = conversionType.Assembly.CreateInstance(TypeName, false, BindingFlags.CreateInstance, null, args, null, null);//此步能接受例4和例5的输入
                 }
                 if (obj3 == null)
                 {
                     throw new Exception("Cannot create instance of " + TypeName);
                 }
             }
             if (!(obj3 is string) && !(obj3 is DispWrapper))
             {
                 obj3 = new DispWrapper(obj3);
             }
             return obj3;
        }
     
     public void LoadAssembly(string partialName)
        {
         string str = partialName.ToLower();
         if (str.IndexOf(".dll") > 0)
         {
             this.LoadAssemblyByPath(partialName);
         }
         else if (str.IndexOf(".exe") > 0)
         {
             this.LoadAssemblyByPath(partialName);
         }
         else if (Assembly.LoadWithPartialName(partialName) == null)
         {
             throw new FileNotFoundException("Cannot load Assembly " + partialName);
         }
        }
    
     private void LoadAssemblyByPath(string path)
        {
         Assembly.LoadFrom(path);
        }
    
        FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr);
        FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr);
        MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr);
        MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr);
        MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr);
        MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers);
        MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr);
        PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr);
        PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr);
        PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers);
        object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters); public object Unwrap(object wrapper);
    // Properties
     protected virtual Type MyType { get; }
     Type IReflect.UnderlyingSystemType { get; }
    }
      
     
    [ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch)]
    internal class DispWrapper : IReflect
    {
     // Fields
     internal Exception _exception;
     internal object _object;
     private Type _ObjectType;
    
     // Methods
     internal DispWrapper(object obj)
     {
         this._object = obj;
         this._ObjectType = obj.GetType();
     }
    
     internal DispWrapper(Type t)
     {
         this._object = null;
         this._ObjectType = t;
     }
     public FieldInfo GetField(string name, BindingFlags bindingAttr);
     public FieldInfo[] GetFields(BindingFlags bindingAttr);
     public MemberInfo[] GetMember(string name, BindingFlags bindingAttr);
     public MemberInfo[] GetMembers(BindingFlags bindingAttr);
     public MethodInfo GetMethod(string name, BindingFlags bindingAttr);
     public MethodInfo[] GetMethods(BindingFlags bindingAttr);
     public PropertyInfo[] GetProperties(BindingFlags bindingAttr);  public PropertyInfo GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers);
     public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters); MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers); PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr);
     
     // Properties
     public Type UnderlyingSystemType { get; }
    }
    
  • LoadRunner出现error问题及解决方法总结(转)

    2009-11-27 14:57:58

     一、Step download timeout (120 seconds)

      这是一个经常会遇到的问题,解决得办法走以下步骤:

      1、 修改run time setting中的请求超时时间,增加到600s,其中有三项的参数可以一次都修改了,HTTP-request connect timeout,HTTP-request receieve timeout,Step download timeout,分别建议修改为600、600、5000;run time setting设置完了后记住还需要在control组件的option的run time setting中设置相应的参数;

      2、 办法一不能解决的情况下,解决办法如下:

      设置runt time setting中的internet protocol-preferences中的advaced区域有一个winlnet replay instead of sockets选项,选项后再回放就成功了。切记此法只对windows系统起作用,此法来自zee的资料。

      二、问题描述Connection reset by peer

      这个问题不多遇见,一般是由于下载的速度慢,导致超时,所以,需要调整一下超时时间。

      解决办法:Run-time setting窗口中的‘Internet Protocol’-‘Preferences’设置set advanced options(设置高级选项),重新设置一下“HTTP-request connect timeout(sec),可以稍微设大一些”;

      三、问题描述connection refused

      这个的错误的原因比较复杂,也可能很简单也可能需要查看好几个地方,解决起来不同的操作系统方式也不同;

      1、 首先检查是不是连接weblogic服务过大部分被拒绝,需要监控weblogic的连接等待情况,此时需要增加acceptBacklog,每次增加 25%来提高看是否解决,同时还需要增加连接池和调整执行线程数,(连接池数*Statement Cache Size)的值应该小于等于oracle数据库连接数最大值;

      2、 如果方法一操作后没有变化,此时需要去查看服务器操作系统中是否对连接数做了限制,AIX下可以直接vi文件limits修改其中的连接限制数,还有 tcp连接等待时间间隔大小,wiodows类似,只不过wendows修改注册表,具体修改方法查手册,注册表中有TcpDelayTime项;

      四、问题描述open many files

      问题一般都在压力较大的时候出现,由于服务器或者应用中间件本身对于打开的文件数有最大值限制造成,解决办法:

      1、 修改操作系统的文件数限制,aix下面修改limits下的nofiles限制条件,增大或者设置为没有限制,尽量对涉及到的服务器都作修改;

      2、 方法一解决不了情况下再去查看应用服务器weblogic的commonEnv.sh文件,修改其中的nofiles文件max-nofiles数增大,应该就可以通过了,具体就是查找到nofiles方法,修改其中else条件的执行体,把文件打开数调大;修改前记住备份此文件,防止修改出错;

      五、问题描述has shut down the connection prematurely

      一般是在访问应用服务器时出现,大用户量和小用户量均会出现;

      来自网上的解释:

      1> 应用访问死掉

      小用户时:程序上的问题。程序上存在数据库的问题

      2> 应用服务没有死

      应用服务参数设置问题

      例如:

      在许多客户端连接Weblogic应用服务器被拒绝,而在服务器端没有错误显示,则有可能是Weblogic中的server元素的AcceptBacklog属性值设得过低。如果连接时收到connection refused消息,说明应提高该值,每次增加25%

      Java连接池的大小设置,或JVM的设置等

      3> 数据库的连接

      在应用服务的性能参数可能太小了

      数据库启动的最大连接数(跟硬件的内存有关)

      以上信息有一定的参考价值,实际情况可以参考此类调试。

      如果是以上所说的小用户时:程序上的问题。程序上存在数据库的问题,那就必须采用更加专业的工具来抓取出现问题的程序,主要是程序中执行效率很低的sql语句,weblogic可以采用introscope定位,期间可以注意观察一下jvm的垃圾回收情况看是否正常,我在实践中并发500用户和600用户时曾出现过jvm锯齿型的变化,上升下降都很快,这应该是不太正常的;

      六、问题描述Failed to connect to server

      这个问题一般是客户端链接到服务失败,原因有两个客户端连接限制(也就是压力负载机器),一个网络延迟严重,解决办法:

      1、 修改负载机器的tcpdelaytime注册表键值,改小;

      2、 检查网络延迟情况,看问题出在什么环节;

      建议为了减少这种情况,办法一最好测试前就完成了,保证干净的网络环境,每个负载机器的压力测试用户数不易过大,尽量平均每台负载器的用户数,这样以上问题出现的概率就很小了。

  • ORACLE 最大连接数的问题

    2009-11-27 14:14:27

    客户端连接数据库报如下错误:

    show parameter processes;
    然后
    更改系统连接数
    alter system set processes=1000 scope=spfile;
    下面是具体的操作步骤与说明


    问题描述:客户端连接数据库报错
    ORA-12516: TNS: 监听程序无法找到匹配协议栈的可用句柄


    解决过程:
    1。查看当前会话数、processes和sessions值,发现session数和2个参数的值已经非常逼近
    SQL*Plus: Release 10.2.0.1.0 - Production on 星期一 10月 9 15:50:21 2006
    Copyright (c) 1982, 2005, Oracle. All rights reserved.
    SQL> conn / as sysdba
    已连接。
    SQL> select count(*) from v$session;
    COUNT(*)
    ----------
    45
    SQL> show parameter processes
    NAME TYPE VALUE
    ------------------------------------ ----------- ----------------------
    aq_tm_processes integer 0
    db_writer_processes integer 1
    gcs_server_processes integer 0
    job_queue_processes integer 10
    log_archive_max_processes integer 2
    processes integer 50
    SQL> show parameter sessions
    NAME TYPE VALUE
    ------------------------------------ ----------- ----------------------
    java_max_sessionspace_size integer 0
    java_soft_sessionspace_limit integer 0
    license_max_sessions integer 0
    license_sessions_warning integer 0
    logmnr_max_persistent_sessions integer 1
    sessions integer 60
    shared_server_sessions integer
    2。修改processes和sessions值
    SQL> alter system set processes=300 scope=spfile;
    系统已更改。
    SQL> alter system set sessions=300 scope=spfile;
    系统已更改。
    3。查看processes和sessions参数,但更改并未生效
    SQL> show parameter processes
    NAME TYPE VALUE
    ------------------------------------ ----------- ----------------------
    aq_tm_processes integer 0
    db_writer_processes integer 1
    gcs_server_processes integer 0
    job_queue_processes integer 10
    log_archive_max_processes integer 2
    processes integer 50
    SQL> show parameter sessions
    NAME TYPE VALUE
    ------------------------------------ ----------- ----------------------
    java_max_sessionspace_size integer 0
    java_soft_sessionspace_limit integer 0
    license_max_sessions integer 0
    license_sessions_warning integer 0
    logmnr_max_persistent_sessions integer 1
    sessions integer 60
    shared_server_sessions integer
    4。重启数据库,使更改生效
    SQL> shutdown immediate
    SQL> startup
    SQL> show parameter processes
    NAME TYPE VALUE
    ------------------------------------ ----------- ----------------------
    aq_tm_processes integer 0
    db_writer_processes integer 1
    gcs_server_processes integer 0
    job_queue_processes integer 10
    log_archive_max_processes integer 2
    processes integer 300
    SQL> show parameter sessions
    NAME TYPE VALUE
    ------------------------------------ ----------- ----------------------
    java_max_sessionspace_size integer 0
    java_soft_sessionspace_limit integer 0
    license_max_sessions integer 0
    license_sessions_warning integer 0
    logmnr_max_persistent_sessions integer 1
    sessions integer 335
    shared_server_sessions integer
    最后测试加大连接数到50,100都没报ORA-12516错误。
    有的时候我们需要调整oracle数据库的最大链接数,而这个链接数的调整是在oacle下的dbs目
    录下init.ora文件中调整的。
    ORACLE的连接数(sessions)与其参数文件中的进程数(process)有关,它们的关系如下:
    sessions=(1.1*process+5)
    但是我们增加process数时,往往数据库不能启动了。这因为我们还漏调了一个unix系统参数:
    它是核心参数中的semmns,这是unix系统的信号量参数。每个process会占用一个信号量。semmns
    调整后,需要重新启动unix操作系统,参数才能生效。不过它的大小会受制于硬件的内存或ORACLE
    SGA。范围可从200——2000不等。
    但是,Processes的修改不仅应该调整init.ora文件中的参数,而且应该调整OS的内核
    参数,象AIX,HPUX,Solaris,SCO,UNIXWare都是这样,OS的调整是需要重新启动的,而且这个参数
    的设置不能简单按照多少个终端要连到这个服务器上而定,
    最关键是考虑会有多少同时连上的session(在使用一些共享连接的中间件时,一般就不需要太大),
    当然还要考虑一些Oracle的后台进程,还有一些系统维护工作需要多一些连接等。
    我的atmp大前置机器上对oracle调整的时候,其使用的是unixware操作系统,在做链接数调整
    的时候,要先对核心参数进行调整。
    核心主要相关的参数的调整如下:
    SHMMAX 1000000000
    SHMMIN 1
    SHMMNI 200
    SHMSEG 15
    SEMMNI 1000
    SEMMSL 300
    SEMMNS 230
    SEMOPM 20
    其中semmni,semmns,semmsl要加大,至少要比processes大18 ;
    SEMMNI(10,10000;150):指定在核心中信号识别的数量。这是可以在任意给定时间被激活的唯
    一信号设置数量。缺省值是150。最大值由系统自动调整产生。
    SEMMSL(25,300;150):指定每个信号识别中信号量的最大值。缺省值是25。
    SEMMNS 除最大db外的所有db 的PROCESSES之和+2*最大db的PROCESSES+10*实例数。如3个实例进
    程数分别为100、100、200,则=(100+100)+2*200+10*3=630
    SEMOPM(10,20;10):指定在每个系统调用semop中能够被执行的信号操作量的最大值。
    缺省值是10。
    SHMMAX(131072,1073741824;524288):指定了共享内存部分大小的最大值。
    等于0.5×物理内存字节数
    SHMMNI(10,1000;100):指定了系统范围内共享内存标识的最大值。
    SHMSEG(6,15;6):指定了与每个进程相关连的共享内存块(或标识)的数量。缺省值是6。与每
    个进程相关连的共享内存块的最大值与进程拥有的未使用空间有关。因此,尽管一个进程拥有少于
    SHMSEG数值的共享内存块,它也有可能因为其有限的空间而不能与其它进程相联系。
    init.ora中调整为:
    processes = 50 # SMALL
    #processes = 100 # MEDIUM
    # processes = 200 # LARGE
    其中的processes就是要调整的最大连接数的数目,我们只要调整这个参数就可以了,其它的参数可
    以保持默认值。

     

    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/rongdajian/archive/2009/10/22/4711748.aspx

  • 查看oracle当前连接数(转)

    2009-11-27 14:11:13

    怎样查看oracle当前的连接数呢?只需要用下面的SQL语句查询一下就可以了。


    select * from v$session where username is not null

    select username,count(username) from v$session where username is not null group by username #查看不同用户的连接数

    select count(*) from v$session   #连接数

    Select count(*) from v$session where status='ACTIVE' #并发连接数

    show parameter processes   #最大连接

    alter system set processes = value scope = spfile;重启数据库   #修改连接

    1。查看当前会话数、processes和sessions值,发现session数和2个参数的值已经非常逼近

    SQL> conn / as sysdba已连接。

    SQL> select count(*) from v$session;

    SQL> show parameter processes;

    SQL> show parameter sessions;

    2。修改processes和sessions值

    SQL> alter system set processes=300 scope=spfile;

    系统已更改。

    SQL> alter system set sessions=300 scope=spfile;

    系统已更改。

     

        3。查看processes和sessions参数,但更改并未生效

     

    4。重启数据库,使更改生效

    SQL> shutdown immediate

    SQL> startup

    SQL> show parameter processes

         SQL> show parameter sessions
  • 数据库连接池

    2009-11-27 14:01:56

    数据库连接池概述:  s-}q # j  
    数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。
      q!.l%@y K  
    数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而再不是重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
     d+MD2?`Q   
    数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。数据库连接池的最小连接数和最大连接数的设置要考虑到下列几个因素:
      ./ ,bSh  
    1) 最小连接数是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费;
     %< xf j xr  
    2) 最大连接数是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求将被加入到等待队列中,这会影响之后的数据库操作。
     [ Ylf  }/W  
    3) 如果最小连接数与最大连接数相差太大,那么最先的连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接。不过,这些大于最小连接数的数据库连接在使用完不会马上被释放,它将被放到连接池中等待重复使用或是空闲超时后被释放。
  • VBScript中的正则表达式语法详解(转)

    2009-11-26 21:25:41

    RegExp属性
    Global
    IgnoreCase
    Pattern

    RegExp方法
    Execute
    Replace
    Test

    RegExp对象
    Match
    Match属性
        FirstIndex
        Length
        Value

    RegExp集合
    Matches
    SubMatches

      我在学习正则表达式的时候根本不知何谓正则表达式、对他的理解也非常模糊,以至于接触了很长时间才懂得,虽然vbs手册中有很详细地解释。

      正则表达式我个人将其理解为用来搜索文本然后然后对搜索结果作处理的一些列动作。

      先来看一段大家所熟知的ubb代码


    function ubb(str)
    Dim rex,match,matches   ' 建立变量。
    Set rex= New RegExp   ' 建立规范表达式。
    rex.IgnoreCase = True   ' 设置是否区分字母的大小写。
    rex.Global = True   ' 设置全程性质。
    rex.Pattern = [url=(.)](.)[url]   ' 设置模式。官方是这样解释的,我认为我们应该换一种叫法:搜索方法,这样我们才便于理解。
    ubb = rex.replace(str,a href="http://www.blog.com.cn/$1"$2a) '将我们搜索到的内容替换
    '我们在设定搜索的时候用到了两个括号,也就是说我们将只需要用到这两个括号中的内容,这两个括号中的内容在替换的时候将会用$1(第一个括号中的内容)和$2(第二个括号中的内容)来代替。
    end function
    '用法
    dim text
    text=[url=httpwww.aaa.com]link[url]
    document.write ubb(text) '输出文本并调用正则表达式
    '如果在asp中使用请将document替换为response

     

      上面是一个简单的正则演示,在这个演示中我们只用了一行内容,用方法replace在替换文字的时候只处理一行中的第一个ubb代码头和最后的一个ubb代码的尾,如下:
    [url=httpwww.aaa.com]link[url] [url=httpwww.aaa.com]link[url]
    将会被替换为a href=httpwww.aaa.com]link[url] [url=httpwww.aaa.coma,这个结果可不是我们要的,
    也就是说我们必须在大量替换搜索内容前将要搜索的全部的文本或者字符串作处理。处理的结果就是要保证每一行只能存在一个相应的代码。这点非常重要,在我学习的时候一直搞不明白为什么?后来才知道是这个原因。

      在上面的一个示例中我们用到了正则表达使得所有属性以及replace的方法,下来我们来看一下有关于方法Execute,对象Match及所有属性,集合Matches 的一个官方的示例

    Function RegExpTest(patrn, strng)
    Dim regEx, Match, Matches   ' 建立变量。
    Set regEx = New RegExp   ' 建立正则表达式。
    regEx.Pattern = patrn   ' 设置模式。即:搜索方法
    regEx.IgnoreCase = True   ' 设置是否区分大小写。
    regEx.Global = True   ' 设置全程可用性。
    Set Matches = regEx.Execute(strng)   ' 执行搜索。我们可以理解为被搜索的字符串
    For Each Match in Matches   ' 遍历 Matches 集合。
      RetStr = RetStr & 匹配 & Match' 注意,在官方提供的示例中这里是错误的,
    这里是被匹配的名称
      RetStr = RetStr & 位于 & Match.FirstIndex & 。'这里是匹配内容的第一个字符,该数字从0开始
      RetStr = RetStr & 匹配的长度为& Match.Length & 个字符。 这里不用解释了吧?
      RetStr = RetStr & vbCRLF '这里是换行
    Next
    RegExpTest = RetStr
    End Function
    document.write(RegExpTest(is., IS1 is2 IS3 is4))
    '如果在asp中使用请将document替换为response


      在这个示例中我们可以看到方法Execute和对象Match是使用在集合Matches中的,Match和Matches是作为变量来使用的,为了我们很容易得看懂它,我们没有必要将他们换名字。关于对象Match的属性,我在上面的示例中都做了注释了。

      最后我们来看集合SubMatches,代码如下:(由于官方的这段代码很含糊,所以我修改了一下)

    Function SubMatchTest(inpStr)
    Dim Re, Match, Matches
    Set Re = New RegExp
    Re.Pattern = (w+)@(w+).(w+)
    Set Matches = Re.Execute(inpStr)
    Set Match = Matches(0) '由于这里没有使用循环,所以只能搜索一次。只匹配搜索到的第一个内容
    retStr = 电子邮件地址是:  & Match & vbNewline ' 这里是匹配的内容
    retStr = retStr & 电子邮件别名是:  & Match.SubMatches(0) '第一个括号中的内容
    retStr = retStr & vbNewline
    retStr = retStr & 组织是:  & Match. SubMatches(1)'第二个括号中的内容
    SubMatchTest = retStr
    End Function
    document.write(SubMatchTest(请写信到 dragon@xyzzy.com 。谢谢!))
    '如果在asp中使用请将document替换为response


      在上面的这段代码中我们看到了对象Match和集合Matches的另外一种用法,由此可见所有的集合均可以用这种方法,就像实用数组一样。看完上面的代码有些朋友可能想到既然在属性Pattern中已经提供了$1$2.....$n这种方法,为什么还要存在集合SubMatches呢?实际上在我们使用证则表达式的时候可能搜索要匹配的内容或字符串很长,然而我们还要对搜索到匹配的字符串进行进一步的处理,而$又不能实现这个,于是便有了集合SubMatches。

      到这里有关于VBScript的正则表达式的内容就全部说完了,上面的3个代码均可以放在<SCRIPT. Language=VBScript><SCRIPT>标签中使用也可以放在ASP中执行。

Open Toolbar