qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

使用VC连接Access数据库的两种方法

 以前的时候用VC写了两种连接Access数据库的方法,为了方便以后查找把这两种方法做一下简单的介绍。Windows平台的数据接口标准有ODBC、OLE DB、ADO和Borland的BDE接口,ODBC(Open DataBase Connectivity)只能用于访问关系型数据库,为了访问非关系型数据微软设计了OLE DB接口并在此基础上推出了ADO(ActiveX Data Objects)。本文介绍的方法是ODBC和ADO。
  一、使用ODBC接口,在这里我们使用MFC的CDatabase类,该类是对SQLConnect等ODBC的API的封装。需要包含afxdb.h
BOOL ODBCConnect(CString strDBFile)
{
CString strConnect;
strConnect.Format(_T("ODBC;DRIVER={MICROSOFT ACCESS DRIVER (*.mdb)};UID=sa;PWD=;DBQ=%s"), strDBFile);
CDatabase db;
if(db.Open(NULL, FALSE, FALSE, strConnect))
{
//连接数据库成功
CRecordset rs(&db);
CString strSql;
strSql = _T("select * from info");                                //SQL语句
rs.Open(AFX_DB_USE_DEFAULT_TYPE, strSql);                        //执行Sql语句(可添加 删除 查询等)
if(rs.IsOpen())
{
CDBVariant variant;
rs.MoveFirst();
while(!rs.IsEOF())
{
//读取记录
rs.GetFieldValue(_T("姓名"), variant);
rs.MoveNext();
}
}
db.Close();
return TRUE;
}
return FALSE;
}
 二、使用ADO连接数据库,因为要使用COM,需要初始化(CoInitialize).然后就可以生成接口的对象操作,代码如下:
#import "C:Program Files/Common Files/System/ado/msado15.dll" rename("EOF", "adoEOF")    //生成C++类,改变EOF函数的名称
using namespace ADODB;
BOOL ADOConnect(CString strDBFile)
{
_ConnectionPtr pConnection;
if(pConnection.CreateInstance(__uuidof(Connection)) != S_OK)
{
return FALSE;
}
CString strConnect;
strConnect.Format(_T("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s"), strDBFile);
if(pConnection->Open(_bstr_t(strConnect), "", "", adModeUnknown) == S_OK)
{
//连接数据库成功
_RecordsetPtr pRecordset;
if(pRecordset.CreateInstance(__uuidof(Recordset)) != S_OK)
{
pConnection->Close();
return FALSE;
}
CString strSql;
strSql = _T("select * from info");
HRESULT hr = pRecordset->Open(_bstr_t(strSql), _variant_t((IDispatch*)pConnection, TRUE), adOpenUnspecified, adLockUnspecified, adCmdUnknown);
if(hr != S_OK)
{
pConnection->Close();
return FALSE;
}
_variant_t vt;
pRecordset->MoveFirst();
while(!pRecordset->adoEOF)
{
vt = pRecordset->Fields->GetItem("姓名")->Value;
pRecordset->MoveNext();
}
pConnection->Close();
return TRUE;
}
return FALSE;
}

posted @ 2014-08-27 10:41 顺其自然EVO 阅读(161) | 评论 (0)编辑 收藏

实例说明Java中的null

 让我们先来看下面的语句:
  String x = null;
  1. 这个语句到底做了些什么?
  让我们回顾一下什么是变量,什么是变量值。一个常见的比喻是 变量相当于一个盒子。如同可以使用盒子来储存物品一样,您可以使用一个变量来存储一个值。当声明一个变量时,我们需要设置其类型。
  在Java中变量分为两大类型: 原始值(primitive)与引用值(reference).
  声明为原始类型的变量,存储的是实际的值;声明为引用类型的变量,存储的是实际对象的地址(指针,引用).
  在上面的语句中, 初始化语句定义了一个变量 "x". x中存放的是String引用,此处为 null.
  下图对此概念提供了更形象的说明:
  
  如果 x = "abc",则引用示意图如下:
  
  2. 在内存中null具体是什么?
  在Java中 null 值是什么,在内存中null是什么?
  首先需要明确,null不是一个合法的object实例,所以并没有为其分配内存.
  null 仅仅用于表明该引用目前没有指向任何对象。
  我们看看 JVM规范 的描述:
  Java虚拟机规范并不强制要求使用一个具体的值编码null。
  我认为和其它类C语言一样,null是对引用变量的值全部置0。
  译者注: Java对象的属性域默认初始化其实很简单,把分配的内存所有位全部置0,所以 数字是0, boolean是false, 浮点是 0.0f, 引用是 null, 因为引用是内存地址,所以可以推测出 null 实际上就是一堆0. 用鼠标手想一想也就明白, 地址 0 肯定是不可以存放任何对象的。

posted @ 2014-08-27 10:37 顺其自然EVO 阅读(172) | 评论 (0)编辑 收藏

如何确定非功能需求?

