希望能找到能与我共同进步的知心朋友!

发布新日志

  • 表空间的ONLINE和OFFLINE状态

    2018-05-14 15:45:41

     
    1. 只要数据库处于OPEN状态,除了SYSTEM表空间外的其他表空间,都可以将其置为online或offline状态。SYSTEM表空间之所以不能置为offline,是因为其中保存的数据字典需要一直使用。将表空间置为offline,可能的原因包括维护、备份以及恢复等目的。
     
    3. 如果表空间处于offline状态,那么Oracle不会允许任何对该表空间中对象的SQL执行。表空间置为offline时仍处于活动状态的语句在交易级别并不会受影响。Oracle会保存这些尚未完成语句相关的回滚数据到SYSTEM表空间。当表空间置为online时,如果有必要,那么Oracle会应用这些回滚数据。
     
    3. 除了Oracle外,没有任何应用能够读取或编辑offline的表空间。因此,offline的表空间更不能导到其他数据库。
     
    4. Oracle在一些场景下会自动切换表空间状态从online到offline。例如,当数据库写进程DBWn,尝试几次仍不能写入表空间的数据文件中。用户访问offline表空间时会收到一个报错。如果造成这种磁盘IO失败的问题是介质错误,解决这问题之后需要恢复表空间。
     
    5. 将表空间置为offline可能包含如下原因:
     
    (1) 需要禁止访问一部分数据库的场景。
     
    (2) 执行一次offline表空间备份(尽管表空间可以在online和使用情况下备份)。
     
    (3) 当更新或维护应用时,需要让应用和对应的表临时不能访问。
     
    (4) 重命名或重分配表空间中的数据文件。
     
    当表空间置为offline,数据库会将关联的所有数据文件都置为offline状态。但是如下表空间不能置为offline:
     
    > SYSTEM
     
    > UNDO表空间
     
    > 临时表空间
     
    6. 将表空间置为offline之前,若有用户设置该表空间为其默认表空间,需要考虑是否需要改变其默认表空间。之所以这样做,是因为这些用户将不能访问offline表空间中的对象。
     
    7. 使用ALTER TABLESPACE ... OFFLINE语句可以添加如下参数:
     
    NORMAL:如果表空间的任何数据文件没有出现错误,表空间能够正常地置为offline。如果出现写错误,那么表空间中的数据文件不会被置为offline。当明确使用OFFLINE NORMAL,数据库会对所有数据文件进行一次checkpoint检查点事件,NORMAL是默认设置。
     
    TEMPORARY:表空间能够临时置为offline状态,即使一个或多个文件出现错误。当使用OFFLINE TEMPORARY,数据库会将还没有置为offline的数据文件进行置位操作,并执行检查点事件。
     
    如果没有文件是offline,但使用了temporary语句,那么当将表空间置为online时不需要介质恢复。然而,如果表空间的一个或多个文件由于写入错误因此导致offline状态,能够临时将表空间置为offline状态,恢复online之前需要对表空间进行恢复操作。
     
    IMMEDIATE:表空间能够立即设置为offline状态,数据库不会进行任何数据文件的检查点事件。当使用OFFLINE IMMEDIATE,那表空间置为online之前需要对表空间进行介质恢复操作。但是如果数据库处于NOARCHIVELOG模式,表空间就不能立即置为offline状态。
     
    8. 如果必须设置表空间为offline状态,建议首先使用默认的NORMAL语句。他会确保当表空间置为online前不需要执行恢复操作,尽管在不完全恢复之后,使用LATER DATABASE OPEN RESTLOGS语句重置了redo日志sequence。
     
    仅仅当不能使用NORMAL方式将表空间置为offline时,可以使用TEMPORARY。使用TEMPORARY后,在表空间置为online前,仅需要恢复那些出错的offline文件。
     
    如果NORMAL和TEMPORARY都失败时,才可以选择使用IMMEDIATE选项。
     
    9. 如果表空间没有“干净地”置为offline(也就是没有使用NORMAL语句执行的offline操作),那么置为online前需要首先对该表空间执行介质恢复操作。否则数据库会报错,表空间仍处于offline状态。
     

    实验:
     
    1. 设置表空间DCSOPEN_TBS为offline:
     SQL> alter tablespace dcsopen_tbs offline;
     
    Tablespace altered.
     

     

    2. 查询数据文件状态:
     
    select file#, name, status from v$datafile;
     file  #name 
     status
     ---  ------------------------------------------------------ ----------
     
    11  /oracle/oradata_petest/petest/dcsopen_tbs02.dbf OFFLINE
     
    DCSOPEN_TBS使用的数据文件状态已经置为OFFLINE。
     

     

    3. 尝试查询已OFFLINE表空间:
     SQL> select * from test;
     select * from test
                  *
     ERROR at line 1:
     ORA-00376: file 7 cannot be read at this time
     ORA-01110: data file 7: '/oracle/oradata_petest/petest/dcsopen_tbs01.dbf'
     
    报错,提示此时数据文件不能读。
     

     

    4. 将表空间置为online:
     SQL> alter tablespace dcsopen_tbs online;
     
    Tablespace altered.
     


    file  #name 
     status
     ---  ------------------------------------------------------ ----------
     
    11  /oracle/oradata_petest/petest/dcsopen_tbs02.dbf ONLINE

  • Eclipse连接MySQL数据库

    2015-11-20 10:11:13

    1、下面来创建一个数据: 

    mysql>CREATE   DATABASE test;   //创建一个数据库

    mysql
    >use test; //指定test为当前要操作的数据库

    mysql
    >CREATE TABLE user (name VARCHAR(20),password VARCHAR(20)); //创建一个表user,设置两个字段。

    mysql
    >INSERT INTO user VALUES('huzhiheng','123456'); //插入一条数据到表中

      

    2。打开Eclipse,创建一个项目(my),

    操作:右键点击my--->build Path--->add external Archiver...选择jdbc驱动,点击确定。

    我的项目列表:

    3。驱动已经导入,下面我们来写一个程序验证一下

    复制代码
    import java.sql.*;
    publicclass MysqlJdbc {
    publicstaticvoid main(String args[]) {
    try {
    Class.forName(
    "com.mysql.jdbc.Driver"); //加载MYSQL JDBC驱动程序
    //Class.forName("org.gjt.mm.mysql.Driver");
    System.out.println("Success loading Mysql Driver!");
    }
    catch (Exception e) {
    System.out.print(
    "Error loading Mysql Driver!");
    e.printStackTrace();
    }
    try {
    Connection connect
    = DriverManager.getConnection(
    "jdbc:mysql://localhost:3306/test","root","198876");
    //连接URL为 jdbc:mysql//服务器地址/数据库名 ,后面的2个参数分别是登陆用户名和密码

    System.out.println(
    "Success connect Mysql server!");
    Statement stmt
    = connect.createStatement();
    ResultSet rs
    = stmt.executeQuery("select * from user");
    //user 为你表的名称
    while (rs.next()) {
    System.out.println(rs.getString(
    "name"));
    }
    }
    catch (Exception e) {
    System.out.print(
    "get data error!");
    e.printStackTrace();
    }
    }
    }
    复制代码

    点击运行程序:  

    Success loading Mysql Driver!

    Success connect Mysql server!

    huzhiheng  

    出现上面结果,说明你连接数据库成功。

    4。可以查看到MySQL里面的内容,那我们是不是想往MySQL中插入数据呢。
    下面的例子,往MySQL的user表中插入100条数据
    复制代码
    import java.sql.*;

    publicclass Myjproject {
    publicstaticvoid main(String args[])
    {
    try {
    Class.forName(
    "com.mysql.jdbc.Driver"); //加载MYSQL JDBC驱动程序
    //Class.forName("org.gjt.mm.mysql.Driver");
    System.out.println("Success loading Mysql Driver!");
    }
    catch (Exception e) {
    System.out.print(
    "Error loading Mysql Driver!");
    e.printStackTrace();
    }
    try {
    Connection connect
    = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test","root","198876");

    int num=100;
    PreparedStatement Statement
    =connect.prepareStatement("INSERT INTO user VALUES(?,?)");
    for(int i=0;i<num;i++) //定义个100次的循环,往表里插入一百条信息。
    {
    Statement.setString(
    1,"chongshi"+i);
    Statement.setString(
    2,"bo"+i);
    Statement.executeUpdate();
    }

    // } catch (ClassNotFoundException e) {
    // TODO Auto-generated catch block
    // System.out.println("An error has occurred:"+e.toString());
    // e.printStackTrace();
    }catch(SQLException e)
    {
    }
    }
    }
    复制代码

     

    5.下面我们打开MySQL数据库进行查看 

    mysql> show databases; //查看所数据库
    mysql> use test; //使test为当前要操作的数据库
    mysql> show tables; //查看当前数据库的所有表
    mysql> select *from user; //查看当前表(user)的所有信息

    注意:如果不能正常连接你的数据库,请检查你代码中,驱动、用户名、密码、表等信息是否对应无误,不要把别人的代码直接复制过来,看也不看就用。

  • Wireshark基本介绍和学习TCP三次握手

    2015-08-19 11:13:49

     

    本文转载自【小坦克】,原文链接 http://www.cnblogs.com/tankxiao阅读目录

    1. wireshark介绍
    2. wireshark不能做的
    3. wireshark VS Fiddler
    4. 同类的其他工具
    5. 什么人会用到wireshark
    6. wireshark 开始抓包
    7. wireshark 窗口介绍
    8. wireshark 显示过滤
    9. 保存过滤
    10. 过滤表达式
    11. 封包列表(Packet List Pane)
    12. 封包详细信息 (Packet Details Pane)
    13. wireshark与对应的OSI七层模型
    14. TCP包的具体内容
    15. 实例分析TCP三次握手过程

    wireshark介绍

    wireshark的官方下载网站: http://www.wireshark.org/

    wireshark是非常流行的网络封包分析软件,功能十分强大。可以截取各种网络封包,显示网络封包的详细信息。

    wireshark是开源软件,可以放心使用。 可以运行在Windows和Mac OS上。

    使用wireshark的人必须了解网络协议,否则就看不懂wireshark了。

    Wireshark不能做的

    为了安全考虑,wireshark只能查看封包,而不能修改封包的内容,或者发送封包。

    Wireshark VS Fiddler

    Fiddler是在windows上运行的程序,专门用来捕获HTTP,HTTPS的。

    wireshark能获取HTTP,也能获取HTTPS,但是不能解密HTTPS,所以wireshark看不懂HTTPS中的内容

    总结,如果是处理HTTP,HTTPS 还是用Fiddler, 其他协议比如TCP,UDP 就用wireshark

    同类的其他工具

    微软的network monitor

    sniffer

    什么人会用到wireshark

    1. 网络管理员会使用wireshark来检查网络问题

    2. 软件测试工程师使用wireshark抓包,来分析自己测试的软件

    3. 从事socket编程的工程师会用wireshark来调试

    4. 听说,华为,中兴的大部分工程师都会用到wireshark。

    总之跟网络相关的东西,都可能会用到wireshark.

    wireshark 开始抓包

    开始界面

    wireshark是捕获机器上的某一块网卡的网络包,当你的机器上有多块网卡的时候,你需要选择一个网卡。

    点击Caputre->Interfaces.. 出现下面对话框,选择正确的网卡。然后点击"Start"按钮, 开始抓包

    Wireshark 窗口介绍

    WireShark 主要分为这几个界面

    1. Display Filter(显示过滤器), 用于过滤

    2. Packet List Pane(封包列表), 显示捕获到的封包, 有源地址和目标地址,端口号。 颜色不同,代表

    3. Packet Details Pane(封包详细信息), 显示封包中的字段

    4. Dissector Pane(16进制数据)

    5. Miscellanous(地址栏,杂项)

    Wireshark 显示过滤

    使用过滤是非常重要的, 初学者使用wireshark时,将会得到大量的冗余信息,在几千甚至几万条记录中,以至于很难找到自己需要的部分。搞得晕头转向。

    过滤器会帮助我们在大量的数据中迅速找到我们需要的信息。

    过滤器有两种,

    一种是显示过滤器,就是主界面上那个,用来在捕获的记录中找到所需要的记录

    一种是捕获过滤器,用来过滤捕获的封包,以免捕获太多的记录。 在Capture -> Capture Filters 中设置

    保存过滤

    在Filter栏上,填好Filter的表达式后,点击Save按钮, 取个名字。比如"Filter 102",

    Filter栏上就多了个"Filter 102" 的按钮。

    过滤表达式的规则

    表达式规则

    1. 协议过滤

    比如TCP,只显示TCP协议。

    2. IP 过滤

    比如 ip.src ==192.168.1.102 显示源地址为192.168.1.102,

    ip.dst==192.168.1.102, 目标地址为192.168.1.102

    3. 端口过滤

    tcp.port ==80, 端口为80的

    tcp.srcport == 80, 只显示TCP协议的愿端口为80的。

    4. Http模式过滤

    http.request.method=="GET", 只显示HTTP GET方法的。

    5. 逻辑运算符为 AND/ OR

    常用的过滤表达式

    过滤表达式 用途
    http 只查看HTTP协议的记录
    ip.src ==192.168.1.102 or ip.dst==192.168.1.102 源地址或者目标地址是192.168.1.102

    封包列表(Packet List Pane)

    封包列表的面板中显示,编号,时间戳,源地址,目标地址,协议,长度,以及封包信息。 你可以看到不同的协议用了不同的颜色显示。

    你也可以修改这些显示颜色的规则, View ->Coloring Rules.

    封包详细信息 (Packet Details Pane)

    这个面板是我们最重要的,用来查看协议中的每一个字段。

    各行信息分别为

    Frame. 物理层的数据帧概况

    Ethernet II: 数据链路层以太网帧头部信息

    Internet Protocol Version 4: 互联网层IP包头部信息

    Transmission Control Protocol: 传输层T的数据段头部信息,此处是TCP

    Hypertext Transfer Protocol: 应用层的信息,此处是HTTP协议

    wireshark与对应的OSI七层模型

    TCP包的具体内容

    从下图可以看到wireshark捕获到的TCP包中的每个字段。

    实例分析TCP三次握手过程

    看到这, 基本上对wireshak有了初步了解, 现在我们看一个TCP三次握手的实例

    三次握手过程为

    这图我都看过很多遍了, 这次我们用wireshark实际分析下三次握手的过程。

    打开wireshark, 打开浏览器输入 http://www.cnblogs.com/tankxiao

    在wireshark中输入http过滤, 然后选中GET /tankxiao HTTP/1.1的那条记录,右键然后点击"Follow TCP Stream",

    这样做的目的是为了得到与浏览器打开网站相关的数据包,将得到如下图

    图中可以看到wireshark截获到了三次握手的三个数据包。第四个包才是HTTP的, 这说明HTTP的确是使用TCP建立连接的。

    第一次握手数据包

    客户端发送一个TCP,标志位为SYN,序列号为0, 代表客户端请求建立连接。 如下图

    第二次握手的数据包

    服务器发回确认包, 标志位为 SYN,ACK. 将确认序号(Acknowledgement Number)设置为客户的I S N加1以.即0+1=1, 如下图

    第三次握手的数据包

    客户端再次发送确认包(ACK) SYN标志位为0,ACK标志位为1.并且把服务器发来ACK的序号字段+1,放在确定字段中发送给对方.并且在数据段放写ISN的+1, 如下图:

    就这样通过了TCP三次握手,建立了连接.

  • ORACLE会话数、连接数配置

    2014-12-03 18:45:42

     
    ORACLE的会话数和连接数参数配置  
    以sysdba身份登录 
    sqlplus sys/xxxx as sysdba; 
     
    查看最大连接数: 
    show parameter processes; 
    show parameter sessions; 
     
    查看当前最大连接数: 
    select count(*) from v$process; 
    select count(*) from v$session; 
     
    修改最大连接数: 
    alter system set processes=1500 scope=spfile; 
    alter system set sessions=2000 scope=spfile; 
     
    创建pfile 
    create pfile from spfile; 
     
    重启数据库: 
    shutdown immediate; 
    startup; 
  • linux系统硬件配置查看方法

    2014-12-03 18:44:30


    一:查看cpu

    more /proc/cpuinfo | grep "model name"

    grep "model name" /proc/cpuinfo

    如果觉得需要看的更加舒服

    grep "model name" /proc/cpuinfo | cut -f2 -d:

     

    二:查看内存

    grep MemTotal /proc/meminfo

    grep MemTotal /proc/meminfo | cut -f2 -d:

    free -m |grep "Mem" | awk '{print $2}'

    三:查看cpu是32位还是64位

    查看CPU位数(32 or 64)

    getconf LONG_BIT

    四:查看当前linux的版本

    more /etc/redhat-release

    cat /etc/redhat-release

    五:查看内核版本

    uname -r

    uname -a

     

     

    六:查看当前时间

    date

    上面已经介绍如何同步时间了,

    七:查看硬盘和分区

    df -h

    fdisk -l

    也可以查看分区

    du -sh

    可以看到全部占用的空间

    du /etc -sh

    可以看到这个目录的大小

    八:查看安装的软件包

    查看系统安装的时候装的软件包

    cat -n /root/install.log

    more /root/install.log | wc -l

    查看现在已经安装了那些软件包

    rpm -qa

    rpm -qa | wc -l

    yum list installed | wc -l

    不过很奇怪,我通过rpm,和yum这两种方式查询的安装软件包,数量并不一样。没有找到原因。

     

    九:查看键盘布局

    cat /etc/sysconfig/keyboard

    cat /etc/sysconfig/keyboard | grep KEYTABLE | cut -f2 -d=

    十:查看selinux情况

    sestatus

    sestatus | cut -f2 -d:

    cat /etc/sysconfig/selinux

    十一:查看ip,mac地址

    在ifcfg-eth0 文件里你可以看到mac,网关等信息。

    ifconfig

    cat /etc/sysconfig/network-scripts/ifcfg-eth0 | grep IPADDR

    cat /etc/sysconfig/network-scripts/ifcfg-eth0 | grep IPADDR | cut -f2 -d=

    ifconfig eth0 |grep "inet addr:" |awk '{print $2}'|cut -c 6-

    ifconfig   | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print $1}'

    查看网关

    cat /etc/sysconfig/network

    查看dns

    cat /etc/resolv.conf

    十二:查看默认语言

    echo $LANG $LANGUAGE

    cat /etc/sysconfig/i18n

    十三:查看所属时区和是否使用UTC时间

    cat /etc/sysconfig/clock

    十四:查看主机名

    hostname

    cat /etc/sysconfig/network

    修改主机名就是修改这个文件,同时最好也把host文件也修改。

    查看pci信息    lspci

    查看硬盘信息  df -lh

    curl --head www.163.com               查看163.com的服务器环境

    uptime              查看开机时间多长

    ifconfig eth0 up    启用网卡eth0

    /etc/initd/network restart 重启网络服务
  • pl/sql 小结

    2012-10-30 14:23:53

    结一下单行多列,单例多行和多行多列的写法:

    1.单行多列:

    1. declare  
    2.        type xxx_type is record(  
    3.             my_sal emp.sal%type,--锚定数据类型   
    4.             my_num emp.empno%type  
    5.        );  
    6.        --声明一个记录的数据类型(记录类型是单行多列)   
    7.        xxx xxx_type;  
    8. begin  
    9.        select sal,empno into xxx from emp where emp.empno = 7369;--执行sql语句是赋值用into   
    10.        dbms_output.put_line(xxx.my_sal);--输出一行(需要先在sql下 set serveroutput on;)   
    11.        dbms_output.put_line(xxx.my_num);  
    12.        --这种方式大多用于自定义   
    13. end;  
    14. /  

    还有一种是用 表名+%rowtype来实现:

    1. declare  
    2.       xxx emp<SPAN style="COLOR: #ff0000">%rowtype</SPAN>;  
    3. begin  
    4.        select * into xxx from emp where emp.empno = 7369;  
    5.        dbms_output.put_line(xxx.sal);  
    6.        dbms_output.put_line(xxx.empno);  
    7.        dbms_output.put_line(xxx.ENAME);  
    8.        dbms_output.put_line(xxx.job);  
    9. end;--使用的时候<SPAN style="COLOR: #ff0000">成员个数,名称,类型必须和表货视图的列的个数,名称,类型完全相同</SPAN>   
    10. /  
    2:单列多行

    1. declare  
    2.       type xxx_type is table of emp.sal%type  
    3.       index by binary_integer;--声明一个单列多行的结构   
    4.       xxx xxx_type;  
    5.       i number;  
    6. begin  
    7.        select sal <SPAN style="COLOR: #ff0000">bulk collect</SPAN> into xxx from emp where emp.deptno = 10;--给xxx批量赋值   
    8.        select count(sal) into i from emp where emp.deptno = 10;  
    9.        for j in 1..i loop  
    10.               dbms_output.put_line(xxx(j));  
    11.        end loop;  
    12. end;  
    13. /  

    3:表结构(多行多列):

    1. declare  
    2.       type xxx_type is table of emp%rowtype  
    3.       index by binary_integer;--声明一个多列多行的结构  
    4.       xxx xxx_type;  
    5.       i number;  
    6. begin  
    7.        select * bulk collect into xxx from emp;--给xxx批量赋值  
    8.        select count(*) into i from emp ;  
    9.        for j in 1..i loop  
    10.               dbms_output.put_line(xxx(j).sal);  
    11.                dbms_output.put_line(xxx(j).ename);  
    12.                 dbms_output.put_line(xxx(j).job);  
    13.                  dbms_output.put_line(xxx(j).mgr);  
    14.        end loop;  
    15. end;  
    16. /  

    异常的学习:

    题目如下 :请删除dept表中的deptno为10的这项并且emp表中的其他数据部受影响

    1. declare  
    2.   e exception;  
    3.   pragma exception_init(e,-02292);  
    4.   --自己定义非预处理异常并绑定异常  
    5. begin  
    6.     delete dept where deptno = 10;  
    7.     --出现异常  
    8. exception   
    9.     when e then   
    10.     --接收到异常  
    11.            --dbms_output.put_line('不能删除');  
    12.            update emp set deptno = null where deptno = 10;  
    13.            --将emp中的外键置为空  
    14.            delete dept where deptno = 10;  
    15.            --删除dept中的编号  
    16. end;  
    17. /  
  • 从表里取数据显示出来

    2012-10-30 14:02:46

    PL/SQL 11g R2 —— PL/SQL程序 !

    分类: PL/SQL 38人阅读 评论(0) 收藏 举报

    例子1:返回一行、多列记录。

    1. SQL> set serveroutput on  
    2. SQL> declare  
    3.   2    v_emp_hiredate employees.hire_date%type;  
    4.   3    v_emp_salary employees.salary%type;  
    5.   4  begin  
    6.   5    select hire_date,salary into v_emp_hiredate,v_emp_salary  
    7.   6    from employees where employee_id = 100;  
    8.   7    dbms_output.put_line('Hire date is :' || v_emp_hiredate);  
    9.   8    dbms_output.put_line('Salary is :' || v_emp_salary);  
    10.   9  end;  
    11.  10  /  
    12. Hire date is :17-6月 -03  
    13. Salary is :24000  
    14.   
    15. PL/SQL 过程已成功完成。  


    例子2:返回一行、多列记录。

    1. SQL> set serveroutput on  
    2. SQL> declare  
    3.   2    type employees_record_type is record(v_first_name employees.first_name%type,v_salary employees.salary%type);  
    4.   3    employees_record employees_record_type;  
    5.   4  begin  
    6.   5    select first_name,salary into employees_record from employees where employee_id = 100;  
    7.   6    dbms_output.put_line(employees_record.v_first_name || employees_record.v_salary);  
    8.   7  end;  
    9.   8  /  
    10. Steven24000  
    11.   
    12. PL/SQL 过程已成功完成。  


    游标的四个属性:
    游标名%isopen   --如果当前游标打开则返回true,否则返回false.
    游标名%found    --如果当前游标读取到数据则返回true,否则返回false.
    游标名%notfound --如果当前游标未读取到数据则返回true,否则返回false.
    游标名%rowcount --返回截止到目前为止当前游标读取到的数据的行数.

    例子3:返回多行、多列记录。

    1. SQL> set serveroutput on  
    2. SQL> declare  
    3.   2    cursor v_cursor is select first_name,salary from employees;  
    4.   3    v_first_name employees.first_name%type;  
    5.   4    v_salary employees.salary%type;  
    6.   5  begin  
    7.   6    open v_cursor;  
    8.   7      loop fetch v_cursor into v_first_name,v_salary;  
    9.   8        exit when v_cursor%notfound;  
    10.   9        dbms_output.put_line(v_first_name || v_salary);  
    11.  10      end loop;  
    12.  11    close v_cursor;  
    13.  12  end;  
    14.  13  /  
    15. Donald2600  
    16. Douglas2600  
    17. Jennifer4400  
    18. ... ...  
    19.   
    20. PL/SQL 过程已成功完成。  
  • 【转贴】oracle参数open_cursors和session_cached_cursor详解!

    2012-10-11 15:27:12

    复制代码
    SQL> show parameter open_cursors           --每个session(会话)最多能同时打开多少个cursor(游标)  
      
    NAME                                 TYPE        VALUE  
    ------------------------------------ ----------- ------------------------------  
    open_cursors                         integer     300  
    SQL> show parameter session_cached_cursor  --每个session(会话)最多可以缓存多少个关闭掉的cursor  
      
    NAME                                 TYPE        VALUE  
    ------------------------------------ ----------- ------------------------------  
    session_cached_cursors               integer     20  
    
    SQL> select count(*) from v$open_cursor;  --是指当前实例的某个时刻的打开的cursor数目
    
      COUNT(*)  
    ----------  
           108
    复制代码

    1、open_cursors与session_cached_cursor的作用?

    open_cursors设定每个session(会话)最多能同时打开多少个cursor(游标)。session_cached_cursor 设定每个session(会话)最多可以缓存多少个关闭掉的cursor。想要弄清楚他们的作用,我们得先弄清楚oracle如何执行每个sql语句。

    看完上图后我们明白了两件事:

    a、两个参数之间没有任何关系,相互也不会有任何影响。b、两个参数有着相同的作用:让后续相同的sql语句不在打开游标,从而避免软解析过程来提供应用程序的效率。

     

    2、如何正确合理设置参数的大小?
    a、如果Open_cursors设置太小,对系统性能不会有明显改善,还可能触发ORA-O1000:m~imum open CUrsOrs exceeded.的错误。如果设置太大,则无端消耗系统内存。我们可以通过如下的sql语句查看你的设置是否合理:

    复制代码
        SQL> SELECT MAX(A.VALUE) AS HIGHEST_OPEN_CUR, P.VALUE AS MAX_OPEN_CUR  
          2    FROM V$SESSTAT A, V$STATNAME B, V$PARAMETER P  
          3   WHERE A.STATISTIC# = B.STATISTIC#  
          4     AND B.NAME = 'opened cursors current'  
          5     AND P.NAME = 'open_cursors'  
          6   GROUP BY P.VALUE;  
          
        HIGHEST_OPEN_CUR MAX_OPEN_CUR  
        ---------------- --------------------  
                      28 300  
    复制代码

    HIGHEST_ OPEN CUR是实际打开的cursors 的最大值,MAX_OPEN_ CUR是参数Open_cursors的设定值,如果二者太接近,甚至触发eRA一01000错误,那么你就应该调大参数Open_cursors的设定 值。如果问题依旧没有解决,盲目增大Open_cursors也是不对的,这个时候你得检查应用程序的代码是否合理,比如说应用程序是否打开了游标,却没 有在它完成工作后没有及时关闭。以下语句可以帮助你确定导致游标漏出的会话:

        SELECT A.VALUE, S.USERNAME, S.SID, S.SERIAL#  
          FROM V$SESSTAT A, V$STATNAME B, V$SESSION S  
         WHERE A.STATISTIC# = B.STATISTIC#  
           AND S.SID = A.SID  
           AND B.NAME = 'opened cursors curent';  

    同样,session_cached_cursors的值也不是越大越好,我们可以通过下面两条语句得出合理的设置。

    复制代码
        SQL> SELECT NAME, VALUE FROM V$SYSSTAT WHERE NAME LIKE '%cursor%';  
          
        NAME                                                                  VALUE  
        ---------------------------------------------------------------- ----------  
        opened cursors cumulative                                             15095  
        opened cursors current                                                   34  
        session cursor cache hits                                             12308  
        session cursor cache count                                              775  
        cursor authentications                                                  324  
          
        SQL> SELECT NAME, VALUE FROM V$SYSSTAT WHERE NAME LIKE '%parse%';  
          
        NAME                                                                  VALUE  
        ---------------------------------------------------------------- ----------  
        parse time cpu                                                          332  
        parse time elapsed                                                     1190  
        parse count (total)                                                    9184  
        parse count (hard)                                                     1031  
        parse count (failures)                                                    3  
    复制代码

    session cursor cache hits就是系统在高速缓存区中找到相应cursors的次数,parse count(total)就是总的解析次数,二者比值越高,性能越好。如果比例比较低,并且有较多剩余内存的话,可以考虑加大该参数。

     

    c、使用下面的sql判断'session_cached_cursors' 的使用情况。如果使用率为100%则增大这个参数值。

    复制代码
        SQL> SELECT 'session_cached_cursors' PARAMETER,  
          2         LPAD(VALUE, 5) VALUE,  
          3         DECODE(VALUE, 0, ' n/a', TO_CHAR(100 * USED / VALUE, '990') || '%') USAGE  
          4    FROM (SELECT MAX(S.VALUE) USED  
          5            FROM V$STATNAME N, V$SESSTAT S  
          6           WHERE N.NAME = 'session cursor cache count'  
          7             AND S.STATISTIC# = N.STATISTIC#),  
          8         (SELECT VALUE FROM V$PARAMETER WHERE NAME = 'session_cached_cursors')  
          9  UNION ALL  
         10  SELECT 'open_cursors',  
         11         LPAD(VALUE, 5),  
         12         TO_CHAR(100 * USED / VALUE, '990') || '%'  
         13    FROM (SELECT MAX(SUM(S.VALUE)) USED  
         14            FROM V$STATNAME N, V$SESSTAT S  
         15           WHERE N.NAME IN  
         16                 ('opened cursors current', 'session cursor cache count')  
         17             AND S.STATISTIC# = N.STATISTIC#  
         18           GROUP BY S.SID),  
         19         (SELECT VALUE FROM V$PARAMETER WHERE NAME = 'open_cursors');  
          
        PARAMETER              VALUE      USAGE  
        ---------------------- ---------- -----  
        session_cached_cursors    20       100%  
        open_cursors             300        16%  
    复制代码

    当我们执行一条sql语句的时候,我们将会在shared pool产生一个library cache object,cursor就是其中针对于sql语句的一种library cache object.另外我们会在pga有一个cursor的拷贝,同时在客户端会有一个statement handle,这些都被称为cursor,在v$open_cursor里面我们可以看到当前打开的cursor和pga内cached cursor.

    session_cached_cursor
    这个参数限制了在pga内session cursor cache list的长度,session cursor cache list是一条双向的lru链表,当一个session打算关闭一个cursor时,如果这个cursor的parse count超过3次,那么这个cursor将会被加到session cursor cache list的MRU端.当一个session打算parse一个sql时,它会先去pga内搜索session cursor cache list,如果找到那么会把这个cursor脱离list,然后当关闭的时候再把这个cursor加到MRU 端.session_cached_cursor提供了快速软分析的功能,提供了比soft parse更高的性能.

     

    更新2:

     

    OPEN_CURSORS是一个十分有趣的参数,经常有DBA发现自己的系统中的OPEN CURSORS十分大。我们看一个例子:
    复制代码
    
    
    SQL>select sid,value from v$sesstat a,v$statname b where a.statistic#=b.statistic# and name='opened cursors current' order by 2;
    
           SID      VALUE
    
    ---------- ----------
    
          5430         93
    
          3527         95
    
          4055         96
    
          4090         97
    
          2012         98
    
          1819         98
    
          5349        102
    
          1684        103
    
          1741        116
    
          4308        169
    
          1970        170
    
          1369        181
    
          4208        184
    
           887        214
    
          5215        214
    
          3518        214
    
           868        214
    
          1770        215
    
          4050        215
    
          1809        231
    
          3010        235
    
           762        237
    
           731        471
    
          4013       1066
    
          2648       1152
    
          2255       1172
    
          2322       2620
    复制代码

     

     

    我们看到这个系统的OPEN_CURSORS参数设置为3000,而会话中当期打开CURSOR最大的会话居然达到了2620。在一般人的眼里,CURSOR使用后就关闭了,OPENED CURSORS的数量应该不会太多,难道应用程序出现了CURSOR泄漏,有些应用使用了CURSOR没有关闭?实际上我们对OPEN CURSOR的概念一直存在误解。认为只有正在FETCHCURSOROPEN状态的,而一旦FETCH结束,CLOSE CURSOR后,CURSOR就处于关闭状态了。因此一个会话中OPEN状态的CURSOR数量应该很少。事实上不是这样的,某些CURSOR在程序中是已经CLOSE了,但是Oracle 为了提高CURSOR的性能,会对其进行缓冲,这些缓冲的CURSOR,在程序中的关闭只是一个软关闭,事实上,在会话中并未关闭,而是放在一个CURSOR缓冲区中。

    Oracle  9.2.0.5之前,OPEN_CURSORS参数的作用是双重的,一方面是限制一个会话打开的CURSORS的总量。另外一方面,OPEN_CURSORS参数也作为PL/SQL CURSOR的缓冲。在PL/SQL中,如果某个CURSOR关闭了,这个CURSOR不会马上硬关闭,而是首先保存在CURSOR缓冲中。如果这个会话当前打开的CURSOR数量还没有达到OPEN_CURSORS参数的值,那么就可以先保持OPEN状态。如果当前打开的CURSOR数量已经达到了OPEN_CURSORS参数的限制,那么首先会关闭一个被缓冲的,实际当时并未打开的CURSOR。如果缓冲池中的所有CURSOR都是实际打开的,那么就会报ORA-1000"maximum open cursors exceeded"

    Oracle  9.2.0.5以后,OPEN_CURSORS参数不再承担PL/SQL缓冲的工作,PL/SQL中的SQL也可以使用SESSION_CACHED_CURSORS的会话缓冲了。这个参数就成为了一个纯粹的限制。

    虽然如此,OPEN_CURSORS参数仍然和CURSOR的缓冲机制密切相关,因为这个参数限制了当前某个会话打开CURSOR的最大值。设置一个较大的OPEN_CURSORS参数,可以避免出现ORA-1000,同时也可以让会话缓冲更多的CURSOR,改善SQL解析的性能。不过这个参数设置的较大会占用较大的PGA空间,消耗一定的物理内存。因此这个参数也不是设置的越大越好,一般的OLTP系统中,10003000就足够了。在共享服务器模式的系统中,这个参数的设置要略微保守一些,因为这个参数越大,占用的SGA空间也就越大。

    另外要注意的是,从Oracle  9.0开始,这个参数就已经是动态的了,可以随时动态调整。

  • 详解虚拟机中为Linux添加硬盘

    2012-09-19 15:26:43

    Linux添加硬盘是在原来安装的硬盘空间不够或者需要使用其他硬盘上的东西时候的解决办法,因为大多数初学者习惯使用虚拟机,这里以在Vmware虚拟机中实现Linux添加硬盘的具体步骤来详细介绍说这个问题。

    Vmware中为linux增加硬盘

    1. 在vmware的setting中为虚拟机增加一个硬盘。

    2. 在vmware中看见 第1个硬盘是 /dev/sda , 第2个硬盘是 /dev/sdb

    3. 创建硬盘信息
    fdisk /dev/sdb
    a. 按n添加分区,选p(主分区);
    b. 选1,也就是sdb1;
    c. 然后就是空间划分,一路回车。默认是使用整个磁盘空间。
    d. 然后按w写入分区信息

    4. 格式化硬盘
    mkfs -t ext3 /dev/sdb1

    5. 创建需要mount的目录
    mkdir -p /opt

    6. mount到指定的目录
    mount /dev/sdb1 /opt -o rw

    7. 如果需要每次启动加载,修改/etc/fstab文件
    在fstab文件里面添加一行:
    /dev/sdb1 /opt ext3 defaults 1 1

    这样我们就完成了在虚拟机上Linux添加硬盘问题的解决。

  • yum使用问题总结

    2012-08-28 17:20:13

    1,错误:This system is not registered with RHN

       

    错误原因:红帽中出现This system is not registered with RHN这个的原因是因为红帽中没有注册RHN。

    解决办法:(假定你已安装yum,且网络畅通)更改yum的源,更改为CentOS的yum,即更换/etc/yum.repos.d/rhel-debuginfo.repo 这个文件。进入

    Shell代码 复制代码 收藏代码
    1. # cd /etc/yum.repos.d/  

     目录,终端中输入

    Shell代码 复制代码 收藏代码
    1. # wget http://docs.linuxtone.org/soft/lemp/CentOS-Base.repo  

     即可在此目录下得到CentOS-Base.repo文件,这是centos的源文件,只需将其重命名为

    Shell代码 复制代码 收藏代码
    1. # mv CentOS-Base.repo rhel-debuginfo.repo  

     即可。

  • 使用LR测试Oracle数据库的方法 .

    2012-08-14 09:34:23

    使用LR测试Oracle数据库的方法

    一个简单的连接方法,欢迎大家跟贴讨论更多方法

     

    选择,建立一个Oracle(2-Tier)协议的脚本

    加入

    static LRD_INIT_INFO InitInfo = {LRD_INIT_INFO_EYECAT};

    static LRD_DEFAULT_DB_VERSION DBTypeVersion[] =

    {

            {LRD_DBTYPE_NONE, LRD_DBVERSION_NONE}

    };

    先定义初始化数据库的各种变量

    static void FAR *       OraEnv1;

    static void FAR *       OraSvc1;

    static void FAR *       OraSrv1;

    static void FAR *       OraSes1;

    static void FAR *       OraStm1;

    unsigned long           rownum;

    初始化数据库部分

    lrd_init(&InitInfo, DBTypeVersion);

    lrd_initialize_db(LRD_DBTYPE_ORACLE, 3, 0);

    lrd_env_init(LRD_DBTYPE_ORACLE, &OraEnv1, 0, 0);

    lrd_ora8_handle_alloc(OraEnv1, SVCCTX, &OraSvc1, 0);

    lrd_ora8_handle_alloc(OraEnv1, SERVER, &OraSrv1, 0);

    lrd_ora8_handle_alloc(OraEnv1, SESSION, &OraSes1, 0);

    连接数据库

    lrd_server_attach(OraSrv1, "这里填写数据库的名称", -1, 0, 0);

    lrd_ora8_attr_set_from_handle(OraSvc1, SERVER, OraSrv1, 0, 0);

    设定数据库密码

    lrd_ora8_attr_set(OraSes1, USERNAME, "system", -1, 0);

    lrd_ora8_attr_set(OraSes1, PASSWORD, "这里填写密码", -1, 0);

    初始化连接session

    lrd_ora8_attr_set_from_handle(OraSvc1, SESSION, OraSes1, 0, 0);

    开始连接数据库

    lrd_session_begin(OraSvc1, OraSes1, 1, 0, 0);

    lrd_ora8_handle_alloc(OraEnv1, STMT, &OraStm1, 0);

    设定查询语句

    lrd_ora8_stmt(OraStm1, "这里填写查询语句", 1, 0, 0);

    执行查询语句

    lrd_ora8_exec(OraSvc1, OraStm1, 0, 0,&rownum, 0, 0, 0, 0, 1);

    释放连接数据库的各种变量

    lrd_handle_free(&OraStm1, 0);

    lrd_session_end(OraSvc1, OraSes1, 0, 0);

    lrd_server_detach(OraSrv1, 0, 0);

    lrd_handle_free(&OraEnv1, 0);

  • 生成大量的测试数据的三种方法

    2012-08-13 17:45:54

    生成大量的测试数据的三种方法:

    1写sql,2工具plsql,3LoadRunner

    性能测试场景之一:
    [1]03 临时表里有20W记录,发送ESB
    说明:结算后台对完账后,在对账汇总确认菜单中点“确认”按钮,系统会将已清算的数据信息插入资金库的临时表pac_biz_account_histmp中,然后逐步esb发送给物流订单系统进行分润处理。
    一 通过工具生成20w笔记录1、  首先介绍一种很方便的方法:采用PL SQL Develop内嵌的data generator工具
    1)  打开PL SQL Develop,选择Tools/Data Generator,出现以下界面

     




    2)  Owner中选择资金库Pacioli,Table中选择临时表pac_biz_account_histmp,number of records中输入200000(这些都可以根据具体的需要进行选择的噢)
    然后下面会出现临时表中所有的字段,根据实际情况进行配置后,显示如下: 


     


    3)        当然拉,为了防止ID和现有的表重复,我们是可以使用SEQUENCES的,点击每个字段后面的…选项可以对每个字段进行设置
    4)        所有的准备好之后,我们可以先测试一下Strat a test run,测试通过后,可以选择窗口中左下角的create data in DB按钮即可生成数据到临时表中。

    2.通过自动化工具实现,下面以load runner为例
       1)  Load runner是一款负载压力测试工具,可以通过load runner的Vurtual User Generator工具实现模拟业务场景然后系统向数据库中插入记录,跟进实际业务实现使用load runner向表中插入记录,或者通过脚本来实现,现将脚本操作和运行过程分享下:
       2) 打开Mercury LoadRunner,选择applications/Vurtual User Generator,在出现的窗口中选择Oracle(2-tier)如下图:

     


    3) 点击ok后,在弹出的窗口中选择:

     



    其中Program to record 选择电脑中plsqldev.exe的安装路径,然后点击ok,在弹出的窗口中输入以下脚本:
    vuser_init()
    {
        unsigned long rownum;
    //初始化数据库部分
             lrd_init(&InitInfo, DBTypeVersion);
             lrd_initialize_db(LRD_DBTYPE_ORACLE, 3, 0);
             lrd_env_init(LRD_DBTYPE_ORACLE, &OraEnv1, 0, 0);
             lrd_ora8_handle_alloc(OraEnv1, SVCCTX, &OraSvc1, 0);//
             lrd_ora8_handle_alloc(OraEnv1, SERVER, &OraSrv1, 0);
             lrd_ora8_handle_alloc(OraEnv1, SESSION, &OraSes1, 0);

    //连接数据库
             lrd_server_attach(OraSrv1, "PAY", -1, 0, 0);//pay怎么得到的?
    //初化始句柄
        lrd_ora8_attr_set_from_handle(OraSvc1, SERVER, OraSrv1, 0, 0);
    //连接数据库
             lrd_ora8_attr_set(OraSes1, USERNAME, "adm_zhifb", -1, 0);
             lrd_ora8_attr_set(OraSes1, PASSWORD, "ali88", -1, 0);

    //初始化句柄
        lrd_ora8_attr_set_from_handle(OraSvc1, SESSION, OraSes1, 0, 0);

    //进程开始      
        lrd_session_begin(OraSvc1, OraSes1, 1, 0, 0);
             lrd_ora8_handle_alloc(OraEnv1, STMT, &OraStm1, 0);
    //设定语句
        lrd_ora8_stmt(OraStm1, "insert into zhifb.beyond_bank_pay_online(id,iw_account_no,gmt_create) values (zhifb.seq_beyond_bank_pay_online.nextval,1234,to_date('2005-4-12 13:45:34','YYYY-MM-DD fmHH24fm:MI:SS'))",1,0,0);
    //执行语句
    lrd_ora8_exec(OraSvc1, OraStm1, 0, 0,&rownum,0,0, 0, 0, 1);
             return 0;
    }
    这个脚本是师傅流川教我的,目前我也不大懂,有兴趣的同学以后可以和我一起学习这个哦,不过这个脚本在运行的时候向临时表插入有点问题,希望各位大虾指点下
    直接通过SQL语句来实现    在表浏览视图,选择表后,按住鼠标左键将表拖到query sql窗口,然后在弹出的快捷菜单中选择insert,然后在另一个表里面点select,修改where条件(这样就可以不用书写这么一大串SQL语句了,直接通过鼠标操作实现
    insert into pac_biz_account_histmp
      (id,   bank_name,   trans_code,   digest_no,   amount,   trans_log_id,   account_date,   compare_date,   clear_date,   voucher_no,   batch_no,   gmt_create,   gmt_modified,   memo,   standby_voucher_no,   operator)
      select id,  bank_name, trans_code, digest_no,amount,trans_log_id,account_date, compare_date,         clear_date,         voucher_no,         batch_no,         gmt_create,         gmt_modified,         memo,         standby_voucher_no,         operator
    from pac_biz_account_history where rownum<5001 and  bank_name = '宅急送快递' and trans_code = '400322'
    通过存储过程来实现存储过程可以理解为是内嵌在ORACLE里面的包装好的SQL语句。存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。
    在公司内部,创建存储过程是必须通过DBA的批准的。在数据库中查找存储过程很方便,在数据库浏览窗口中选择Procedures来查看,可以看一个简单的例子:
    while()
    {
             callprocedure("p_test").;
             }
    create procedure p_test(a,b,c)
    begin
             insert into t values(a,b,c);
    end;
    四 通过程序来实现   程序实现有两种方式
    一种为通过for循环,链接数据库,然后执行insert操作实现,不过这种方式会每insert一条记录然后就要链接一次数据库,而且还要网络传输数据到DB中,所以会比较慢
    另一种也是通过程序,不过可以把链接数据库的操作在for循环之前执行,然后insert多条数据的时候就只用耗费网络传输数据的时间了,这样比之前的一种操作要节约时间一些。
    附上一个简单的例子:
    java
    while()
    {
             callprocedure("p_test").;
             }
    create procedure p_test(a,b,c)
    begin
             insert into t values(a,b,c);
    end;

    • 大小: 19.5 KB
    • 大小: 28.6 KB
    • 大小: 37.1 KB
    • 大小: 19.6 KB
  • mysql注册的key

    2012-07-09 14:56:18

    在用mysql-front的时候遇到显示:程序注册时间到期 程序将被限制模式下运行
    可以在
    帮助菜单下的点登记-->把以下的key复制试试,留下以后需要。注意:是整十行一起复制。(后面几个没试过,第一个可以用的)

    gNBpPFgyOw9Rwt/ozsnjgM7tJNo2
    bhaaAThangemMkaz2tQhq3/f7dZ7
    Vj29WeGHjuupj/AhYqymjAuokhYi
    X1T/fG+q1yR22PdcEP39dxU3ovEo
    lLLzwIZlQr9oJYwUf5eG4x5e1bMP
    nfIaIl8reszQPHFNbrxBjCVrBEXL
    TyBLehxzUpVI672t3LjX8q4ytCRC
    ezcoZQfMAc0DulJzNREbwlcf0Rco
    N0zW3ojBUxGsplBBZZPrD7/bPhkM
    rjtS8Bxym+HeV1TJDTXuiL8QLg==

    ======================================

    fSbC9xxy7ga57DOrLz9mMqYSFx8S
    OIWiOBI61uJ562GINVTVNBDaGBIl
    Cuni0a1iUAF88I6zrHzH9Wzcv4h+
    h3wTGgOX8mYgN0jEEOmzI1DLx0DJ
    8t94hUJ5O0I99Ts6iqvHhw24jYfI
    h++JG/BzVLnaSDbNdqH9iYbXZ2Pc
    eFZAZe6hzPQ9DREtkEvg7rAul/Fw
    ZptCP1WFfKkfgviwY8i67NucJe2L
    UTZFKoX5MGSuP9GGJnouQg/P1SII
    3PCKXGoUv0hBoTiMLXBlJWpaNg==

    =============================================

    0W01VaFQPp/XRYgXjOFSUY7hZ5Cc
    W9f35KH4bym2jmhYygsHyNsr47Hs
    7OBjd7QH+ALAKqZdDAh/AfG3V/8Q
    his64uZEhglY8B8yu5PvN49tOO05
    XG7Qyz3skOK3An9Zoc/xSA1fLGeq
    PioqBj/khHWF1LK0lBi00LOLFXzs
    oQtoMi1Ol+Ehxz8URH3kQqN09raw
    iM7DrTxZe1oVoOjTPDerwPOLULI1
    6EnbdBu92YSk0tYQw0BmVss2G6ak
    GjaDrPWrDWP3uip0OOX4UXNggQ==

    ===============================================

    H4nLHG3xsjy5l4QMEsSpaYAyggPp
    9OdFDMG0Y1XM7VqTyg+GAAm8V/eP
    9zuAwQ5/9tA8GQeOlavXxIDkMsY7
    I4UAy4LmhUU2vLtEkgjtMhSd3nFT
    OGe2bOmGvoMCPts/1eQx5YFMet9K
    AjkZPI1BR8/fm7Mb0bQOPeJQyilC
    T1/4k4MfqnQkub06+ADZ7pg3WdkC
    jneqAVvKPaM2Kf55cGDsLmo3Xxck
    ZHpzPKJDISjEQ+qFadS8Z9Ao0HHK
    31JWyvw0Qr/9d0Ku10+W6DrhZw==

    =================================================

    DZaNXFw2rfRrF3xlukPGGiilkurQ
    r7vKuSPCUEdAoRWRJmjnADY0Ink3
    Nr9qD3CM5+v9PYJ4uf/b9jShtlYH
    KV16XPA+On7CjH8zqxywbz2ci85i
    f0va/I0DOvGhpsww1jAJCJWC4A+z
    ZjTMzA0+SEQcKyHzOUe89eA+c/Gq
    FZBmitn5u602wlMj2KtvMSN8EgSc
    wDVxI+FSi0U/b89fRaUMJRbUadm0
    uZHKMPdlaykMQPwZFN8G561OFCU/
    rbFQlatd0JFPnLKxjNsjva04LQ==

    ===============================================

    hFeWdc8oboH/QwzaaLhrH6CgRo6g
    nBXqa0bjHJdEYTIzMdqnkEBvygf+
    xJeO2zRqajhnH+S1wZWeNUwXLwZm
    KvS8LCvwCf1WBqzsRMuDOTQnac5d
    RGf80G986szBG8kzkhKjC4Bx3uLy
    NomiYSHrGBoDacd5wPCqFMoTsaMC
    CjVMabK/JyQyAeuULOf8lW0WiXTo
    TKH7k1yGW6plaQKWGIqBZuYlYk5H
    tFm8hdKXaxbeiiREFl7ni1G9lP7j
    1Gdf/cmb+fq2sKrSgZyLEjQLFA==

    ===============================================

    Y2CjWsyI23Fa0G1pban8ep83zQAI
    7mERztK7a3ZufX0LWeAe/y50DURN
    kOOlakZ0dgkoipf/6KsNEEm2aptm
    L3/dXG1jKphojzSwNsS4PHY4qGKA
    9vHBEAsDLlwGrLFfmdtKOCrgNG6V
    ab7clt+yRFuxctwefegNu02YdlGC
    wEKI2MP9QcMXl/aFLkFsz3mBFn1t
    YZtjYFswD+7zJ6KETy1cRK0TG/UK
    /6GoBQtjLIeCjNBbrEWvOm6XunsO
    jCaOhBeccOe3lIUCbJEwSFKAGA==

    =============================================

    3AFJhTfHVl0MBUFC1NEgO34cyEqR
    saJhnLE8X1K0OU5wU630QIlLyAiu
    pMGYcSoTEanqEaBvKiXFfMvqbTM+
    X87dmWn6bicol0G9APDw1GKO4A4g
    Zyc8z47uRSNgqD9moJGFIdZZ+l1b
    +/PCg5MKBBhDhc6VDBKJ3hdVTu6L
    sW3+fY+9awZvyMMrXNu3STU0z0TX
    kHVOuMI+XqKeywPGEClGO/U5vgN7
    DbL2xQm0Czm89V3fPnY+03gVOkP2
    dvBKP4EqwgCXuxJVDEbC8T0bPQ==

    =============================================

    SoydMqMl+/Gpf41SeCYSamtq3urK
    wqREsSLloXTdR1DoEd6sFEtxWH+0
    w/nC12MfI+TzlhOuvit3bqOzUSrq
    XTPipT1EA1YfelWllo3inkHWZ8Bd
    IG4b/GCULr4ufAKEtZnyXVHeUPoo
    /HCkWPViDUwQUbQqZhcu7baPDnAo
    fGQlW5++dTXq3yIZTxNs8tpffgEk
    5oemtUyJhXaAEas6KQKw/vEFLPho
    48B3tuL31SNvluTSp3O3y8qZvSEV
    h3GE09Cp7E4SWKkv6rB9VG8Vcg==

    ===============================================

    Xzlv+2HZXpuIUhAUGVYmjhw6ncp9
    b7qlOIwQa4BiPlhJl61ma2fUW1s4
    BvNSzx0WgiHGB86X6VZ1ix3bXZop
    eq4MxQFHKtaLj60Y6jduOX8Id9Is
    oBIKLLkuRijSbZJpBxIqHLrz+2C/
    nym1n8XbWYagYJ1z4OqNxjkrCGfW
    LoSPC9jAtivGSk3T5lDsUzh6MEqF
    bSd6Bjce5tqDgX9AV0DM3icFg3dF
    /u9XXp+72DOCT9FStV01UwID6L/O
    zzokhH37OQL8irSbjE1FdGW+TQ==

    ==========================================

    BJNZHBPeVX4GKH3AbulBcezga945
    qNEKaHM8PpixioQLO0rZ57tUUQ7l
    jkWF/5Vh6pWVSJTmNhM54CkFDq3a
    M6EVzfPJT00+YS66mmQe4FI85zaj
    cvyNyiaKqBh8XjwxXhFs6oHjYJJ4
    MAWRTTvOVXDH29E7J30UQkz4qFWD
    0445Aj0clJCfu4WAmGq7TmAWF8H2
    g+k5VUTx8aBnRS/WVMG3iyryv+3h
    W2S4LjfsnF1Zsaf4D4N9p5Uqr2rI
    Lvhaj80tbxjTja+MLVhNr4GURQ==

    =================================================

    Lv/+h44wqgNXFicAJPjLZFqwpCoF
    mnn2JvfPTtQ9kEX51XdLNImcH6Pe
    bKp1KUMMGaUWSA5/NRMqqmoVaJQm
    Fh3B9G2jCyVfYeag+EFRCI/ByCpx
    Jg+yvnE4i9NUS1mKuBXD/QR5uEBk
    OsiAzv8DgQORN/sbIkjUKX7vwvzG
    6QEaDIPaWzKqPV7RIctjkUt4+5Av
    r5oBre/6Mg1Q1GIhBftZkD1UtPm3
    /3oDrT3o+2SlPNwElOcmypfkMHkk
    jAVK5+vfb8lOPKou3lmzUPZPKw==

    ==============================================

    zPH5/yKwB7akS0BMDoMsIRoIA0dN
    rE5EB8qSLhyCiwp+oZVZOYm7fH/o
    z7odFfCIGuTPHwUOB7r2u6AT1v0a
    i0vSNJXevY/dv/EY2hCClIhxTohs
    GUE0VLLV3vZJ0+AalJPuXfP3v513
    PQgPG0jLLMHoYm2gC0eZU4TCQx0B
    r4JJo5Ne0CH9wGfwiPdkIul0NhHU
    uQGP78v0FIsTBbQvDuing6q3msxX
    GQ+GeVUmshiefNvZ8MzB86ug0PaL
    hgtayc9N3lwGEf23C2S/MZW6bQ==

    ==================================================

    pF+PyM1Vz5eTwApjWBBOC8UtZmOV
    0xsmgjgvdTLVMXc8pLbhdsDkvMyI
    sgBv8WZuftr4FdKRxQVXVr+j5MAi
    ai3I9jJ4msA80i5ITzj+UykFuXeJ
    M8AB68iTiN80FjoKA1o2aJcjzc1J
    ffxHJCavDvlFG7KnfbuM9VjLHIbQ
    9lkXTIQX20o6qYOPmPpOG7JqeVLe
    H4XZLbTjzJp81h5YY9dVISCKbf01
    1Wl6vlh3L1Q1IFSnIfaQpTZwixHw
    bJZE8tuy2STl7G17uiqjuvcmdg==

  • 认识单元测试

    2009-02-10 11:00:44

    下面是我准备让开发人员了解的单元测试知识,从而有利于测试人员进行系统测试。不足之处请大家指出!多谢!

    认识单元测试

     

    一、单元测试的重要性

      单元测试是软件测试的基础,因此单元测试的效果会直接影响到软件的后期测试,最终在很大程度上影响到产品的质量。从如下几个方面就可以看出单元测试的重要性在何处。

      时间方面:如果认真的做好了单元测试,在系统集成联调时非常顺利,因此会节约很多时间,反之那些由于因为时间原因不做单元测试或随便做做的则在集成时总会遇到那些本应该在单元测试就能发现的问题,而这种问题在集成时遇到往往很难让开发人员预料到,最后在苦苦寻觅中才发现这是个很低级的错误而在悔恨自己时已经浪费了很多时间,这种时间上的浪费一点都不值得,正所谓得不偿失。

      测试效果:根据以往的测试经验来看,单元测试的效果是非常明显的,首先它是测试阶段的基础,做好了单元测试,在做后期的集成测试和系统测试时就很顺利。其次在单元测试过程中能发现一些很深层次的问题,同时还会发现一些很容易发现而在集成测试和系统测试很难发现的问题。再此单元测试关注的范围也特殊,它不仅仅是证明这些代码做了什么,最重要的是代码是如何做的,是否做了它该做的事情而没有做不该做的事情。

      测试成本:在单元测试时某些问题就很容易发现,如果在后期的测试中发现问题所花的成本将成倍数上升。比如在单元测试时发现1个问题需要1个小时,则在集成  测试时发现该问题需要2个小时,在系统测试时发现则需要3个小时,同理还有定位问题和解决问题的费用也是成倍数上升的,这就是我们要尽可能早的排除尽可能  多的bug来减少后期成本的因素之一。

      产品质量:单元测试的好与坏直接影响到产品的质量,可能就是由于代码中的某一个小错误就导致了整个产品的质量降低一个指标,或者导致更严重的后果,如果我们做好了单元测试这种情况是可以完全避免的。

      综上所述,单元测试是构筑产品质量的基石,我们不要因为节约单元测试的时间不做单元测试或随便做而让我们在后期浪费太多的不值得的时间,我们也不愿意因为由于节约那些时间导致开发出来的整个产品失败或重来!

     

    二、单元测试与功能测试比较

    单元测试好比房屋建筑现场的建筑监理员,他关心房屋的各个内部系统,如地基、构架、供电系统和管道设备等。房屋每部分工作都安全、正常。 单元测试是从开发者的角度来编写的。它们确保类的每个特定方法成功执行一系列特定的任务。每一个测试都要保证对于给定的一个已知的输入应该得到所期望的输出。

           
    功能测试类似于视察同一建筑现场的房主,他假定内部系统将正常运作,并假定建筑监理员在执行其任务。房主关心的是住在这所房子里将会怎样。他关心房子的外观如何,各个房间的大小是否合适,房子能否满足家庭的需要,以及窗户的位置是否有利于采光。
        

    三、单元测试内容和步骤

    单元测试的内容

    单元测试的对象是软件设计的最小单位——模块或函数;

    单元测试的依据是详细设计描述,测试者要根据详细设计说明书和源程序清单,了解模块的I/O条件和模块的逻辑结构。

    主要采用白盒测试的测试用例,辅之以黑盒测试的测试用例,使之对任何合理和不合理的输入都能鉴别和响应。要求对所有的局部和全局的数据结构、外部接口和程序代码的关键部分进行桌面检查和代码审查。

    单元测试任务包括:1 模块接口测试;2 模块局部数据结构测试;3 模块边界条件测试;4 模块中所有独立执行通路测试;5 模块的各条错误处理通路测试。

      

    1、模块接口:模块接口测试是单元测试的基础。只有在数据能正确流入、流出模块的前提下,其他测试才有意义。测试接口正确与否应该考虑下列因素:
      1 输入的实际参数与形式参数的个数是否相同;
      2 输入的实际参数与形式参数的属性是否匹配;
      3 输入的实际参数与形式参数的顺序是否一致;
      4 调用其他模块时所给实际参数的个数是否与被调模块的形参个数相同;
      5 调用其他模块时所给实际参数的属性是否与被调模块的形参属性匹配;
      6调用其他模块时所给实际参数的量纲是否与被调模块的形参顺序一致;
      7 调用预定义函数时所用参数的个数、属性和顺序是否正确;
      8 是否存在与当前入口点无关的参数引用;
      9 是否修改了只读型参数;
      10 对全程变量的定义各模块是否一致;
      11是否把某些约束作为参数传递。

      2、局部数据结构测试:检查局部数据结构是为了保证临时存储在模块内的数据在程序执行过程中完整、正确。局部数据结构往往是错误的根源,应仔细设计测试用例,力求发现下面几类错误:
      1检查不正确或不一致的数据类型说明;
      2使用尚未赋值或尚未初始化的变量;
      3错误的初始值或错误的默认值;
      4变量名拼写错误或书写错误;
      5不一致的数据类型。

      

    3、独立执行通路:在模块中应对每一条独立执行路径进行测试,单元测试的基本任务是保证模块中每条语句至少执行一次。此时设计测试用例是为了发现因错误计算、不正确的比较和不适当的控制流造成的错误。此时基本路径测试和循环测试是最常用且最有效的测试技术。计算中常见的错误包括:
      1 误解或用错了算符优先级;
      2混合类型运算;
      3变量初值错;
      4精度不够;
      5表达式符号错。

      4、错误处理通路:一个好的设计应能预见各种出错条件,并预设各种出错处理通路,出错处理通路同样需要认真测试,测试应着重检查下列问题:
      1输出的出错信息难以理解;
      2记录的错误与实际遇到的错误不相符;
      3在程序自定义的出错处理段运行之前,系统已介入;
      4异常处理不当;
      5错误陈述中未能提供足够的定位出错信息。

    5、边界条件:边界条件测试是单元测试中最后,也是最重要的一项任务。众的周知,软件经常在边界上失效,采用边界值分析技术,针对边界值及其左、右设计测试用例,很有可能发现新的错误。

     

    2、单元测试的步骤

    1 理解需求和设计

      理解设计是很重要的,特别是要搞清楚被测试模块在整个软件中所处的位置,这对测试的内容将会有很大的影响。需要记住的一个原则就是:好的设计,各模块只负责完成自己的事情,层次与分工是很明确的。在单元测试的时候,可以不用测试不属于被测试模块所负责的功能,以减少测试用例的冗余,集成测试的时候会有机会测试到的。

    2 概览源代码

      浏览一下源代码,主要任务:

      (1)初步检查源代码的编码风格与规范

      (2)大致估算测试工作量,比如:需要多少的测试用例、需要写多少的驱动模块和桩模块等。

      (3)确定模块的复杂程度,初步制定测试的优先级等。

    3  精读源代码

      认真阅读和分析代码,主要任务:

      (1)理解代码的业务逻辑。

      (2)检查代码与设计是否相符,如果详细设计没有该模块的流程图的话,先去画出流程图。

      (3)仔细研究逻辑复杂的模块

      (4)可以采用一些检查列表来检查程序可能会出现的问题。如果没有检查列表,那么,可以根据程序的特点,有针对性地检查容易出问题的地方(记得把经验总结下来供下次使用)。

    4  设计测试用例

      综合运用白盒测试方法(和结合黑盒测试方法)来设计测试用例,包括功能测试性能测试等,要达到一定的测试覆盖率。在设计测试用例的过程中,流程图或控制流图是分析的好帮手。

    5  搭建单元测试环境

      使用XUnit或自己写的框架将有助于单元测试的实施。在这个阶段主要就是写桩模块和驱动模块,第4步所设计的测试用例是通过驱动模块传递给被测试模块的,然后驱动模块想办法获取被测试模块对数据的处理结果,并判定返回的实际结果与测试用例的预期结果是否一致,通过测试框架来记录执行的结果,对于出现的错误,还需要统计错误的信息,供执行完之后分析。

      搭建单元测试环境要避免在main函数中使用printfscanf函数来跟测试人员交互来达到获取测试用例数据的信息。这样的测试还是没有摆脱手工测试方式,效率是低下的。同时,对于测试结果是否通过测试也不要使用printf方式打印被测试函数的返回结果值,避免要人工去检查结果。

    6  执行测试

      运行写好的驱动模块完成对被测试模块的测试。

    7  补充和完善测试用例

      单元测试也是个循序渐进的过程,可能一开始考虑的不够全面,或预期的覆盖标准太低,需要在测试过程中不断补充测试用例,直到满足要求为止。

    8  分析结果,给出评价

      根据测试的结果分析、查找错误的原因,并找到解决的办法。测试结束之后,根据测试过程的数据统计,给出被测试对象评价

     

     

  • qtp测试字体颜色(转载)

    2008-12-31 10:17:23

    和大家分享一下刚学的测试字体颜色的方法。

    set iDisplay = Browser().Page().WebElement().Object
    ' Get the currentstyle object
    set iDisplayStyle = iDisplay.currentstyle
    ' Access the Display attribute
    sTmp = ""
    sTmp = iDisplayStyle.color

    'This way gets you the color of object.

    当然字体大小,什么字体也一样可以测试了。

  • 如何复现不可复现的严重Bug

    2008-12-05 08:53:16

    从标题来看大家可能会觉得晕,这里说到的不可复现是指这些Bug有时出现,有时候不出现。相信大家在测试过程中肯定遇到过这种Bug,不少这种不可复现的Bug定位起来非常困难,可能很长时间都不能得到解决。能否复现这些不可复现的Bug成为大家关注的一个话题,最近国外的测试专家James Bach、Jonathan Kohl等对这个话题进行了一些探讨,这里把他们的一些思路理出来和大家分享。
        要想复现不可复现的Bug,需要先提到一个概念就是ET(Exploring Test),也就是探索式测试,这种测试方法是由James Bach首先提出来的,在所掌握的被测对象的信息不是很充分的情况下,这是一种很有效的测试方法,如果大家感兴趣,我再整理一篇ET的文章出来。
        在给大家阐述如何复现不可复现的Bug的思路之前,先说说为什么要复现这些不可复现的Bug(废话两句^_^)。对于整个项目或者产品而言,如果这些不可复现的Bug是很严重的Bug,比如导致系统崩溃等,如果不能及时、准确的定位和解决,最终发布出来的软件到达用户手中后,一旦出现势必会影响软件已经公司在用户心中的形象,严重的会“迫使”用户选择竞争对手的产品,这些显然都是公司所不愿看到的。而对于测试人员而言,出现了这些不可复现的Bug,实际上是一次很好的锻炼和提高机会,如果只是提交缺陷报告将这个大皮球踢给开发人员,不仅丧失了一次提高测试水平的机会,还有可能破坏和开发人员之间的关系。
        废话完了,进入正题。当出现不可复现的Bug时,大家可以从以下五个方面来进行考虑:
    1、被测对象的版本信息
        我测试的到底是哪个版本,这主要是有两个作用:一是确认我测试的是正式的软件版本,如果不是就先记录下该问题,然后选择正式的版本进行测试(开发人员基于尝试的一次非正规的修改可能会导致不可复现的Bug);二是可以和其它版本进行对比,如果其它的版本没有类似的问题,就可以去对比这两个版本之间的区别。
    2、环境
        这里的环境是指出现不可复现的Bug时所对应的测试环境等,比如测试所用的计算机,如果出现不可复现的Bug,那我换一台机器是不是还会出现类似的问题,也就是说通过环境的改变来进一步搜集不可复现Bug的相关信息。
    3、模式
        这里的模式是指我对这个Bug如何出现的一个理解,先给这个Bug设定一个模式,比如是不是数据库通信中断,然后再进行测试,收集更多的信息去修改和完善这个模式,这样不断进行,最终直到Bug能完全复现为止,这个时候只要使用这个模式就可以复现出Bug了。
    4、人
        这里提到的人有两个含义:一是测试是由人来进行的,人的操作、人的思维方式会有不同,通过分析这些信息也有可能找到这些不可复现的Bug的蛛丝马迹;二是想复现不可复现的Bug,往往需要多个人之间的相互协作,比如测试人员、开发人员等,通过大家的沟通和协作就能更容易去复现了。
    5、测试工具
        通过一些debug工具或者log工具等搜集内存等信息,根据这些信息来进行分析,找出不同信息之间的共同点,比如某一块内存始终都会被改写等,通过这种方式来去复现Bug。
        上面的五个方面都是和ET的思想紧密相关的,通过不断的测试和不断的信息收集和分析,逐步的把模糊的、不确定的测试变成清晰的、确定的测试,这样就能复现那些不能复现的Bug了。考虑信息时可以从以上五个方面来进行考虑。
  • 08年最流行的十大SaaS术语

    2008-11-11 10:47:26

    每当有一种新技术出现,相关的流行词便开始在网上漫天传播。下面,我们总结出了如今最流行的十大SaaS术语,目前,正流行着一种新技术“SaaS”或“Software-as-a-Service”,即“软件作为服务”。这个新兴词在网上大有愈演愈热之势。付费SaaS多集中在企业管理软件领域。国内最早在2004年出现了800CRM和Xtools等托管型软件,标志着SaaS模式在中国的诞生。

    下面,我们总结出了如今最流行的十大SaaS术语:

    (1) 多重租赁(Multi-tenancy)

    SaaS的“多重租赁”概念就是,多个公司将其数据和业务流程托管存放在SaaS服务商的同一服务器组上,相当于服务商将一套在线软件同时出租给多个公司,每个公司只能看到自己的数据,由服务商来维护这些数据和软件。也就是说,多个公司登录到同一网站,但登录后看到的界面和数据,不同的公司大不相同。

    这种模式有利有弊。好处是卖主相对于每个客户的平均硬件和维护成本很低。卖主将这种成本优势分摊给客户,客户用不着花大力气去维护自己的系统平台。服务商同步升级硬件软件,客户不需要另付费。

    但是也存在一定的弊端,由于SaaS模式是由服务商来维护系统,因此当服务商要对系统进行升级时,客户也只能跟着升级。这有点像中国以前吃大锅饭的时代,由中央统一分配。比如说6月1日,服务商要发布新版本,到时候客户就都只能使用新版本的系统。确实也只能这样,否则就不叫“多租”了。而且如果服务商支持多种不同版本的系统,那么成本就会相应地增加。当然,绝大多数的客户会更喜欢升级后的软件版本。

    (2) 跨界混搭(mash-up)

    “跨界混搭”这个术语起源于流行音乐,编曲者把两张唱片混编以后重新制作出一首新歌。这个概念应用在SaaS上,就是指把多个不同的在线应用软件服务搭建成为一种新型的整合服务。用户通常只需要登录一次就可以使用集成好的应用软件组合。

    需要注意的是,当你把多种SaaS服务混合到一个软件中去后,其中一种会是核心,如果其出现严重问题,将会影响到整个软件的使用。

    (3) 集成器(Connector)

    集成器是一种软件程序,让你从一个应用程序中读取数据,然后下载到SaaS解决方案中(同样可以用于将数据送回到另一个应用程序中)。这种数据传送通常用于实时或批量传送的情况,企业完成初始数据的导入或导出,然后根据需要定期更新这些数据。

    比如,像国外的SaaS服务商Salesforce或国内的800CRM提供SAP集成器,就将SAP中的客户数据导入到Salesforce或800CRM系统中。

    (4) 解决方案扩展(Solution extension)

    SaaS 解决方案具有的扩展性让用户能够在已存在的软件结构上,按需再增加额外的工具或功能。像前面提到的Salesforce的App Exchange应用软件开发平台,以及国内的SaaS托管商800CRM的800App Native应用软件开发平台都是解决方案扩展的典型代表。

    还有一些扩展性例如可以扩展数据模型,提供个性化的用户界面以及其他更多自定制的扩展服务。

    (5) 垂直应用(Vertical applications)

    “垂直应用”不是SaaS的专用术语,它也应用于其他领域,通常是指为某一个领域(例如银行,医药等)建立一个专门的平台。虽然它已经在传统行业应用很多年了,但是相对来讲应用在SaaS中还是一个比较新的概念。

    每当有一种新技术出现,相关的流行词便开始在网上漫天传播。下面,我们总结出了如今最流行的十大SaaS术语

    随着SaaS的不断成熟,客户希望SaaS服务商能提供详细的垂直应用行业方案。例如,目前Salesforce的APP Exchange平台已经能够实现全方位跨行业的应用,各个行业的公司都能够在Salesforce的平台上进行二次开发。

    (6) 参数应用(Parametric applications)

    在传统软件模式下,如果软件的服务功能需要改变,那么相应的代码也需要重新编写。但是在SaaS模式下,用户可以通过输入新的参数变量,或者制定一些数据关联规则来开启一种新的应用。这种新式服务模式也被称为“参数应用”,“宏”或“自定制对象”,主要是因为这种应用程序可以让用户自己定制新的应用,不需要懂软件编程。

    Salesforce或800CRM升级系统,自定制对象也同时升级,而最本质的应用则是客户可以自己通过改变参数和参数关联来为系统增加新的功能。

    (7) 模块化(Modular)

    SaaS中模块功能主要用于关闭或开启服务。在聚集了丰富功能的强大应用平台中,IT经理可以像选择菜单那样任意地选择功能,关闭某些不需要用到的功能,也可以根据需求增加新的功能。

    SaaS服务商基于网络架构建立了自己的应用平台,模块的灵活性使得他们可以根据客户的不同需求,将功能复杂繁多的系统配置成适合客户的系统。

    (8) 在线SaaS (Net-native SaaS)

    “在线SaaS”从表面意思来看似乎有点累赘,SaaS本身的概念就是提供一种在线服务,因此所有的SaaS应用程序都应该是产生于网络,壮大于网络的。

    但该术语是相对于SaaS的前身--ASP(Application Service Provider,应用服务提供商)来说的,这是一种早期的远程软件托管形式。跟如今直接在网上使用的系统相比,ASP时代的用户可能觉得通过专线或专用加密设备访问的系统来得更安心。显然,早期的ASP解决方案设计的一些运行缓慢的程序并没有很好地体现“在线”这个概念,很多ASP客户需要借用VPN、Citrix等实现远程访问。

    所以当人们说 “在线SaaS”时,这个术语其实是在强调使用浏览器直接使用软件,而加密是通过浏览器通用的SSL加密协议。

    (9) 基础架构平台(Platform infrastructure)

    有时候SaaS的拥护者希望出现一种基础架构的平台来推动SaaS更好地发展。

    这是因为首先得有一个平台来支撑SaaS软件应用程序的运行,如今最著名的是国外Salesforce公司的APP Exchange平台,国内800CRM的800APP Native的平台与Salesforce兼容。

    (10) SaaS(软件作为服务)

    最后,我们别忘了SaaS本身就是个非常红火的流行词。厉害的SaaS销售代表直接用SaaS就能解决你所有管理软件问题。比起其它软件,SaaS软件更便宜,灵活性更强,能省掉更多的麻烦。

    SaaS确实存在很多优势。例如“在线托管”,就一改传统软件需要用户自己购买,配置,维护的局面;SaaS还开启了一种新型商业模式,与传统软件需要用户一次性购买相比,SaaS可以按月付费,像国内的800crm和Xtools都可以按帐户数量和按月付费,完全体现了按需购买的要求。

  • QTP破解方法

    2008-10-17 10:30:08

    周末在家休息,打开qtp想调试一些写的代码,但是发现qtp9.5过期,本人很懒实在厌烦重新安装系统,到网上看资料发现都是先破解qtp8.2或者9.2然后卸载8.2或者9.2版本然后在安装9.5版本,那有没有办法直接破解呢?
          思考:8.2到9.2的破解方式是把mgn-mqt82.exe文件拷贝到C:\Program Files\Mercury Interactive和qtp同级目录,然后执行该破解文件,但是到了9.5版本安装路径变成C:\Program Files\HP了,我想肯定是是否是文件夹路径改变后导致破解不成功,所以先在系统中创建了C:\Program Files\Mercury Interactive文件夹,然后把mgn-mqt82.exe拷贝到文件夹下,执行该破解文件,意想不到的事情发生,系统错误mgn-mqt82报错,不管三七二十执行QTP 9.5,发现破解没有完成。
               既然不行换个思路,以前我用mgn-mqt82.exe破解8.2的时候,经常发现破解不成功的问题,就到C:\Program Files\Common Files\Mercury Interactive\License Manager文件夹下去修改LSERVRC文件,删除里面的生成代码,再次执行mgn-mqt82.exe,反复几次就可以达到破解8.2的目的。
              既然这样我就到C:\Program Files\Common Files\Mercury Interactive\文件夹下,发现没License Manager文件夹,也没有生成LSERVRC文件,那我就手工创建该文件夹,做好该工作之后,然后再C:\Program Files\Mercury Interactive文件夹,执行mgn-mqt82.exe,执行成功,没有报错,既然没有报错,那就继续我把C:\Program Files\Common Files\Mercury Interactive\License Manager\LSERVRC中产生的生成的字符串拷贝出来,然后拷贝到qtp的license向导中,破解成功。
         呵呵,功夫不负有心人,试验成功
        
         破解步骤:
         1.安装qtp
         2.拷贝mgn-mqt82.exe到C:\Program Files\Mercury Interactive(创建)文件夹下
         3.创建C:\Program Files\Common Files\Mercury Interactive\License Manager文件夹
         4.执行mgn-mqt82.exe
         5.打开qtp9.5,然后安装license,copy文件C:\Program Files\Common Files\Mercury Interactive\License Manager\LSERVRC中#之前的字符串
          如:
       3QVWCPPOS5NGGFM6KPX64EQFSH6INFRJIVMC5WZ4XIIFIXX86UCPIP4M686DZKV9NANA9BUP# "QuickTestPro" version "6.0", no expiration date, exclusive
    JZ7F79F6YQQFVUWNG2V7AW22K537DOELQYNX6VSCNCZ9J8M2QW9OXO5DSEQKUZA46X5BO# "FT-Unified" version "1.0", no expiration date, exclusive
        就拷贝#号前的3QVWCPPOS5NGGFM6KPX64EQFSH6INFRJIVMC5WZ4XIIFIXX86UCPIP4M686DZKV9NANA9BUP 然后paste到license向导中的license输入的地方,就可以了
         恭喜成功了
  • 深入认识session

    2008-10-15 10:44:09

    目录:

      一、术语session

      二、HTTP协议与状态保持

      三、理解cookie机制

      四、理解session机制

      五、理解javax.servlet.http.HttpSession

      六、HttpSession常见问题

      七、跨应用程序的session共享

      八、总结

      

      一、术语session

      在我的经验里,session这个词被滥用的程度大概仅次于transaction,更加有趣的是transaction与session在某些语境下的含义是相同的。

      session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个 session。有时候我们可以看到这样的话“在一个浏览器会话期间,...”,这里的会话一词用的就是其本义,是指从一个浏览器窗口打开到关闭这个期间 ①。最混乱的是“用户(客户端)在一次会话期间”这样一句话,它可能指用户的一系列动作(一般情况下是同某个具体目的相关的一系列动作,比如从登录到选购商品到结账登出这样一个网上购物的过程,有时候也被称为一个transaction),然而有时候也可能仅仅是指一次连接,也有可能是指含义①,其中的差别只能靠上下文来推断②。

      然而当session一词与网络协议相关联时,它又往往隐含了“面向连接”和/或“保持状态”这样两个含义, “面向连接”指的是在通信双方在通信之前要先建立一个通信的渠道,比如打电话,直到对方接了电话通信才能开始,与此相对的是写信,在你把信发出去的时候你并不能确认对方的地址是否正确,通信渠道不一定能建立,但对发信人来说,通信已经开始了。“保持状态”则是指通信的一方能够把一系列的消息关联起来,使得消息之间可以互相依赖,比如一个服务员能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有“一个TCP session”或者 “一个POP3 session”③。

      而到了web服务器蓬勃发展的时代,session在web开发语境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器之间保持状态的解决方案④。有时候session也用来指这种解决方案的存储结构,如“把xxx保存在session 里”⑤。由于各种用于web开发的语言在一定程度上都提供了对这种解决方案的支持,所以在某种特定语言的语境下,session也被用来指代该语言的解决方案,比如经常把Java里提供的javax.servlet.http.HttpSession简称为session⑥。

      鉴于这种混乱已不可改变,本文中session一词的运用也会根据上下文有不同的含义,请大家注意分辨。

      在本文中,使用中文“浏览器会话期间”来表达含义①,使用“session机制”来表达含义④,使用“session”表达含义⑤,使用具体的“HttpSession”来表达含义⑥

      二、HTTP协议与状态保持

      HTTP 协议本身是无状态的,这与HTTP协议本来的目的是相符的,客户端只需要简单的向服务器请求下载某些文件,无论是客户端还是服务器都没有必要纪录彼此过去的行为,每一次请求之间都是独立的,好比一个顾客和一个自动售货机或者一个普通的(非会员制)大卖场之间的关系一样。

      然而聪明(或者贪心?)的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用,就像给有线电视加上点播功能一样。这种需求一方面迫使HTML逐步添加了表单、脚本、DOM等客户端行为,另一方面在服务器端则出现了CGI规范以响应客户端的动态请求,作为传输载体的HTTP协议也添加了文件上载、 cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的session机制则是又一种在客户端与服务器之间保持状态的解决方案。

      让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠,然而一次性消费5杯咖啡的机会微乎其微,这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案:

      1、该店的店员很厉害,能记住每位顾客的消费数量,只要顾客一走进咖啡店,店员就知道该怎么对待了。这种做法就是协议本身支持状态。

      2、发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。

      3、发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。

      由于HTTP协议是无状态的,而出于种种考虑也不希望使之成为有状态的,因此,后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择。

      三、理解cookie机制 

      cookie机制的基本原理就如上面的例子一样简单,但是还有几个问题需要解决:“会员卡”如何分发;“会员卡”的内容;以及客户如何使用“会员卡”。

      正统的cookie分发是通过扩展HTTP协议来实现的,服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如Javascrīpt或者VBscrīpt也可以生成cookie。

      而cookie 的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie,如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置,则把该cookie附在请求资源的HTTP请求头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示,如果某家分店还发行了自己的会员卡,那么进这家店的时候除了要出示麦当劳的会员卡,还要出示这家店的会员卡。

      cookie的内容主要包括:名字,值,过期时间,路径和域。

      其中域可以指定某一个域比如.google.com,相当于总店招牌,比如宝洁公司,也可以指定一个域下的具体某台机器比如www.google.com或者froogle.google.com,可以用飘柔来做比。

      路径就是跟在域名后面的URL路径,比如/或者/foo等等,可以用某飘柔专柜做比。

      路径与域合在一起就构成了cookie的作用范围。

      如果不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览器会话期的 cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。

      存储在硬盘上的cookie 可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存里的cookie,不同的浏览器有不同的处理方式。对于IE,在一个打开的窗口上按 Ctrl-N(或者从文件菜单)打开的窗口可以与原窗口共享,而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie;对于 Mozilla Firefox0.8,所有的进程和标签页都可以共享同样的cookie。一般来说是用javascrīpt的window.open打开的窗口会与原窗口共享内存cookie。浏览器对于会话cookie的这种只认cookie不认人的处理方式经常给采用session机制的web应用程序开发者造成很大的困扰。

      下面就是一个goolge设置cookie的响应头的例子

      HTTP/1.1 302 Found

      Location: http://www.google.com/intl/zh-CN/

      Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun,

      17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com

      Content-Type: text/html

      这是使用HTTPLook这个HTTP Sniffer软件来俘获的HTTP通讯纪录的一部分

      浏览器在再次访问goolge的资源时自动向外发送cookie

      使用Firefox可以很容易的观察现有的cookie的值

      使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。

      IE也可以设置在接受cookie前询问

      这是一个询问接受cookie的对话框。

      四、理解session机制

      session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。

      当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为 session id,如果已包含一个session id则说明以前已经为此客户端创建过session,服务器就按照session id把这个 session检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个 session id将被在本次响应中返回给客户端保存。

      保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID,而。比如weblogic对于web应用程序生成的cookie,JSESSIONID= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764,它的名字就是 JSESSIONID。

      由于cookie可以被人为的禁止,必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面,附加方式也有两种,一种是作为URL路径的附加信息,表现形式为http://...../xxx;jsessionid= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764

      另一种是作为查询字符串附加在URL后面,表现形式为http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764

      这两种方式对于用户来说是没有区别的,只是服务器在解析的时候处理的方式不同,采用第一种方式也有利于把session id的信息和正常程序参数区分开来。

      为了在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。

      另一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如下面的表单

      <form name="testform" action="/xxx">

      <input type="text">

      </form>

      在被传递给客户端之前将被改写成

      <form name="testform" action="/xxx">

      <input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">

      <input type="text">

      </form>

      这种技术现在已较少应用,笔者接触过的很古老的iPlanet6(SunONE应用服务器的前身)就使用了这种技术。

      实际上这种技术可以简单的用对action应用URL重写来代替。

      在谈论session机制的时候,常常听到这样一种误解“只要关闭浏览器,session就消失了”。其实可以想象一下会员卡的例子,除非顾客主动对店家提出销卡,否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的,除非程序通知服务器删除一个session,否则服务器会一直保留,程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭,因此服务器根本不会有机会知道浏览器已经关闭,之所以会有这种错觉,是大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个 session id就消失了,再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的HTTP请求头,把原来的session id发送给服务器,则再次打开浏览器仍然能够找到原来的session。

      恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为seesion设置了一个失效时间,当距离客户端上一次使用session的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。

      五、理解javax.servlet.http.HttpSession

      HttpSession是Java平台对session机制的实现规范,因为它仅仅是个接口,具体到每个web应用服务器的提供商,除了对规范支持之外,仍然会有一些规范里没有规定的细微差异。这里我们以BEA的Weblogic Server8.1作为例子来演示。

      首先,Weblogic Server提供了一系列的参数来控制它的HttpSession的实现,包括使用cookie的开关选项,使用URL重写的开关选项,session持久化的设置,session失效时间的设置,以及针对cookie的各种设置,比如设置cookie的名字、路径、域, cookie的生存时间等。

      一般情况下,session都是存储在内存里,当服务器进程被停止或者重启的时候,内存里的session也会被清空,如果设置了session的持久化特性,服务器就会把session保存到硬盘上,当服务器进程重新启动或这些信息将能够被再次使用, Weblogic Server支持的持久性方式包括文件、数据库、客户端cookie保存和复制。

      复制严格说来不算持久化保存,因为session实际上还是保存在内存里,不过同样的信息被复制到各个cluster内的服务器进程中,这样即使某个服务器进程停止工作也仍然可以从其他进程中取得session。

      cookie生存时间的设置则会影响浏览器生成的cookie是否是一个会话cookie。默认是使用会话cookie。有兴趣的可以用它来试验我们在第四节里提到的那个误解。

      cookie的路径对于web应用程序来说是一个非常重要的选项,Weblogic Server对这个选项的默认处理方式使得它与其他服务器有明显的区别。后面我们会专题讨论。

      关于session的设置参考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869

      六、HttpSession常见问题

      (在本小节中session的含义为⑤和⑥的混合)

      1、session在何时被创建

      一个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某server端程序调用 HttpServletRequest.getSession(true)这样的语句时才被创建,注意如果JSP没有显示的使用 <% @page session="false"%> 关闭session,则JSP文件在编译成Servlet时将会自动加上这样一条语句 HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的 session对象的来历。

      由于session会消耗内存资源,因此,如果不打算使用session,应该在所有的JSP中关闭它。

      2、session何时被删除

      综合前面的讨论,session在下列情况下被删除a.程序调用HttpSession.invalidate();或b.距离上一次收到客户端发送的session id时间间隔超过了session的超时设置;或c.服务器进程被停止(非持久session)

      3、如何做到在浏览器关闭时删除session

      严格的讲,做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascrīpt代码window.oncolose来监视浏览器的关闭动作,然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。

      4、有个HttpSessionListener是怎么回事

      你可以创建这样的listener去监控session的创建和销毁事件,使得在发生这样的事件时你可以做一些相应的工作。注意是session的创建和销毁动作触发listener,而不是相反。类似的与HttpSession有关的listener还有 HttpSessionBindingListener,HttpSessionActivationListener和 HttpSessionAttributeListener。

      5、存放在session中的对象必须是可序列化的吗

      不是必需的。要求对象可序列化只是为了session能够在集群中被复制或者能够持久保存或者在必要时server能够暂时把session交换出内存。在 Weblogic Server的session中放置一个不可序列化的对象在控制台上会收到一个警告。我所用过的某个iPlanet版本如果 session中有不可序列化的对象,在session销毁时会有一个Exception,很奇怪。

      6、如何才能正确的应付客户端禁止cookie的可能性

      对所有的URL使用URL重写,包括超链接,form的action,和重定向的URL,具体做法参见[6]

      http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770

      7、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session

      参见第三小节对cookie的讨论,对session来说是只认id不认人,因此不同的浏览器,不同的窗口打开方式以及不同的cookie存储方式都会对这个问题的答案有影响。

      8、如何防止用户打开两个浏览器窗口操作导致的session混乱

      这个问题与防止表单多次提交是类似的,可以通过设置客户端的令牌来解决。就是在服务器每次生成一个不同的id返回给客户端,同时保存在session里,客户端提交表单时必须把这个id也返回服务器,程序首先比较返回的id与保存在session里的值是否一致,如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表示层模式的部分。需要注意的是对于使用javascrīpt window.open打开的窗口,一般不设置这个id,或者使用单独的id,以防主窗口无法操作,建议不要再window.open打开的窗口里做修改操作,这样就可以不用设置。

  • 测试人员怎样拿高薪

    2008-08-26 16:22:16

    看到许多媒体都在争相炒作测试工程师—这一“黄金”职业,我有些不同的看法。以下的内容是从网站上摘录的一段信息:

    随着国内IT企业对软件测试的重要性的日益了解,软件测试人才岗位的薪资待遇也稳步提升。据了解,刚入门的软件测试工程师薪水一般在3000-5000元左右,工作2-3年年薪普遍在10-15万之间。即便如此,很多企业仍然难以招到适合的人才。“我现在要是公布招聘10个软件开发人员,会来几百人投简历;如果我说招聘一名软件测试工程师,应聘者就会少很多。” 北京红旗中文贰仟软件技术有限公司总经理胡才勇不由感慨。智联招聘等招聘网站甚至撰文称“从入门级的初级测试工程师到高级测试工程师及项目负责人全线短缺。” 套用狄更斯那句话说:对于急需软测人员的企业来说,这是一个最坏的时代,但对软件测试人才来说,这是一个最好的时代。

    之所以摘录以上信息,不是针对这段信息本身有什么不同的观点,而是想要说明一位想从事软件测试行业的人或正在从事初级测试岗位的人员如何月薪可以拿到年薪10-20万。

    无论是你想升职还是想要加薪,首先必须要分析一下公司给员工升职和加薪的原因。我想这方面大家都是清楚的,但是好像操作起来又非常的模糊。谁都知道要升职或加薪就是要干的比别人好,要为公司创造比别人更多的价值,节约更多的资金和成本......但是如何做到这些呢,恐怕就没有什么特别行之有效的方法了。其实这个问题以前也困扰了我许久。

    记得当时最开始从事开发工作时,薪水才1.2k,现在虽然听起来少的可怜,但是十几年前自己还是挺满足的。所以工作的时候也就特别卖力,总是老板或主管要求的事情,一定要尽全力做好,老板和主管没有要求的,如果觉得对公司有帮助,也会主动去做。所以很快我就被提为小组长,当然薪水也涨到了2K。当时其实我的技术并不是我们组里最好的,所以有好多人都不服气,我也知道自己的不足,所以就二话不说,赶紧补呗,没过两个月就奠定了巩固的地位。 由此我获得了升职和加薪的第一个方法:那就是不仅要做好你该做的事情,还要尽量去做对公司有益的事情!这样在公司做了快两年的时间,后来因为老板要移民所以只能关掉公司,不过老板对我们还是不错的,都提前和我们员工打好了招呼,让我们先去找工作,然后等我们都安顿好了,他才把公司关掉的。

    后来就去了一家美国公司,这是加薪的第二种方法—“成功”跳槽!请注意不是每一次普通的跳槽都可以使你的工资翻倍的,只有你在前一家企业确实为公司做出过真正的贡献,那么以后的跳槽才会被新的东家所欣赏。所以我强烈建议目前在公司工作的兄弟姐妹们一定要随时留心,随时积累工作心得,最好有一些真实客观的数据(比如目前您所测试的项目中,您个人所发现的缺陷占到整个团队发现缺陷的比率是多少?您个人发现的对公司最有价值的缺陷是什么?.......)说明您为上家公司所作的贡献是什么,无论是技术上的,还是管理上的,都最好有一些客观的数据证明。所以工作过程中处处积累,处处留心才能为您以后的成功跳槽打好基础,而不是等到新东家面试您的时候,您才拼命的“回忆”自己的光辉业绩,那不容易让人家信服的!

    在这家美国公司里,技术的长进不是特别大,但是毕竟是外企,所以对自己“英语”能力的锻炼可就提供了非常好的机会。虽说是六级,但是没进这家公司之前,根本就没说过外语。所以刚进去的时候,我和老外主管沟通真是挺费劲的,不过没关系,还是老办法—补呗!二话不说,没过一个月,我的经理就夸我有很大的进步。过了英语关,我的工作也更如鱼得水了,而且公司让我负责与美国那边的客户沟通,尤其是针对客户提出的问题进行一些软件功能检查。由于客户评价很好,所以我又一次得到了升职和加薪的机会,这使我又获得了一个新的方法—想尽一切办法为公司的“客户”提供最好的服务!

    就这样一路走来,从开发转到测试再到负责公司的过程改进,做了不少的角色,但是等到薪资想要超越更多一些的时候,发现没有什么好的方法可以让我迈过这个坎,因为在公司工作的过程中,总是自己在指导别人如何做事,但其实自己做事的过程中,尤其是技术方面,也有许多不到位的地方,但是总也是找不到特别有效的解决方案。总是一个项目接一个项目的忙碌,有一次同时负责4个项目,真觉得分身乏力!郁闷了好久,不知道下一步该怎么走,一个项目一个项目的做,同样的问题反复出现,丝毫没有好的解决方案.....当时我曾经有想法改行,不做技术了,想去做销售!因为无法突破自己的瓶颈。

    直到“撞”到了51tesing,(之所以说是撞到了51tesing,是因为当时其实只是打算做一名兼职老师,挣点外快就行了,并没有打算留下来。)。遇到了我测试生涯中的三个贵人,也是我现在的老板和上司—周峰老师、王威老师和朴老师,但是我们都尊敬的称他们为老师(这也是我们51testing的一种文化吧,无论是领导还是同事之间,大家都以老师相称)。他们给了我许多指导,让我看到了自己在技术上的不足,也通过教学的环节,让我把自己的所得与大家共同分享,使我终于明确了自己的发展方向,突破自己的瓶颈的同时又获得最重要的一个法宝—适时地停下来,总结自己,与更多的人分享,才能更快的提高自己!

    就像我们说宝马车和普通车的区别,其实不在于宝马车比普通车跑得更快,最大的区别是当时速过百时,宝马车可以随时稳定的“叫停”,但是其他的车就完全不听指挥了。

    所以如果大家想要获得更好的加薪和升职的机会,首先要脚踏实地的认真高效做事,无论老板有没有盯着你,记着这是为“自己工作!”,绝不是为老板工作,只有自己的能力提高了,为公司创造了真正的价值,才会有更多更好的机会迎接你!同时别忘记在工作过程中一定要不断地充电学习找一个优秀、无私的“教练”是成功的关键,否则自己很难突破的,起码短时间内是绝对不可能的!最后就是要适时地停一停,对以前的自己好好总结一下,才能为第二次腾飞作好充分的准备!

461/3123>
Open Toolbar