非功能需求一般和系统的状态有关而与系统需要提供的功能无关。通常是系统的“ ilities”功能,比如可扩展性(scalability)、互操作性(interoperability)、可维护性(maintainability)、移植性(portability)、性能和安全性都包括在此类。敏捷团队经常纠结于定义和估算项目的非功能需求。
  Mike Cohn建议几乎所有的非功能需求都能以用户故事表述。他给出了几个例子展示非功能需求能够适用标准的用户故事模板
  幸运的是约束/非功能需求能很容易的按用户故事处理。这里给出几个例子:
  作为客户,我要在从Windows 95之后的所有版本的Windows上运行产品。
  作为CTO,我要(新)系统使用我们已有的订单数据库而不是创建新数据库,这样我们就不用再多维护一个数据库了。
  作为用户,我要网站在99.999%的时间是可访问的,这样我就不会感到沮丧并找其它的网站来用。
  然而,Mike也警告说用户故事模板只是用来作为一个思考工具。不应该用一个固定的模板来记录所有的非功能需求。
  Jason建议不要试图在用户故事级别记录非功能需求,团队应该把它们作为(项目)大图景的一部分。按照Jason所说,在他的团队,他们尝试过在每个单独的用户故事级别记录非功能需求,但是没起到作用。他提到:
  我喜欢把这些非功能需求(NFR)用户故事写在墙上并在工作区都能看到,这样可以提醒团队在给出估算时考虑这些约束的因素。
  Mike还提出一种明确的方法来估算非功能需求。按他所说,非功能需求与两个成本相关联
  初始遵循(非功能需求)成本——团队满足非功能需求所用的工作量。比如,在sprint 5花在性能测试上的工作量。
  持续遵循(非功能需求)成本——在以后的sprint中满足非功能需求的工作量。
  一旦团队接受非功能需求作为项目的一部分(就像我们团队在sprint 5中做的),他们需要把持续达到非功能需求作为项目的提示。我认为这种成本就像上税。进行性能测试(或者说遵从任何非功能需求)产生了一些额外的开支(税)。这种开支,或者说税,是必须定期付出的。
  为了估算,Mike认为这两种成本需要单独考虑。初始遵循成本应该和任何其它的用户故事或产品backlog中的任务一样被估算。持续遵循成本,团队和product owner需要决定多久要进行一次遵循验证工作。
  例如,假设团队和product owner同意每四个两周的sprint中进行一次性能测试。团队估算每次第四个sprint有六个点的工作要做。那就是大约每个sprint1.5点。如果团队的速度(velocity)是30个点,1.5点可以认为是大约5%的税。
  Nick Xldis对遵循成本进行了一次非常有意思的观察。据Nick所说,
  如果这种税持续增长,那你的架构或流程上就有问题了,需要格外关注。这是对于技术债的很好的晴雨表。
  Scott Ambler通过提升一个独立测试团队的能力分享了管理非功能需求的想法。
  Kassab、Olga、Maya和Alain介绍了NFR大小测量方法(NFSM)来减少估算非功能需求中的不确定性。
  因此,处理非功能需求可能不是痛苦的挣扎。关键是尽早处理它们并关注持续成本。
  注意:关于非功能需求这一术语的使用有很多想法和争论。Mike Cohn称其为约束而Tom Glib强烈建议称之为质量需求。

posted @ 2014-08-27 10:33 顺其自然EVO 阅读(442) | 评论 (0)编辑 收藏

使用LoadRunner进行服务器性能测试

 由于项目进入尾声,需要进行性能测试,没有专业的性能测试工程师,只好自己动手,研究一下loadrunner.
  发现loadrunner对web测试介绍比较多,牵涉到winsocket测试的资料极少,不过到处找一找,研究一下,也是可行的.
  先说一下我们的协议,采用tcp协议,与客户端采用自定义二进制流的方式进行通信.遵从普通的自定义协议的方式,即协议结构采用包头+包体的形式,包头为固定大小的长度,并在包头中加入包体总长度的字段.
  好了,下面可以用loadrunner进行协议测试了.首先想法在PC上实现一个简单的协议生成软件,我采用python进行编制,将协议跑一遍,然后用loadrunner进行录制.由于是针对单个的协议录制,因而在loadrunner中生成的脚本一目了然.考虑到同一条协议根据不同的条件,返回的数据是不一样的,因此脚本稍有点复杂.
  录制的脚本默认采用函数lrs_receive()来接收脚本,根据loadrunner的匹配规则,默认用data.ws中recv buf 中指定的长度来进行匹配,这样,由于同一个协议返回的数据总是不断变化的,就必然导致测试不通过的情况.在网上查到,可以通过某个设置使得每次达到录制时的数据量即可,但这样做有个明显的缺陷,每次读到到指定的数据后就不读取了,针对短连接,或是只测试一次的还可以,要是长连接,需要不停发送和接收的,必然出现测试不准确的问题.
  以下为解决方法,将lrs_receive改为lrs_receive_ex,并将一次读取改为两次读取,第一次读取固定大小的包头,读完包头后,解析出包体的大小,然后再读取包体.
  此方法适用所有自定义winsocket协议,附上相关脚本.
/********************************************************************* * Created by Mercury Interactive Windows Sockets Recorder * * Created on: Fri Jul 13 16:08:19 *********************************************************************/
#include "lrs.h"
vuser_init()
{
lrs_startup(257);
lr_start_transaction("create_socket");
lrs_create_socket("socket0", "TCP", "RemoteHost=127.0.0.1:110",  LrsLastArg);
lr_end_transaction("create_socket", LR_AUTO);
return0;
}
/********************************************************************* * Created by Mercury Interactive Windows Sockets Recorder * * Created on: Fri Jul 13 16:08:19 *********************************************************************/
#include "lrs.h"long getNextRecvLen(char* socketID)
{
int NumberOfBytes = 0;
int NextRecvLen = 0;
char *Buffer;
lrs_get_last_received_buffer(socketID, &Buffer, &NumberOfBytes);
memcpy((char*)&NextRecvLen, Buffer+20, 4);
lr_log_message("last_received:%d, NextRecvLen:%d", NumberOfBytes, NextRecvLen);
return NextRecvLen;
}
int receive_ex(char* socketID, char* buf)
{
long NextRecvLen = getNextRecvLen(socketID);//getNextRecvLen("socket0");char flag[50];
memset(flag, 0, sizeof(flag));
sprintf(flag, "NumberOfBytesToRecv=%d", NextRecvLen);
lr_log_message(flag);
lrs_receive_ex(socketID, buf, flag, LrsLastArg);
}
void doOneThing(int index)
{
char sendbuf[50];
char recvbuf1[50];
char recvbuf2[50];
char transbuf[50];
memset(transbuf, 0, sizeof(transbuf));
sprintf(transbuf, "one_send_recv_%d", index);
lr_start_transaction(transbuf);
memset(sendbuf, 0, sizeof(sendbuf));
memset(recvbuf1, 0, sizeof(recvbuf1));
memset(recvbuf2, 0, sizeof(recvbuf2));
sprintf(sendbuf, "buf%d", 2*index);
sprintf(recvbuf1, "buf%d", 2*index+1);
sprintf(recvbuf2, "dbuf%d", index);
lrs_send("socket0", sendbuf, LrsLastArg);
lrs_receive_ex("socket0", recvbuf1, "NumberOfBytesToRecv=32", LrsLastArg);
receive_ex("socket0", recvbuf2);
lr_end_transaction(transbuf, LR_AUTO);
}
Action()
{
lr_rendezvous("read_all_req_0");
doOneThing(0);
}
/********************************************************************* * Created by Mercury Interactive Windows Sockets Recorder * * Created on: Fri Jul 13 16:08:19 *********************************************************************/
#include "lrs.h"
vuser_end()
{
lrs_close_socket("socket0");
lrs_cleanup();
return0;
}
  由于是分两次读取数据,必然读取的内容与录制的会稍有不同,幸好我们判断成功与否不是用返回的数据进行比较,而只是核对一下数据的大小,因此完全可以手动修改数据脚本,以下为在录制的基础上手工修改的脚本(注意,只是更改了接收端)
send  buf0 28
"Test"
"\x00\x1b\x00\x00\x00"
"\x00\x00\x00\x00"
"\x12\x01\x00\x00\x00\x01\x00\x00\x00"
"\x02\x00\x01\x00\x01\x00"
recv  buf1 -1
recv rbuf0 -1
 

posted @ 2014-08-27 10:32 顺其自然EVO 阅读(857) | 评论 (0)编辑 收藏

Selenium—实现网页元素拖拽

Drag and Drop, 使用鼠标实现元素拖拽的操作貌似很复杂, 在Selenium中, 借助OpenQA.Selenium.Interactions.Actions类库中提供的方法, 实现起来还是比较简单的。道理如下:
  1. 找到要拖拽的页面元素-源(source)。
  2. 找到要释放的页面元素-目标(target), 页面显示的这个元素可能是个坑, 但是在页面代码中他就是一个元素。
  3. 借助(new Actions(IWebDriver)).DragAnddrop( source, target).Perform(), 完成元素拖放操作。
  示例代码:
// drag and drop
using OpenQA.Selenium.Interactions;
SIE.InternetExplorerDriver driver = new SIE.InternetExplorerDriver();
if (source != null && target != null)
{
// drag and drop
new Actions(driver).DragAndDrop(source, target).Perform();
}

posted @ 2014-08-27 10:29 顺其自然EVO 阅读(350) | 评论 (0)编辑 收藏

Redis和Ssdb读取性能对比

最近关注了一下ssdb,它的特点是基于文件存储系统所以它支撑量大的数据而不因为内存的限制受取约束.从官网的测试报告来看其性能也非常出色和redis相当,因此可以使用它来代替redis来进行k-v数据业务的处理.想法总是美好的,不过现实中就可能带点骨感.
  幸好ssdb是兼容redis的部份协议,所以直接用redis client库就可以进行一个压力测试.以于针对Redis和ssdb的几个读操进行一个简单的性能测试对比,这个测试不是直接在本机调用Redis和ssdb. 而是通过一个程序在别的服务器上调用.测试指令(get,hget,lregion)以下是测试结果截图
class Test
{
long mCount = 0;
long mIndex = 0;
private bool mRuning = true;
public long Count
{
get
{
return mCount;
}
}
public void Execute()
{
Console.WriteLine("* -----------------------------------------------");
Console.WriteLine("* redis get");
ConsoleWait.Start();
string result = OnTest(Config.RedisClient,GetHandler);
ConsoleWait.End();
Console.WriteLine(result);
Console.WriteLine("* ssdb get");
ConsoleWait.Start();
result = OnTest(Config.SSDBClient, GetHandler);
ConsoleWait.End();
Console.WriteLine(result);
Console.WriteLine("* -----------------------------------------------");
//
Console.WriteLine("* redis lregion[1-2]");
ConsoleWait.Start();
result = OnTest(Config.RedisClient, LRegionHandler1TO2);
ConsoleWait.End();
Console.WriteLine(result);
Console.WriteLine("* ssdb lregion[1-2]");
ConsoleWait.Start();
result = OnTest(Config.SSDBClient, LRegionHandler1TO2);
ConsoleWait.End();
Console.WriteLine(result);
Console.WriteLine("* -----------------------------------------------");
//
Console.WriteLine("* redis lregion[50-60]");
ConsoleWait.Start();
result = OnTest(Config.RedisClient, LRegionHandler1TO2);
ConsoleWait.End();
Console.WriteLine(result);
Console.WriteLine("* ssdb lregion[50-60]");
ConsoleWait.Start();
result = OnTest(Config.SSDBClient, LRegionHandler1TO2);
ConsoleWait.End();
Console.WriteLine(result);
Console.WriteLine("* -----------------------------------------------");
//
Console.WriteLine("* redis lregion[100-110]");
ConsoleWait.Start();
result = OnTest(Config.RedisClient, LRegionHandler1TO2);
ConsoleWait.End();
Console.WriteLine(result);
Console.WriteLine("* ssdb lregion[100-110]");
ConsoleWait.Start();
result = OnTest(Config.SSDBClient, LRegionHandler1TO2);
ConsoleWait.End();
Console.WriteLine(result);
Console.WriteLine("* -----------------------------------------------");
//
Console.WriteLine("* redis hget");
ConsoleWait.Start();
result = OnTest(Config.RedisClient, HGetHandler);
ConsoleWait.End();
Console.WriteLine(result);
Console.WriteLine("* ssdb hget");
ConsoleWait.Start();
result = OnTest(Config.SSDBClient, HGetHandler);
ConsoleWait.End();
Console.WriteLine(result);
Console.WriteLine("* -----------------------------------------------");
}
private void HGetHandler(RedisClient e)
{
while (mRuning)
{
long index = System.Threading.Interlocked.Increment(ref mIndex);
ProtobufKey key = "user_" + Data.Import.Users[(int)(index % Data.Import.Users.Count)].Name;
key.Get<Model.Order, Model.Employee, Model.Customer>(e);
System.Threading.Interlocked.Increment(ref mCount);
}
}
private void LRegionHandler1TO2(RedisClient e)
{
while (mRuning)
{
ProtobufList<Model.Order> list = "Orders";
list.Range(1, 2, e);
System.Threading.Interlocked.Increment(ref mCount);
}
}
private void LRegionHandler50TO60(RedisClient e)
{
while (mRuning)
{
ProtobufList<Model.Order> list = "Orders";
list.Range(50, 60, e);
System.Threading.Interlocked.Increment(ref mCount);
}
}
private void LRegionHandler100TO110(RedisClient e)
{
while (mRuning)
{
ProtobufList<Model.Order> list = "Orders";
list.Range(100, 110, e);
System.Threading.Interlocked.Increment(ref mCount);
}
}
private  void GetHandler(RedisClient e)
{
while (mRuning)
{
long index = System.Threading.Interlocked.Increment(ref mIndex);
ProtobufKey key = "user_" + Data.Import.Users[(int)(index % Data.Import.Users.Count)].Name;
key.Get<Model.User>(e);
System.Threading.Interlocked.Increment(ref mCount);
}
}
private string OnTest(RedisClient client,Action<RedisClient> handler)
{
mCount = 0;
mRuning = true;
for (int i = 0; i < 20; i++)
{
System.Threading.ThreadPool.QueueUserWorkItem((o) =>
{
GetHandler((RedisClient)o);
}, client);
}
int s = 20;
while (s > 0)
{
System.Threading.Thread.Sleep(1000);
s--;
}
mRuning = false;
System.Threading.Thread.Sleep(1000);
return string.Format("* [seconds:{1}/total:{0}]", mCount, mCount / 20);
}
}
  从测试结果看来差距还是非常明显,并不象官网那样说得这么理想.虽然SSDB效率上不如REDIS,但其基于磁盘存储有着其最大的优势,毕竟很多业务数据远超过服务器内存的容量.
  SSDB的测试结果不理想也许是硬件环境受限,如果有个SSD硬盘的测试环境估计也得到一个更好的结果,但在测试过程中发现一个问题就是SSDB占用的CPU资源也是非常大的,在以上测试过程SSDB的并发效率比不上REDIS,同时CPU损耗上基本要比REDIS高出一倍的样子.
  以上测试结果紧紧是是一些情况下的性能测试对比,不能完全表述出两者在应用的差距的结果,如果需要用到这些产品的同学不防在实施前进行一些测试为实施选择提供一个更可靠的结果.
 

posted @ 2014-08-27 10:19 顺其自然EVO 阅读(345) | 评论 (0)编辑 收藏

很久以前写的一个功能测试用例

你要测试windows附件中的计算器,请列出两个整数相加的测试用例(假设计算器能输入的数据最大长度为8位)。
  - 整数(双字节[16bit]):
  有效等价类:≥-32768(-2[-15]-1)且≤32767(2[15]-1)、
  无效等价类:<-32768、>32767
  边界值:     -32769、-32768、0、32767、32768
  错误推测:
  - 无符号整数(双字节[16bit]):
  有效等价类:≥0且≤65535(2[16]-1)、
  无效等价类:<0、>65535
  边界值:     -1、0、65535、65536
  错误推测:
  仅对第一类给出例子:
  有效的测试用例:(符合整数条件及其整数相加不超过整数范围的用例)应考虑上述情况
  如:
  100+200=300
  -100+400=300
  0+32767=32767
  -32768+1=-32767
  ......
  无效的测试用例:(不符合整数条件及其整数相加超过整数范围的用例以及无效的等价类)
  如:
  -1000000+100
  -32769+0
  32767+1
  -32768-1
    ......

posted @ 2014-08-27 10:13 顺其自然EVO 阅读(194) | 评论 (0)编辑 收藏

RAC数据库恢复到单实例数据库

RAC数据库恢复到单实例数据库的基本步骤如下:
  a.准备单实例服务器,pfile文件,启动到nomount
  b.备份rac数据库
  c.将备份文件拷贝到单实例服务器
  d.在单实例服务器上还原、恢复
  e.resetlogs打开数据库
  f.rename redo文件名
  g.disable thread 2并删除其redo组
  h.增加temp临时表空间数据文件
  i.删除不必要的undo表空间
  业务需要(比如,测试备份)将RAC数据库通过备份恢复到单实例服务器;下面是实际操作步骤;测试环境:RHEL4u7、oracle 10gR2、ASM、2节点,单实例服务器:RHEL4u7、oracle 10gR2、文件系统;在测试环境下,RAC 数据库文件都在asm时,在rename file操作时会遇到了BUG问题,最后的恢复时则需要重建控制文件;上面介绍的步骤是指没有BUG的情况的操作;
  另外,备份、拷贝的环节就请参考其他文档,就不介绍了,下面从第4步在单实例服务器上还原、恢复与打开开始介绍;
RMAN> startup nomount
RMAN> restore controlfile to '/app/oracle/oradata/ctl01.dbf' from '/app/oracle/backup/ctl_23_1_855331400';
RMAN> run{startup mount;
set until sequence 870 thread 1;
set newname for datafile 1  to '/app/oracle/oradata/system.257.779207027';
set newname for datafile 3  to '/app/oracle/oradata/sysaux.262.779207043';
set newname for datafile 4  to '/app/oracle/oradata/users.260.779207053';
set newname for datafile 2  to '/app/oracle/oradata/undotbs1.264.779207043';
set newname for datafile 15  to '/app/oracle/oradata/pptest_tbs.282.793979093';
set newname for datafile 5  to'/app/oracle/oradata/undotbs2.268.779207507';
set newname for datafile 8  to'/app/oracle/oradata/tbs_p3w.271.780396123';
set newname for datafile 9  to'/app/oracle/oradata/tbs_p4w.274.780396125';
set newname for datafile 6  to'/app/oracle/oradata/tbs_p1w.270.780396121';
set newname for datafile 7  to'/app/oracle/oradata/tbs_p2w.273.780396123';
set newname for datafile 14 to'/app/oracle/oradata/pptest_tbs.279.781454807';
restore database;
switch datafile all;
recover database;
}
sys@racdb3> alter database rename file '+DG/racdb/onlinelog/group_1.263.779207025' to '/app/oracle/oradata/redo1.log';
  rename 完所有redo文件后,即可resetlogs打开数据库;但是,实际操作中遇到bug7207932:Rman Restore From RAC ASM To Single Instance Non ASM Fails With ORA-00600 [kgeade_is_0] (文档 ID 1146703.1)
  Bug 7207932  ORA-600 [KGEADE_IS_0] WHEN RENAMING A FILE FROM ASM TO FS
  要想绕开的方法则是重建控制文件后,再打开数据库
  sys@racdb3> alter database backup controlfile to trace as '/tmp/ctl.trc' reuse resetlogs;
 打开trace文件,修改里面的logfile部分信息;然后重启数据库到nomount状态;
sys@racdb3> shutdown immediate
SQL> STARTUP NOMOUNT
CREATE CONTROLFILE REUSE DATABASE "RACDB" RESETLOGS  ARCHIVELOG
MAXLOGFILES 50
MAXLOGMEMBERS 2
MAXDATAFILES 2000
MAXINSTANCES 8
MAXLOGHISTORY 292
LOGFILE
GROUP 1 '/app/oracle/oradata/group_1.263.779207025'  SIZE 10M,
GROUP 2 '/app/oracle/oradata/group_2.259.779207027'  SIZE 10M,
GROUP 3 '/app/oracle/oradata/group_3.258.779207027'  SIZE 10M
DATAFILE
'/app/oracle/oradata/system.257.779207027',
'/app/oracle/oradata/undotbs1.264.779207043',
'/app/oracle/oradata/sysaux.262.779207043',
'/app/oracle/oradata/users.260.779207053',
'/app/oracle/oradata/undotbs2.268.779207507',
'/app/oracle/oradata/tbs_p1w.270.780396121',
'/app/oracle/oradata/tbs_p2w.273.780396123',
'/app/oracle/oradata/tbs_p3w.271.780396123',
'/app/oracle/oradata/tbs_p4w.274.780396125',
'/app/oracle/oradata/pptest_tbs.279.781454807',
'/app/oracle/oradata/pptest_tbs.282.793979093'
CHARACTER SET ZHS16GBK
;
  创建完成后,用backup controlfile进行恢复;
sys@racdb3> RECOVER DATABASE USING BACKUP CONTROLFILE until cancel;
sys@racdb3>ALTER DATABASE ADD LOGFILE THREAD 2
GROUP 4 '/app/oracle/oradata/group_4.265.779207453' SIZE 10M REUSE,
GROUP 5 '/app/oracle/oradata/group_5.266.779207459' SIZE 10M REUSE,
GROUP 6 '/app/oracle/oradata/group_6.267.779207467' SIZE 10M REUSE;
sys@racdb3> alter database open resetlogs;
成功resetlogs打开后,还需要做一些去thread 2的操作;
sys@racdb3> alter database disable thread 2;
sys@racdb3> alter database drop logfile group 4;
alter database drop logfile group 4
*
ERROR at line 1:
ORA-00350: log 4 of instance UNNAMED_INSTANCE_2 (thread 2) needs to be archived
ORA-00312: online log 4 thread 2: '/app/oracle/oradata/RACDB/onlinelog/o1_mf_4_9ym2kvgf_.log'
sys@racdb3> alter database clear unarchived logfile group 4;
sys@racdb3> alter tablespace temp add tempfile '/app/oracle/oradata/temp01.dbf' size 10M reuse;
Tablespace altered.
sys@racdb3> drop tablespace undotbs2 including contents and datafiles;

posted @ 2014-08-26 09:43 顺其自然EVO 阅读(249) | 评论 (0)编辑 收藏

关于Java加壳和代码混淆

 在C中,进行代码加密,首要经过加壳的方法。所谓加壳,即是先将程序代码加密,然后用特定的程序加载器,将代码解密后加载进内存,这样能够在避免代码的反编译,当然,有加壳东西,也有解壳东西,尽管不能100%避免crack,但仍然给代码增加一层有力的维护。
  然而在Java中,维护代码是件很困难的工作,由于class文件十分标准,很容易反编译,且反编译后的代码明晰可读。常见的维护办法是运用代码混淆器,打乱class和function以及变量的姓名,能够搅扰反编译后的代码的可读性。尽管简略提高了代码的安全性,但还仅仅适当于未加壳的C程序。
  java能够加壳吗?曾经我以为这是不能够的,由于动态加载代码这样的内存等级的操作,java无法做到,除非运用JNI(JavaNativeInterface),调用自个编写的C代码,在C代码中完成动态加载java代码。可是,C如何加载java代码呢?这需要对JVM适当的知道。所以其时的我以为这是不能够的。
  然而,最近接触的一些常识告诉我——java也能够加壳!!
  1.URLClassLoader。用URLClassLoader能够在java程序的运转时间,再将文件夹或许jar加入到classpath中,这个特性事实上即是动态加载。既然能够动态加载class的文件夹或许jar,为何不能够加载加密后的classes呢,将classes用自个的方法加密,在URLClassLoader调用时,运用自个的方法解密。不即是达到了加壳的目的了吗?不过解密的代码放在何处是个疑问,即是说解壳器的代码暴露在外,仍是很风险的。
  2.javassist。这实在是一个十分奇特的新技能,我是在学习Tapestry5时首次遇到这个包的,他能够动态创立java字节码,乃至能够修正你现已写好的函数,比如你的getter和setter,仅仅简略的读取和赋值,你能够在Runtime用他修正你的getter和setter,让你的getter和setter每次调用时都能够触发某些代码。凭借这项奇特的技能,必定能够完成更强壮的动态加载,加壳也就有了能够。

posted @ 2014-08-26 09:42 顺其自然EVO 阅读(1907) | 评论 (0)编辑 收藏

51Testing专访史亮:测试人员在国外

  版权声明:51Testing软件测试网原创出品,转载时请务必以超链接形式标明文章原始出处、作者信息和本声明,否则将追究法律责任。
  史亮,东南大学计算机软件与理论专业博士,研究领域为软件分析与测试。2006年加入微软(中国)有限公司,任职软件开发测试工程师,负责微软在线业务与商业智能产品的测试工作。2011年调至微软总部,从事Microsoft Office 2013的测试工作。2012年与淘宝测试工程师高翔合著了《探索式软件测试实践之路》一书。2014年,独自出版了《软件测试实战:微软技术专家经验总结》。目前,史亮正从事下一代Microsoft Office产品的研发工作。
  51Testing:史亮老师,您好,欢迎做客51Testing。听说您目前在国外工作,您是出于什么原因选择去国外工作的?
  史亮:在2011年,我打算更换工作环境,以接触更多的新技术和重要产品。于是,我主动申请工作调动,然后通过内部面试流程,获得了微软总部的工作机会,所在部门是Microsoft Office。
  51Testing:您去国外大概多长时间了?主要的工作内容是什么?
  史亮:从2011年到现在,我已经在微软总部工作了整整三年。最初我加入Microsoft Office部门,主要负责的是Microsoft Office 2013的研发,工作内容是测试Windows版本的Office产品。目前,我正参与研发下一代的Microsoft Office,主要工作是测试产品和开发测试辅助工具。
  51Testing:很多朋友刚出国时会有不适应,您是否也如此?在国外工作了三年,您感觉国外公司和国内公司存在哪些差异?(例如管理、工作环境、薪资、员工福利)让您感受最深的又是什么?
  史亮:没有存在不适应。我认为测试人员的工作环境、工作压力、员工福利等取决与具体的项目、团队和企业,与企业的注册国籍并没有直接的关系。而且,目前国内软件业蓬勃发展,有形形色色的项目和团队,任何外资企业所面临的情况,都可以在中国企业中找到相似的语境。一些中国企业在全球处于领先的地位,他们的企业文化、工作方式和福利报酬都胜过外企,且领先优势还在扩大。对于测试人员而言,应该多接触业内同行,了解他们的工作实践,以"他山之石可以攻玉"的心态,虚心请教。然后,将好的工作实践"因地制宜"地修改为适合当前项目的方法,从而改进项目环境、优化工作成果。
  51Testing:看来现在国内外软件测试行业的差异不是很大,测试人员想要出国发展还是十分可行的。那对于想要有出国发展的测试人员,您作为一个前辈对他们有些什么建议呢?
  史亮:测试专家Cem Kaner和James Bach对于测试人员的职业发展有一条忠告:"不管选择走哪条路,都要积极追求"。测试人员并没有被锁定在测试上,也没有被锁定在任何公司或软件行业上。他完全可以选择改变职业发展方向并追求其他目标。一旦下定决心,就要对自己负责,通过持续地努力来推动职业生涯的发展。
  51Testing:前面聊了很多关于您在国外工作的部分,满足了小编对于测试人员在国外工作状态的好奇。根据小编的了解,现在很多测试新人对软件测试的未来较为迷茫,而您在国内外都工作过很长一段时间,有相当丰富的测试经验,您是怎么看待未来的软件测试人员的发展趋势?
  史亮:为了更好地讨论这个问题,先介绍一个测试技术分类的参考模型。测试专家Lisa Chrispin和Janet Gregory在《敏捷软件测试》中将测试技术划分到如图1所示的四个象限中。
  图1  敏捷测试四象限
  "Q1:面向技术的(technology facing)、支持项目团队的(supporting the team)的自动化测试,例如单元测试、组件测试等。
  "Q2:面向商业的(business facing)、支持项目团队的自动化和手工测试,包括功能测试、样例、用户故事测试、原型、模拟等。
  "Q3:面向商业的、考验产品的(critique product)的手工测试,包括探索式测试,情景测试、可用性测试、用户验收测试、Alpha及Beta测试等。
  "Q4:面向技术的、考验产品的、基于工具的测试,例如性能测试、负载测试、安全性测试、属性测试等。
  利用敏捷测试四象限,测试人员可以快速理解测试技术在软件开发中的位置,并根据当前任务选择合适的测试技术。不过,我并不同意Lisa Chrispin和Janet Gregory将探索式测试(exploratory testing)置于Q3象限。探索式测试是一种并行地实施测试学习、测试设计、测试执行和结果评估的测试风格。作为一种测试思维方法,它可以指导四个象限的任何一种测试技术的使用。
  目前,软件行业高速发展,以前所未有的速度向各个产业渗透。在互联网应用、移动应用、物联网应用等重要领域,市场竞争日趋激烈。为了在竞争中脱颖而出,软件项目团队必须具备高度的机动性,能够快速地尝试新想法,并持续发布具有特色的产品。这要求程序员负责更多的测试活动,通过加速"编码-测试-重构"的循环,来快速交付高质量的代码。也就是说,程序员将承担Q1象限(面向技术、支持项目团队)的测试工作,以及部分其他象限的活动--以Q2象限(面向商业、支持项目团队)的活动较为常见。
  在该趋势下,专职测试人员的活动将向四象限的右侧和上方移动,更偏向面向商业的、考验产品的测试活动。从业务角度,测试人员的角色应该是领域专家和实际用户,能够以超越代码(beyond code)眼光来考察产品的商业价值和用户价值。从技术角度,测试人员的角色可以是黑客和技术专家,能够在安全性、性能、稳定性等领域实施专业的、高强度的测试。
  另一个软件研发的趋势是DevOps,即融合研发团队和运维团队,由一个团队负责整个产品开发、测试、发布、运维和更新。在此类团队中,测试人员需要承担部分开发和运维任务,例如分析服务端的日志、分析客户端提交的遥测(telemetry)数据、分析用户行为、报告服务状态、定位产品问题、修复特定环节的错误、发布产品更新等。这意味着测试人员的工作不仅仅是寻找缺陷,而是通过技术调查(调查对象包括已发布的线上产品)来获得产品信息,以持续提高产品质量。可以说,在一些项目环境中,测试人员的职责发生了变化,需要更多样化的技能。测试人员需要积极面对变化,拓展自己的能力,以适应行业的发展。
51Testing:您已经第二次做客我们51Testing了,上一次专访我们聊得是探索式测试,相信很多朋友都对此印象深刻。作为探索式测试的资深人士,怎样才能进行有效地探索式测试?另外很多优秀的软件测试工程师都能敏锐地嗅到bug,您认为该如何训练这方面能力?
  史亮:首先,"态度决定一切"。成为一个优秀的测试人员,我认为最重要的基础是对项目、对自己负责任的态度。对项目负责,测试人员需要提供高质量的测试服务来帮助项目成功;对自己负责,测试人员应该以专业人员(professionals)自居,坚持专业主义(professionalism),追求精湛的技艺和卓越的成果。这需要通过日复一日的努力工作来落实,无捷径可言。
  第二,Cem Kaner等测试专家指出"困惑是一种测试工具"。有时,软件的表现出乎测试人员预料,但是他并不能确定这是一个缺陷。这说明测试人员对软件的设计还有不了解的地方。他应该将此疑惑视为一个学习的机会,通过阅读文档、咨询同事等方法来获得答案。推而广之,如果测试人员对软件、技术或项目产生疑问,他应该感到警惕。这可能意味着他不了解业务逻辑,不知晓产品设计,不清楚实现细节。这些知识上的漏洞会导致薄弱的测试设计和严重的缺陷遗漏。
  负责人的测试人员不会放过任何一个疑问,在"好奇心"的指引下,他会"打破沙锅问到底"。他会运用多种手段(周密测试、代码分析、软件调试、文档阅读、请教专家等)对问题进行研究。通过积极地测试和学习,测试人员不但可以弥补知识的漏洞,还可以发现隐藏的缺陷。
  第三,测试人员需要"刻意练习"。测试专家已经给出了许多好的建议和方法,这些想法皆来自于实践。软件开发专家Ralph E. Johnson 指出"从实践中来的知识在没有实践之前是无法被真正理解的"(practical knowledge has to be experienced to fully understood),测试专家Cem Kaner等也认为"你不能掌握测试,除非你重新发明它"(You can't master testing unless you reinvent it)。因此,测试人员需要将学到的新技术应用于真实的测试,并认真评估其效果。通过练习、评估和反思,测试人员能够掌握方法的原理和细节,并混入自身经验和其他技术,以演化出新的方法。坚持这样的研究和创新将帮助测试人员走上精通之路。
  51Testing:许多刚从事测试的新人往往会在工作的过程中发现自己的很多不足,想要提高自己,在您看来,测试人员应如何提高自己的测试思维和测试技术?
  史亮:前面两个问题的回答对于本问题有参考价值。在这里,我补充说明一个测试人员容易忽略的要点:提高测试技术的根本目标是为了更有效的测试,在许多情况下,测试效果(测试技术的实施效果)决于测试人员对软件和项目的理解。
  我曾经长期测试一个网络应用。当我离开这个项目时,测试经理安排一个测试员工来接替我。他刚刚入职,对被测软件和业务领域都不了解,在工作中遇到了许多困难,我帮助他解决了一系列问题。作为一个测试工程师,我的工作效率更高,主要原因包括:
  " 我理解产品,知道它的业务目标,了解它通过什么方法去实现目标。因此,我能够快速地制定测试方案。
  " 我理解用户的期望,知道哪些功能绝对不能出错,需要仔细测试。我也知道哪些功能允许一些瑕疵,即便出错,也可以在三个月之后发布的下一个版本中修复。因此,我能够更好地分配测试时间。
  " 我理解产品的架构,阅读过大部分模块源代码,知道哪些模块容易出现哪些缺陷。因此,我可以针对不同的模块采用有针对性的测试策略。
  " 我曾经尝试自动化测试用户界面,但是发现此类自动化测试很不稳定,需要很高的维护代价,却不能发现错误。于是,我只为Web服务编写自动化测试用例,用手工测试来检查用户界面。因此,我回避了浪费时间却没有收益的任务。
  " 我了解产品元素和项目团队。当出现缺陷时,我知道如何阅读系统日志发掘蛛丝马迹;当我遇到困难时,我知道向哪位程序员或测试人员求助。因此,我可以深入挖掘并快速推进。
  " 我在原先的团队工作了很长的时间,与同事们保持了良好的关系。当我提出一些可测试性的建议时,比较容易受到程序员的支持。
  从以上几点不难看出,我能够更有效地测试,其主要原因不是我掌握更多的测试技术,而是我更了解软件产品、业务领域和项目环境。通过逐点分析,可以得到如下启示。
  " 产品是一种解决方案,如果没有解决问题,它就是无用的。测试人员需要了解软件产品和业务领域,才能设计有效的测试。
  " 测试是一种信息服务,要了解服务对象(通常最重要的服务对象是用户和项目经理)的需求。如果用户不能容忍某些错误,测试人员就需要仔细测试相关功能;如果用户对一些瑕疵并不在意,测试人员就不必在此花费更多的时间。只有了解服务对象的优先级,才能更好地设定测试工作的优先级。
  " 不同的模块采用不同的技术,拥有不同的典型错误。只有了解软件实现,才能设计差异化且有针对性的测试用例。
  " 测试设计可能包含错误,测试人员需要从错误中吸取经验和教训。避免一些已知的错误,会提高测试效率。
  " 当测试工作遇到困难时,测试人员需要知道在哪里寻找信息。了解产品能够提供的信息、了解哪位同事知道更多内幕,会节省时间。
  " "人脉"有时候会极大地提高测试人员的工作效率,测试人员需要和程序员和测试同事保持良好的关系。达成协作关系的关键之一是测试人员能够为同事们提供高质量的信息服务。
  " 在职业生涯中,测试人员总是会遇到新的软件、项目和团队。他应该培养一种好的工作风格,以求快速地理解产品和项目。
  实施高效的测试需要很多条件。熟练地掌握测试技术是一个很重要的因素,但很少会是决定性的因素。只有充分地掌握软件产品和项目环境,测试技术才能找到大放光彩的舞台。

 51Testing:想要提高测试技术,书籍是必不可少的朋友,作为探索式测试的忠实实践者,您能给我们的会员推荐几本相关书籍吗?
  史亮:探索式测试是一个内涵丰富的主题,感兴趣的测试人员可以从以下书籍入手。
  " Cem Kaner, James Bach, Bret Pettichord, 《软件测试经验与教训》(Lessons Learned in Software Testing:A Context-Driven Approach)。该书是语境驱动测试的经典著作,充满对软件测试的真知灼见,是探索式测试者案头必备。
  " 史亮,高翔,《探索式测试实践之路》。该书由我与淘宝资深测试工程师高翔合著,系统地总结了现有的探索式测试实践,并纳入了我们的经验和反思。探索式测试大师James Bach对此书予以了肯定:This is the first book on exploratory testing, in any language, that summarizes the published work in the field。
  " 史亮,《软件测试实战》。我本人是探索式测试的忠实实践者,该书可视为"一个探索式测试者的自我总结"。全书虽然没有强调名词"探索式测试",但是探索式测试的核心精神(将测试学习、测试设计、测试执行、测试结果评估作为相互支持的活动来并行实施)贯穿全书。
  " 我和高翔在《探索式测试实践之路》的附录B提供了一批推荐读物,供读者参考。
  51Testing:本次访谈即将接近尾声,再问最后一个问题,您以后会选择继续长期留在国外发展还是回国发展呢?
  史亮:我目前还在持续评估自己的职业发展,尚未做出长远的规划。
  51Testing:由于时间关系,本次访谈正式结束,非常感谢史亮老师抽出宝贵时间参加我们的访谈,祝您在国外工作一切顺利!
  史亮:谢谢,也祝51Testing越办越好!
 版权声明:51Testing软件测试网原创出品,转载时请务必以超链接形式标明文章原始出处、作者信息和本声明,否则将追究法律责任。

posted @ 2014-08-26 09:41 顺其自然EVO 阅读(185) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 58 59 60 61 62 63 64 65 66 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