Ansel's Blog

It would probably render the application more complex

博客园 首页 新随笔 联系 订阅 管理
  81 Posts :: 1 Stories :: 115 Comments :: 2 Trackbacks

2008年5月22日 #

 

  我的一天在这个项目中,很多时候,我的一天是这样度过的。 
   AM9:00,开始工作,花5分钟时间看看项目组成员新发的项目日志。如果有必要,用15分钟和大家开个会,沟通遇到的最新问题。 
   AM9:30,内部重点沟通。和业务专家就下阶段工作和客户需求进行详细沟通,大约用半小时。 
   A10:00,向主管领导汇报工作。 
   AM10:30,与负责中行项目的销售沟通,最近客户配合不太积极,工作拖拉,请销售出面协调一下。 
   AM11:00~12:00,检查部分编码工作,上网浏览信息。 
   中午与项目组成员一起吃饭,大家聊聊彼此的工作、生活,分析员小周今天情绪不高,和他好好聊了聊。 
   PM1:00,询问采购部门扫描仪何时到货,如果迟迟不到位,该怎么办? 
   PM2:00~4:30,开评审会,用半小时讲解设计,包括具体的模块和技术应用,总结最近的设计问题,搜集大家的意见、建议。最终,评审通过。 
   PM4:30~5:30,整理会议纪要,与各部门确认,并安排跟踪。 
   我在这个项目中也负责一部分开发工作,但并不是我的工作重点。我的大部分时间都用在与项目组成员或其他部门的沟通上了,协调、整合各方资源,达成项目目标。   在软件项目管理中,有几个常见误区,如重技术轻管理,重开发轻计划,重编码轻设计,重编码轻测试等。虽然项目经理大都是技术出身,但做好项目经理,技术并不是关键。 
   项目经理需要四种基本素质及八大管理技能 
   项目经理的入行门槛 
   项目管理资深顾问周小桥教授指出,项目经理需要具备四种基本素质及八大管理技能。 
   ●四种素质 
   1.品德素质。项目经理对外与供应商、客户打交道,对内需要跨部门整合资源,诚信的品德素质是基础。 
   2.能力素质。项目经理需要具备较强的综合管理能力。 
   3.知识结构。如今的项目经理不再仅仅是个技术专家、在办公室画画图就可以了,需具备一般的管理知识,如市场营销、人力资源管理等;项目管理专业知识;应用领域知识,如IT、金融、房地产等行业知识。 
   4.身体素质。没有一天只干8个小时的项目经理。项目管理工作经常赶周期,赶进度,工作起来没日没夜,业内戏称“体力活”,需要具备良好的身体素质。 
   ●八大技能 
   1.项目管理与专业知识技能。项目经理需要制订项目计划、控制项目成本、确保项目质量,需要具备项目管理专业知识。 
   2.人际关系技能。这是项目经理面临的最大挑战,项目经理对上需要向老板汇报进展,对下需要向项目成员分配任务,对外要与供应商、承包商打交道,耳听八方,眼观六路,需要具备良好的人际关系技能。 
   3.情境领导技能。项目经理需要不断激励项目员工,努力冲锋陷阵。管理因人而异,需要针对项目组不同成员不同需求,在不同情境下因需而变。 
   4.谈判与沟通的技能。无论是与客户还是员工相处,项目经理85%的时间都在谈判、沟通。 
   5.客户关系与咨询技能。现在的项目经理不仅是技术专家,需要走到客户端,根据客户需求,为客户量身定做项目方案。有一位项目经理给一家工业锅炉公司设计网页,他把网页设计得十分漂亮,又是玫瑰花又是鸟鸣什么的。结果,客户大为不满:“我们的产品就是灰不溜秋的铁疙瘩,又不是搞电子商务的,搞这么花哨有什么用?” 
   6.商业头脑和财务技能。企业目标是通过项目管理实现的,项目经理需要把项目放在整个企业战略中考虑。比如由于IT行业竞争激烈,IBM转型为IT服务商,IBM的项目经理就必须跟上企业转型。另外,项目经理需要了解项目的投资汇报率,净现值等财务指标。 
   7.解决问题和处理冲突的技能,每天项目经理都会碰到无穷无尽的问题,如安全事故,成本超支了或项目人员携款潜逃了,作为项目经理,需要具备较强的应变能力及化解冲突的能力。 
   8.创新技能,很多项目都是前无古人,后无来者的事业,如神舟六号,这往往需要项目经理具备创新能力。 
   领导团队,多快好省地实现项目目标,这是项目经理发展的关键 
   项目经理如何发展 
   作为一个团队的领导者,项目经理需要不断“造势”,让整个团队鼓足干劲,形成你追我赶、力争上游的氛围。 
   ●鼓舞团队的士气(Morale)有激情,使战士愿意打仗,有不达目的不罢休的高昂士气。 
   ●提高团队的效率(Productivity),使战士会打仗,合理设置项目周期,项目一做就对。 
   领导团队,多快好省地实现项目目标,兼顾范围、时间、成本、质量,这是项目经理发展的关键。 
   多——指项目工作范围。项目经理要把项目规模范围界定清楚。 
   快——指项目工期,尽快完成项目任务是多数人面临的挑战,通常项目完成时间越快越好,按规定时间完成是基本标准。 
   好——项目交付结果质量,项目经理不能因为成本压力、时间期限而牺牲质量,要保证项目技术性能特征和质量。 
   省——项目成本,在保质保量的前提下,项目消耗费用也是重要指标。 
   项目经理的薪酬结构为:基本工资+项目奖金及费用奖金+年底分红,一般来说,软件行业项目经理薪酬状况如下: 
   项目经理 3-4年项目管理经验 6年以上项目管理经验 
   国内企业年薪 8-10万 10-12万 
   外企年薪 10-15万 15-20万 
   软件项目管理业内知名公司:IBM、朗讯、亚信、联想、神州数码 
   一个业务项目就是一个舞台,给项目经理一个充分展示才华的机会。通常,项目经理的晋升之路可以沿着:项目成员→项目经理→项目总监→运营总监,在技术和专业岗位不断得到提升。由于项目经理出色的管理能力和过硬的技术背景,不少项目经理往往可以转到业务部门,成为统筹大局的运营总监。 
  

posted @ 2008-05-22 15:37 Ansel 阅读(64) | 评论 (0)编辑

2008年5月21日 #

 

项目团队发展一般会经历这么几个阶段: 形成、震荡、规范、发挥 

形成(Forming)阶段特点: 

成员对工作和人际关系:高度焦虑状态 
成员的情绪特点:激动、希望、怀疑、焦急、怀疑 
在心理上:极不稳定状态 
应对措施:明确整个团队的方向、目标和任务;为每个人确定职责和角色 
领导风格:指导型的领导风格 

震荡(Storming)阶段特点: 

成员对工作和人际关系:剧烈动荡状态 
成员的情绪特点:紧张、挫折、不满、对立、抵制 
应对措施:应付和解决出现的各种问题和矛盾;引导成员对自己的角色及职责进行调整;邀请团队成员积极参与解决问题和作出决定。 
领导风格:影响型的领导风格 

规范(Norming)阶段特点 

成员对工作:积极、努力 
人际关系:已确立,大部分矛盾已解决 
成员的情绪特点:信任、合作、忠诚、友谊、满意 
应对措施:积极放权,使成员进行自我管理和自我激励;对成员取得进步给予表扬;积极支持团队成员的各种建议和参与;努力规范整个团队的行为。 
领导风格:参与型的领导风格 

发挥(Performing) 阶段特点 

成员对工作:积极、努力; 
人际关系:融洽 
成员的情绪特点:开放、坦诚、依赖、集体荣誉感 
应对措施:给予团队足够的授权,使团队做到自我管理和自我激励;及时公布项目进程,表彰先进;集中精力做好进展计划和项目变更,指导项目团对改进作业方法。 
领导风格:授权型的领导风格 

团队成员选择的3个原则: 

用更好更少的人; 
使任务和人员技能和动机匹配起来;
posted @ 2008-05-21 10:15 Ansel 阅读(68) | 评论 (0)编辑

2008年5月16日 #

[导读]: 本人做项目经理工作多年,感到做这个工作最要紧的就是要明白什么是因地制宜、因势利导,只有最合适的,没有什么叫对的,什么叫错的,项目经理最忌讳的就是完美主义倾向,尤其是做技术人员出身的,喜欢寻找标准答案,耽误了工作进度,也迷茫了自己。以下是本人一些做项目的个人体会,写出来供大家指点,在讨论过程中共同提高水平。

项目开始阶段是一个最重要的阶段。项目经理在接手一个新项目的时候,首先要尽可能地多从各个方面了解项目的情况,如:
  
1.这个项目是什么项目,具体大概做什么事情,是谁提出来的,目的是解决什么问题。在国内很多客户都很不成熟的情况下,千万不要根据项目的名称望文生义地去想象项目的目标。一个名为“办公自动化”的项目很有可能在你进场以后一个月才发现客户其实需要的是一个计算机生产管理辅助信息系统系统。前期了解情况的工作越详细,后面的惊讶就越少,项目的风险就越小。

2.这个项目里牵涉哪些方面的人,如投资方、具体业务干系方、项目建成后的运营方、技术监督方等等,很多项目里除了业主单位的结构很复杂以外,还有一些其他单位也会牵涉进来,如项目监理公司、业主的行业主管机构等。项目经理需要了解每个方面的人对这个项目的看法和期望是什么。事先了解各个方面的看法和期望,可以让你在做项目碰到问题的时候,就每件事情分析哪些人会在什么方面支持你,哪些人会出于什么目的反对你,从而提前准备联合朋友去对抗敌人,让事情向你所希望的方向发展。没有永远的朋友,也没有永远的敌人,只有一致的利益,这句话作为项目经理是一定要记住的;

3.基本了解了客户的情况后,下面的事情就是了解自己公司各方面对这个项目的看法。首先是高层领导是否重视,这个决定了你在需要资源的时候,公司是否会根据你的要求提供最有力的支持。领导口头肯定是说支持的,你需要做的是了解公司对这个项目的实际期望,是想把项目越做越大还是想赚钱?是想做样板工程还是干脆想敷衍了事,公司领导对项目的态度决定了你做这个项目的战略,而这个战略方针将对你做项目计划产生直接的影响;
  
4.在做整体项目计划前,还要大致计算一下你手上的资源。首先是时间,现在市场竞争激烈,往往很多项目要求在几乎不可能的时间范围里完成。对于这一点,你在做项目的风险控制计划的时候要充分考虑。其次是人员,根据项目预算和已往经验,大致计算一下未来的项目小组有多少种角色,每个角色目前公司是否有人,是否能完全归这个项目使用,是否需要另外招聘一些人员,招聘的准备工作要尽早启动。最后就是一些设备的准备,项目所需大件关键设备要尽早预定,以后不管发生设备等人还是人等设备的情况,浪费的都是你的时间;

5.现在是做项目说明书的时候了。一份好的项目说明书不仅将要做的事情描述得很清楚(主要是讲做什么,而不是说怎么做),而且把如何检查也说明得很透彻。也就是说它不仅说明白了要做哪些事情,也让客户的业务人员(一般不懂技术)知道项目做成什么样就算完成了。简单地说,项目说明书描述项目做哪些事情和每件事情做到什么程度以及如何检查每一个结果。
  
6. 是到做总体计划的时间了吗?不,你现在已经知道了客户的目标和你手上的资源,那么做计划以前,你还需要和你的经理和客户充分沟通资源的问题。因为很多资源是还不明确的,你需要写一份报告,详细分析这个项目的风险以及对资源的需求情况。如果一些问题不能得到解决的话,将发生什么样的后果。如果资源不够,就要高层改变策略,增加对这个项目的投入。甚至在条件许可的情况下,有些公司会放弃这个项目。总之,没有人能完成一个不可能完成的任务,如果项目经理不能尽早发现风险,那么就只能去当烈士了。

7.明白了要做哪些事情和你手上的筹码以及你做这个项目的总体策略,现在是成立项目小组的时候了。很多项目经理都没有自己选择组员的权利,那么,就尽量发挥你的影响力去寻找那些你想要的人吧。成员的组成根据项目不同,相差较大,很难有什么具体要求,但是,一定要有精通客户业务的人,很多小项目里,这个人就是项目经理本人,大项目里会配备行业专家(Industry expert),这样和客户沟通起来才不会鸡同鸭讲,双方才可以相互理解。我经常看到的情况是我们的技术人员和客户交谈时满口的专业术语,结果搞得客户一头雾水,反过来,他还指责客户不懂技术。其实,明白自己想做什么的客户已经是很好的客户了,不知道自己要做什么,更不懂怎么做还要指手画脚的客户到处存在,但是要明白,是客户选择了你,而不是你选择了客户,有了客户你才有工资拿,心平气和一点吧。

对于这种需求天天变的客户,你就一定要事先做好规矩:
  一、统一联系人,客户指定一个人和项目组进行沟通,不能张领导、王领导都来说几句,如果他们意见不一致,那你只有得罪领导的选择了,所以,项目的最初就要定好规矩,我项目组只认一个的意见,有什么要求你们内部先统一再和我谈,我不想卷入你们内部业务部门之间的矛盾之中;
  二、所有需求变更全部要有书面文字,这点切记!这样做好处多多:
  *有书面证据,以后他还想改,你有了他以前要求的证据,告诉他:你以前可是这么说的;
  *便于需求变更管理,需求如何慢慢演变的历史可以看清楚,从而更深切地体会客户的目的;
  *对于客户来说,嘴巴一动最方便,反正是你们做,不花他的资源,所以要求是否合理,是否和项目的目的一致,他是不负责任的。但是如果要他写书面要求,还要签字盖章,他就要谨慎多了,而且一写东西,思想就会更加深入,很多无理要求也就这样胎死腹中了;

8.现在你要面对三群人:你的领导、你的组员和你的客户,和这些人沟通,让他们知道你打算怎么做,什么时候要他们做什么准备这些事情将是你的主要工作。既然沟通这么重要,那些事先定义一下沟通的原则也是一件很要紧的事情。很多沟通原则都是潜规则,如果你在一个部门时间做长了,对这些规则的运用觉得是一件理所应当的事情,但是,你现在面对的是多个部门甚至多个单位,不把沟通规则说清楚,你以后就会吃亏。下面的东西看起来无聊,其实还是很管用的:第一个是规定信息的流动方式和介质,是推还是拉。推的意思就是项目经理将主动发布信息,不管通过电话、邮件还是书面方式,保证将信息传达到每个人。这种情况适合小项目,人少;拉的意思就是项目经理就是一个类似web服务器,你自己需要什么信息就去问他。当然,没有项目经理把自己搞得那么累,他会用发布信息到公共介质的方式公布信息,简单的是白板,复杂一点的是项目的公共信息交互区,潜规则就是我发了你没去看就不要说我没告诉你。说这些看似很无聊,其实里面牵涉信息传达不完全的责任问题。当然,这些都是指一般的方式,而且不要绝对化,一般情况下,主动沟通和被动访问是同时存在的,尤其是对领导,项目经理更加应该主动去和领导沟通。第二个问题就是文档问题,很多人怕写文档,但是项目经理一定要牢记“好记性不如烂笔头”的道理。有理有时候为什么会说不清呢?就是因为没有证据。所以项目经理开始就要和客户说清楚有些文档是必须签字的,比如项目经理的项目日志,每个星期至少让客户签字,另外所有达成共识的东西,比如会议纪要,甚至领导的讲话记录,都要写成文档,双方签字,这样以后扯皮的时候,就能做到有据可查。记住:说了的就和没说一样,只有写下来大家签字后才算真正发生了的。还有一些问题,比如你提交的报告,给领导(包括本方领导和客户领导)做一个选择题,结果领导压住不批,让你无所适从,结果拖延了进度。这时候,你可以等,但是注意要留记录,标明是谁的责任;另外,如果你在开始阶段就和领导商定:如果批示提交三天后没有得到领导答复就算对方同意,这样你就会主动很多。再比如不同事件的审批流程问题:什么等级的事情记录在项目日志里、什么等级的事情要双方项目经理专门签署备忘录、什么等级的事情要双方领导出面签署合同附件等等。事先想得越周到,以后的工作就越主动。

9.好了,做了很多前期工作,定义了一些游戏规则,现在是坐下来做计划的时候了。这一节,任意找一本项目管理的书都会说得比我好,所以我就少写一点,说一些自己的体会就是了。首先是找几个关键组员,比如客户业务专家、系统分析员等等,做一下项目模块划分工作。项目分成几块去做,每一块完成什么,模块之间的信息如何交换等等。需求定义的是做什么的问题,而这里说的是怎么做的问题。这里要强调一点:完成一个目标有很多种方式,你要选一种你最熟悉的,而不是看上去最完美的,这个思路会让你的项目减少很多风险。有时候客户会被某种新技术打动,坚持要你采用那种新技术,你就应该告诉他:你选我做这个项目,就应该容许我采用自己最喜欢的方式做事情,新技术之所以有诱惑力,就是因为吃亏的人还不多,我不希望你成为第一批受害者。采用一个计划会让你的工作更加明确,比如用微软的Project软件,你填写完表格以后,就可以知道这个项目有多少件事情要做,每件事情需要什么资源,他们之间的前后关系如何,消耗的时间有多长,完成后有什么标志等。所有的结果最后用一个叫做干特图的形式表现出来。你做完这个表以后会惊奇地发现,干特图上项目的结束时间会远远落后于你的计划结束时间(签合同的人永远不会先征求你的意见的)。当然,学过项目管理的人会大谈什么WBS、优化路径之类的东西,但是我的经验是你再优化也不可能把这些东西安排到计划的时间结束。如果你没碰到这个问题,在我恭喜你挑了一个轻松活之前,请你再去确认你是否罗列了所有要做的事情和正确评估了他们所需要的时间。这时候,你就要考虑牺牲一些任务的时间(也意味着质量)了。按照什么标准牺牲?这个项目的战略!我们在第三节提到过的战略。我的经验是如果你什么都赶进度,其结果可能就是十件事情你一件也没做好,想想多么失败啊。所以,把资源投到你熟悉和有把握的事情上,最后的结果是十件事情,你有三件做成了精品,三件完成,还有四件因为某些原因延误,成绩单是否靓丽了很多呢?战略决定优先级,而正确排列事情的优先级是一个项目经理能力的主要体现。

好,现在项目已经完成了前期工作,了解了项目的目标、搞清楚了手上的资源,制定了项目的策略,然后编制了项目的整体计划,项目进入实施阶段。进入这个阶段反而是项目经理比较空闲的时候,不像前期的时候项目经理要象记者一样到处和不同的人接触,搞清楚他们在说什么,努力猜测他们在想什么和他们的真正目的,那才是最累人的事情。当然,小项目的项目经理往往自己也是一个资源,要做很多事情,这时候反而比谁都苦。项目经理这段时间的主要工作是保持和客户领导以及自己领导的沟通。和客户领导沟通时特别要注意,除非你需要对方给你支持,那么你才需要讲得具体一点,否则,告诉他一切正常就可以了,而且态度要积极一些,千万不要说一些领导不懂的细节,比如:“王局长,最近项目进度还算正常,就是JVM经常发生一些内存泄漏的情况…”王局长:“(*&$@@”。和自己的领导汇报也要注意这个问题,除非他是一个技术高手,你需要他的技术经验,否则一般就汇报进度是否正常以及有问题时你的对策和打算就可以了,有些需要他支持的地方,比如资源调用需要说详细一点。和组员开会,除了一些项目进度跟踪会议以外,还有很多讨论会,需要大家用头脑风暴方法给出解决问题。与会人员很多都是技术人员,他们的特点是注重细节、缺乏大局观、有点消极悲观、自尊心强(如果总结得不对,欢迎大家拍砖),所以,你作为会议的主持人,只要负责提出问题和记录下他们的观点,千万不要做评判者的角色。一个问题,有很多方面,从不同的角度看,现象是完全不同的,想想盲人摸象的故事吧。这些技术人员,他们往往精通一个方面,就自己的角度发表见解,除非一些很特别的情况,你都应该认为,他们提出的方案,从他们的角度来看是最合理的。你的长处是掌握事情的优先级,评估各个方面的轻重缓急,从而根据他们的意见得出一个合适的(而不是正确的)方案。所以,在会议上,你要充分尊重每一个人和他的意见,夸奖那些意见提得比较好的人,千万不要把会议带入无休止的争论(你要让大家知道事情不是非黑即白的,而是多元的,唉,我们的教育惹的祸…)。会后,你自己写文档,做决定。会议上大家的面子都被照顾了,自己实施起来的阻力就小,如果还有意见的,你就私下找他聊,如果还不能说服他,你就要让他明白,因为你负责这个项目、你担当风险,所以,这个优先级应该你来判断。组织中的高层,并不见得水平会比一般的成员高,但是,他要承担组织的风险,加之信息的不对称性,所以,对事情的优先级的判断肯定比下属强。

在开发过程中,内部管理还要注意的一点是时刻强调以验收为目的的思想,每个任务的最终可交付成果一定要是可以被检查的,比如,【界面要求:美观大方、简洁明快】,这个要求我就不知道如何检查。所以,给开发小组布置任务的时候就要考虑如何检查结果,比如我见过一个计划,里面有一个任务【开发人员熟悉EJB编程】,这个任务,除了让这些人去参加一些专业认证考试,否则,结果很难被检查。所以,时刻考虑如何检查结果、如何向客户交付是项目经理一直要注意的事情,我听说有些老项目经理拿到项目是倒排计划的,即首先看如何验收和验收标准,然后决定工作计划。很多项目开始了很久,还不知道如何验收,那么这个项目出问题的可能性就很大了。做项目就是为了验收,我们的角色不是研究机构,我们的目的就是在付出那么多劳动后得到结果。
  
   另外我插一句:我是极其不主张到客户现场开发的。尤其是一大群技术人员直接和客户交流,很容易引起冲突和矛盾(技术人员的本性决定的)。我的做法是项目经理和项目实施人员到现场,软件开发人员还是在公司做项目。项目实施人员就是初级项目经理,他们了解自己的产品,懂得一些客户的业务,关键是在于他们具有良好的沟通能力,俗称“皮厚”。他们是客户和研发人员的桥梁,其职业方向也是很机动灵活,以后可以有很多方向可以转,比开发人员的路要宽得多。

接着,我们再谈谈最让人头痛的需求变更问题。变更通常分为两种:一种是部分更改了原先的目标,即需求变更;另一种是没改变目标,但是客户不满意目前的实现方式,大到流程的实现,小到界面的布局,都是属于这类。碰到这种情况是难以避免的,主要是事先沟通的不够充分和客户随着项目的进展,慢慢想清楚了问题,改变了以前的思路。这时候,如果需要改并且你的战略是容许这种情况的,那么注意下面几点:
  
  1. 确保以前的文档,就是记载着以前的结论的东西,客户是否签过字,如果没有,赶紧把你的工作停下来,赶快再和客户自己确认一下你的方案,然后让他签字,避免以后说话没有凭据;
  
  2. 和客户坐下来,自己探讨他修改的根本目的是什么,是不是有同样能达到相同目的,但是对你来说有代价更小的选择?
  
  3. (项目初期的工作)明确更改流程,一般是客户指定一人签字(否则客户每个领导都有权力来插一杠子,你就废了),以正式项目文件的方式提交给你,然后,你做评估分析,分析对成本、进度的影响,在你的领导同意后,出相应意见书,主要是要说明更改设计的原因和指出由此带来的不确定后果(这个东西先写出来,后面如果真的发生了,至少不是你的错)。然后再让客户在上面签字。见过医院给病人做手术以前让家人签的免责条款吗?对,就学习那个,让大家都意识到任何的更改都有成本和代价。
系统开发告一段落后,就进入客户培训、系统验收阶段,这个阶段,我一般会注意以下几个问题:
  
  一、给客户做培训前,多注意一些表面功夫。很多程序员认为,系统的逻辑核心是否正确是关键,至于界面如何,界面上的用词是否准确,那是无关紧要的问题,而且培训的时候也是信手拈来,想到哪里说到哪里,下面听讲的人不知所云,云山雾罩,培训效果自然可以想象。我的体会是,给客户做培训的版本,如果你在做多次测试以后仍然不能确定逻辑是否合乎要求,那么,你至少要在界面上多花一点功夫。注意每个界面的布局、用词、链接的正确性等等,总之不要让客户看到一些他不该看到的东西。文档方面,准备至少两个文档:用户手册和培训手册。这两个文档的内容很多都是一致的,但是角度完全不同。用户手册往往是站在系统设计者的角度,按照自己的思路,分模块讲解系统的操作和功能;而培训手册,一定要站在客户业务人员的角度,根据每个角色面对不同业务的办理,如何通过使用本系统的一系列功能来实现目标。所以,第一次培训以前,系统界面是否完整正确、培训文档是否完备都是很关键的因素,第一炮打不响,以后就麻烦很多。

作为项目经理,其实脑子里就是几样东西:做哪些事情、做到什么程度、怎么交货、手上的资源以及各个事情的优先级。所谓多快好省那是人类的梦想,这四个方面都是相互矛盾的,属于典型的又要马儿跑,又要马儿不吃草的类型。考虑问题的轻重缓急方面,往往是把快放在第一位,各方领导都会给你最后期限,所以保进度是第一位的;省是第二位的,企业的根本目的是盈利,如果收入不能增加的话,至少费用要控制住;好是第三位的,没办法,谁都想精益求精,但是,没有强大的资源保障,质量只好先牺牲了;最后是多,客户的要求源源不断,如何降低客户的期望值,让他们从理想回到现实也是项目经理的分内工作。
  
  验收前,除了做好文档工作,即可交付成果以外,多花时间搞清楚客户的做事情流程是很重要的事情,这些在前面已经有所提及,这里就不再多说。
  
  我对验收最大的体会就是举证问题。即千万不要让客户这么想:你必须有证据证明你的系统是没问题的。这样你就没戏了,微软那么多天才,做了XP还天天打补丁,要你的程序没问题,既不可能,你也没办法拿出证据。你要让客户明白,所谓验收,就是我按照测试文档的测试用例跑一遍,结果和预期结果一致就应该算通过了,而且还容许有一些小错误留在验收后改正,他可以对测试用例提意见。所以,验收前双方要确认测试计划和测试用例。如果他认为系统不符合要求,那么他应该举证,证明这个系统和最初设计相背离的。所以,参考法律概念,千万不要举证倒置。另外,认为系统完美了才能验收的想法也是错误的,软件开发合同里一定要注明验收以后维护期的费用问题,否则,客户担心一旦验收就得不到你们的支持,自然不配合验收,那么,你这个项目经理就很难交功课了。

posted @ 2008-05-16 15:53 Ansel 阅读(153) | 评论 (1)编辑

2006年8月4日 #

老早我认识的那个猎头mm就找我推荐工作,这次我终于答应去看看.前一天准备了一下算法还有设计模式之类的东东,复习了一遍。

一切准备妥当出发,结果不是他们的总部,原来是他们的外包事业部找人,我寒,既来之则安之。提前10分钟进去,后来都超过当时约定的时间下午一点了终于来了一个人事mm,另外一个哥们也和我一起面试。被她叫进一个小黑屋,然后发给我们每人一套考试题,1小时后交。

我一看题这不是tmd前几天我都复习过的内容吗?
复习充分,没用多久都搞定了,我想如果没有准备1个小时我顶多能做2道,这些内容很少用都是大学时期的东西,如果不准备还真不好弄。

我对面的那个哥们,硬是憋了40分钟左右问我你都会答吗,我说还好。
他说我tm一道都不会,c语言早就忘光了。索性收起卷子,给门口那个保安了:一道都不会答,提前走了!

下午快3点了,人事mm终于找到一个空的屋子,一看是一个更小的小黑屋,让我在这里等。一会儿来了一个哥们,来面我,啥都问,问啥我答啥,能答得就答,不能答得就避重就轻。

最后他看了看我的卷子居然说我链表倒置不对,我说应该是对的,我给你讲一下我的思路。他看样子没什么说的了,因为我的思路比较别致。他心里的思路应该还是重新建一条链表,然后一个一个给搬过去。寒~~~

后来谈了谈工资,加班费的问题以及发展。最后跟我说下次他们主管会继续面试一次,如果搞定就过来。然后就让我走了,自己在那里写评语去了。

唉,这段时间老是有外包公司找我,我去的时候还以为是本部找人呢
既然如此就无所谓了能去则去,不去就拉倒,爱谁谁~~~
 

posted @ 2006-08-04 10:05 Ansel 阅读(362) | 评论 (3)编辑

2006年8月3日 #

 .NET框架垃圾回收机制

    .NET框架包含一个托管堆,所有的.NET语言在分配引用类型对象时都要使用它。像值类型这样的轻量级对象始终分配在栈中,但是所有的类实例和数组都被生成在一个内存池中,这个内存池就是托管堆。

   .NET框架中的垃圾回收器被称为分代的垃圾回收器(Generational Garbage Collector),也就是说被分配的对象划分为3个类别,或称为“代”。分别为012012代对应的托管堆的初始化大小分别是256K2M10M。垃圾回收器在发现改变大小能够提高性能的话,会改变托管堆的大小。例如当应用程序初始化了许多小的对象,并且这些对象会被很快回收的话,垃圾回收器就会将第0代的托管堆变为128K,并且提高回收的频率。如果情况相反,垃圾回收器发现在第0代的托管堆中不能回收很多空间时,就会增加托管堆的大小。在应用程序初始化的之前,所有等级的托管堆都是空的。当对象被初始化的时候,他们会按照初始化的先后顺序被放入第0代的托管堆中。 

    最近被分配内存空间的对象被放置于第0代,因为第0代很小,小到足以放进处理器的二级(L2)缓存,所以第0代能够为我们提供对其中对象的快速存取。经过一轮垃圾回收后,仍然保留在第0代中的对象被移进第1代中,再经过一轮垃圾内存回收后,仍然保留在第1代中的对象则被移进第2代中。第2代包含了生存期较长的对象,这些对象至少经过了两轮回收。

    C#程序为一个对象分配内存时,托管堆几乎可以立即返回新对象所需的内存,托管堆之所以能有这样高效的内存分配性能是由于托管堆较为简单的数据结构。托管堆类似于简单的字节数组,有一个指向第一个可用内存空间的指针。

    在某块被某对象所请求时,上述指针值就会返回给调用函数,而指针会重新调整至指向下一个可用的内存空间。分配一个托管内存块只比递增一个指针的值稍微复杂一点。这也是托管堆所优化的性能之一。在一个不需太多垃圾回收的应用程序中,托管堆的表现会优于传统的堆。

    由于这个线性的内存分配方法的存在,在C#应用程序中同时分配的对象在托管堆上通常会被分配成彼此相邻。着安排和传统的堆内存分配完全不同,传统的堆内存分配是基于内存块大小的。例如,两个同时分配的对象在堆上的位置可能相距很远,从而降低了缓存的性能。因此虽然内存分配很快,但在一些比较重要的程序中,第0代中的可用内存很有可能会彻底被消耗光。记住,第0代小到可以装进L2缓冲区,并且没有被使用的内存不会被自动释放。当第0代中没有可以分配的有效内存时,就会在第0代中触发一轮垃圾回收,在这轮垃圾回收中将删除所有不再被引用的对象,并将当前正在使用中的对象移至第1代。针对第0代的垃圾回收是最常见的回收类型,而且速度很快。在第0代的垃圾内存回收不能有效的请求到充足的内存时,就启动第1代的垃圾内存回收。第2代的垃圾内存回收要作为最后一种手段而使用,当且仅当第1代和第0代的垃圾内存回收不能被提供足够内存时进行。如果各代都进行了垃圾回收后仍没有可用的内存,就会引发一个OutOfMemeryException异常 。

posted @ 2006-08-03 10:25 Ansel 阅读(546) | 评论 (0)编辑

2006年8月1日 #

http://student.zjzk.cn/course_ware/data_structure/web/chazhao/chazhao9.2.2.1.htm

二分法查找

1、二分查找(Binary Search)
     二分查找又称折半查找,它是一种效率较高的查找方法。
     二分查找要求:线性表是有序表,即表中结点按关键字有序,并且要用向量作为表的存储结构。不妨设有序表是递增有序的。

2、二分查找的基本思想
     二分查找的基本思想是:(设R[low..high]是当前的查找区间)
 (1)首先确定该区间的中点位置:
                
 (2)然后将待查的K值与R[mid].key比较:若相等,则查找成功并返回此位置,否则须确定新的查找区间,继续二分查找,具体方法如下:
     ①若R[mid].key>K,则由表的有序性可知R[mid..n].keys均大于K,因此若表中存在关键字等于K的结点,则该结点必定是在位置mid左边的子表R[1..mid-1]中,故新的查找区间是左子表R[1..mid-1]。
     ②类似地,若R[mid].key<K,则要查找的K必在mid的右子表R[mid+1..n]中,即新的查找区间是右子表R[mid+1..n]。下一次查找是针对新的查找区间进行的。
     因此,从初始的查找区间R[1..n]开始,每经过一次与当前查找区间的中点位置上的结点关键字的比较,就可确定查找是否成功,不成功则当前的查找区间就缩小一半。这一过程重复直至找到关键字为K的结点,或者直至当前的查找区间为空(即查找失败)时为止。

3、二分查找算法
    int BinSearch(SeqList R,KeyType K)
      { //在有序表R[1..n]中进行二分查找,成功时返回结点的位置,失败时返回零
        int low=1,high=n,mid; //置当前查找区间上、下界的初值
        while(low<=high){ //当前查找区间R[low..high]非空
          mid=(low+high)/2;
          if(R[mid].key==K) return mid; //查找成功返回
          if(R[mid].kdy>K)
             high=mid-1; //继续在R[low..mid-1]中查找
          else
             low=mid+1; //继续在R[mid+1..high]中查找
         }
        return 0; //当low>high时表示查找区间为空,查找失败
       } //BinSeareh
  二分查找算法亦很容易给出其递归程序【参见练习】

4、 二分查找算法的执行过程
  设算法的输入实例中有序的关键字序列为
    (05,13,19,21,37,56,64,75,80,88,92)
要查找的关键字K分别是21和85。具体查找过程【参见动画演示】

5、二分查找判定树
     二分查找过程可用二叉树来描述:把当前查找区间的中间位置上的结点作为根,左子表和右子表中的结点分别作为根的左子树和右子树。由此得到的二叉树,称为描述二分查找的判定树(Decision Tree)或比较树(Comparison Tree)。
  注意:
     判定树的形态只与表结点个数n相关,而与输入实例中R[1..n].keys的取值无关。
   【例】具有11个结点的有序表可用下图所示的判定树来表示。
  
          

(1)二分查找判定树的组成
  ①圆结点即树中的内部结点。树中圆结点内的数字表示该结点在有序表中的位置。
  ②外部结点:圆结点中的所有空指针均用一个虚拟的方形结点来取代,即外部结点。
  ③树中某结点i与其左(右)孩子连接的左(右)分支上的标记"<"、"("、">"、")"表示:当待查关键字K<R[i].key(K>R[i].key)时,应走左(右)分支到达i的左(右)孩子,将该孩子的关键字进一步和K比较。若相等,则查找过程结束返回,否则继续将K与树中更下一层的结点比较。

(2)二分查找判定树的查找
  二分查找就是将给定值K与二分查找判定树的根结点的关键字进行比较。若相等,成功。否则若小于根结点的关键字,到左子树中查找。若大于根结点的关键字,则到右子树中查找。
  【例】对于有11个结点的表,若查找的结点是表中第6个结点,则只需进行一次比较;若查找的结点是表中第3或第9个结点,则需进行二次比较;找第1,4,7,10个结点需要比较三次;找到第2,5,8,11个结点需要比较四次。
     由此可见,成功的二分查找过程恰好是走了一条从判定树的根到被查结点的路径,经历比较的关键字次数恰为该结点在树中的层数。若查找失败,则其比较过程是经历了一条从判定树根到某个外部结点的路径,所需的关键字比较次数是该路径上内部结点的总数。
    【例】待查表的关键字序列为:(05,13,19,21,37,56,64,75,80,88,92),若要查找K=85的记录,所经过的内部结点为6、9、10,最后到达方形结点"9-10",其比较次数为3。
     实际上方形结点中"i-i+1"的含意为被查找值K是介于R[i].key和R[i+1].key之间的,即R[i].key<K<R[i+1].key。

(3)二分查找的平均查找长度
      设内部结点的总数为n=2h-1,则判定树是深度为h=lg(n+1)的满二叉树(深度h不计外部结点)。树中第k层上的结点个数为2k-1,查找它们所需的比较次数是k。因此在等概率假设下,二分查找成功时的平均查找长度为:
           ASLbn≈lg(n+1)-1
  二分查找在查找失败时所需比较的关键字个数不超过判定树的深度,在最坏情况下查找成功的比较次数也不超过判定树的深度。即为:
          
  二分查找的最坏性能和平均性能相当接近。

6、二分查找的优点和缺点
  虽然二分查找的效率高,但是要将表按关键字排序。而排序本身是一种很费时的运算。既使采用高效率的排序方法也要花费O(nlgn)的时间。
  二分查找只适用顺序存储结构。为保持表的有序性,在顺序结构里插入和删除都必须移动大量的结点。因此,二分查找特别适用于那种一经建立就很少改动、而又经常需要查找的线性表。
  对那些查找少而又经常需要改动的线性表,可采用链表作存储结构,进行顺序查找。链表上无法实现二分查找。

二分法排序

#include <stdlib.h>
#include <stdio.h>
void TwoInsertSort(int array[],int n)
{
      int left,right,num;
      int middle,j,i;
      for(i = 1;i < n;i++)
      {
          left = 0;// 准备
          right = i-1;
          num = array[i];        
          while( right >= left)// 二分法查找插入位置
          {
              middle = ( left + right ) / 2; // 指向已排序好的中间位置
              if( num < array[middle] )// 即将插入的元素应当在在左区间
      right = middle-1;
     else                    // 即将插入的元素应当在右区间
      left = middle+1;   
          }
          for( j = i-1;j >= left;j-- )// 后移排序码大于R[i]的记录
              array[j+1] = array[j];
          array[left] = num;// 插入
      }
}

int rcmp( const int *a, const int *b)
{
 return (*a-*b);
}
void main()
{
 int array[50];
 int i;
 printf("The original array is :\n");
 for( i=0; i<50; i++ )//数组初始化并显示
 {
  array[i] = 50-i;
  printf("array[%d]:%d\n", i, array[i]);
 }
 TwoInsertSort(array,sizeof(array)/sizeof(int));//二分法排序
 printf("\nAfter sorted :\n");
 for( i=0; i<50; i++ )
  printf("array[%d]:%d\n", i, array[i]);

//库函数bsearch用二分法查找一个有序数组中的一个特定数,并返回该数的地址

 a = (int *)bsearch(&b, numarray, sizeof(numarray)/sizeof(numarray[0]), sizeof(int),rcmp);

}


posted @ 2006-08-01 15:18 Ansel 阅读(1293) | 评论 (1)编辑

2005年11月28日 #


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<!-- 动态调试编译
设置 compilation debug="true" 以启用 ASPX 调试。否则,将此值设置为
false 将提高此应用程序的运行时性能。
设置 compilation debug="true" 以将调试符号(.pdb 信息)
插入到编译页中。因为这将创建执行起来
较慢的大文件,所以应该只在调试时将此值设置为 true,而在所有其他时候都设置为
false。有关更多信息,请参考有关
调试 ASP.NET 文件的文档。
-->
<compilation
defaultLanguage="c#"
debug="true"
/>
<!-- 自定义错误信息
设置 customErrors mode="On" 或 "RemoteOnly" 以启用自定义错误信息,或设置为 "Off" 以禁用自定义错误信息。
为每个要处理的错误添加 <error> 标记。
"On" 始终显示自定义(友好的)信息。
"Off" 始终显示详细的 ASP.NET 错误信息。
"RemoteOnly" 只对不在本地 Web 服务器上运行的
用户显示自定义(友好的)信息。出于安全目的,建议使用此设置,以便
不向远程客户端显示应用程序的详细信息。
-->
<customErrors
mode="RemoteOnly"
/>
<!-- 身份验证
此节设置应用程序的身份验证策略。可能的模式是 "Windows"、
"Forms"、 "Passport" 和 "None"
"None" 不执行身份验证。
"Windows" IIS 根据应用程序的设置执行身份验证
(基本、简要或集成 Windows)。在 IIS 中必须禁用匿名访问。
"Forms" 您为用户提供一个输入凭据的自定义窗体(Web 页),然后
在您的应用程序中验证他们的身份。用户凭据标记存储在 Cookie 中。
"Passport" 身份验证是通过 Microsoft 的集中身份验证服务执行的,
它为成员站点提供单独登录和核心配置文件服务。
-->
<authentication mode="Windows" />
<!-- 授权
此节设置应用程序的授权策略。可以允许或拒绝不同的用户或角色访问
应用程序资源。通配符: "*" 表示任何人,"?" 表示匿名
(未经身份验证的)用户。
-->
<authorization>
<allow users="*" /> <!-- 允许所有用户 -->
<!-- <allow users="[逗号分隔的用户列表]"
roles="[逗号分隔的角色列表]"/>
<deny users="[逗号分隔的用户列表]"
roles="[逗号分隔的角色列表]"/>
-->
</authorization>
<!-- 应用程序级别跟踪记录
应用程序级别跟踪为应用程序中的每一页启用跟踪日志输出。
设置 trace enabled="true" 可以启用应用程序跟踪记录。如果 pageOutput="true",则
在每一页的底部显示跟踪信息。否则,可以通过浏览 Web 应用程序
根目录中的 "trace.axd" 页来查看
应用程序跟踪日志。
-->
<trace
enabled="false"
requestLimit="10"
pageOutput="false"
traceMode="SortByTime"
localOnly="true"
/>
<!-- 会话状态设置
默认情况下,ASP.NET 使用 Cookie 来标识哪些请求属于特定的会话。
如果 Cookie 不可用,则可以通过将会话标识符添加到 URL 来跟踪会话。
若要禁用 Cookie,请设置 sessionState cookieless="true"。
-->
<sessionState
mode="InProc"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"
cookieless="false"
timeout="20"
/>
<!-- 全球化
此节设置应用程序的全球化设置。
-->
<globalization
requestEncoding="utf-8"
responseEncoding="utf-8"
/>

</system.web>
</configuration>

连接数据库的语句应该在哪个地方插入的?
我找了很就了,找不到,测试通不过啊
测试通过马上结贴,刷新中.....
请赐教,都拷贝上来吧,谢谢

 1<?xml version="1.0" encoding="utf-8" ?>
 2<configuration>
 3
 4<appSettings>
 5<add key="dsn" value="server=localhost;uid=netfriend;password=19771231;database=cnpg_news" />
 6<add key="dsn1" value="server=localhost;database=cnpg_news;Trusted_Connection=no;user id=netfriend;pwd=19771231;" />
 7</appSettings>
 8<system.web> 
 9<compilation defaultLanguage="C#" debug="true"/>
10<identity impersonate="true" userName="administrator" password="197869"/>
11<pages validateRequest="false" />
12<customErrors mode="Off" />
13<globalization fileEncoding="gb2312" requestEncoding="gb2312" responseEncoding="gb2312" />
14<httpRuntime maxRequestLength="5655648" />
15<authentication mode="Windows" /> 
16<sessionState mode="InProc" cookieless="true" timeout="80"/>
17<trace enabled="true"/>
18
19</system.web>
20</configuration>
posted @ 2005-11-28 15:40 Ansel 阅读(433) | 评论 (0)编辑

简介


 


         MSMQ(微软消息队列)是Windows操作系统中消息应用程序的基础,是用于创建分布式、松散连接的消息通讯应用程序的开发工具。消息队列和电子邮件有着很多相似处,他们都包含多个属性,用于保存消息,消息类型中都指出发送者和接收者的地址;然而他们的用处却有着很大的区别:消息队列的发送者和接收者是应用程序,而电子邮件的发送者和接收者通常是人。


 


如同电子邮件一样,消息队列的发送和接收也不需要发送者和接收者同时在场,可以存储在消息队列或是邮件服务器中。因此,我们可以用下图来描述MSMQ应用程序的体系结构:



         从上图可以看出,开发MSMQ应用程序并不是十分困难的事情。不过要使用MSMQ开发你的消息处理程序,必须在开发系统和使用程序的主机上安装消息队列。消息队列的安装属于Windows组件的安装,和一般的组件安装方法类似。安装好消息队列后,就可以开发你自己的消息处理程序了。不过有一点需要注意,如果你的计算机处于工作组中,而不是某个域中,可能你的公用队列不能使用,不过这并不影响你的程序开发。


 


         消息处理程序不外乎消息的发送和接收,然而要收发消息,还必须引用一个队列,通常我们引用公用队列和专用队列,这两个队列都存放用户生成的消息。引用队列后,就可以发送、接收和阅读消息了。消息接收服务位于System.Messaging中,如果你找不到这一命名空间,你必须手动添加。点击[项目]中的[添加引用],按下浏览按钮,找到System.Messaging.dll文件,添加进来即可。


 


引用队列


 


         引用队列有三种方法,通过路径、格式名和标签引用队列,这里我只介绍最简单和最常用的方法:通过路径应用队列。队列路径的形式为 machinenamequeuename。指向队列的路径总是唯一的。下表列出用于每种类型的队列的路径信息:

  

















队列类型


路径中使用的语法


公共队列


MachineNameQueueName


专用队列


MachineNamePrivate$QueueName


日志队列


MachineNameQueueNameJournal$


        


如果是发送到本机上,还可以使用”.”代表本机名称。具体的引用方法通过Path属性来进行,也可以在初始化消息队列时进行。


 


如果在初始化时引用消息队列,那么消息队列必须存在于系统中,否则会产生中断。往系统中添加队列十分的简单,打开[控制面板]中的[计算机管理],展开[服务和应用程序],找到并展开[消息队列](如果找不到,说明你还没有安装消息队列),右击希望添加的消息队列的类别,选择新建队列即可。当然,在程序中也可以实现消息队列的创建,下文会有相应的说明。在初始化时引用消息队列的代码很简单,如下所示:


 


MessageQueue Mq=new MessageQueue(“.\private$\jiang”)


通过Path属性引用消息队列的代码也十分简单:


MessageQueue Mq=new MessageQueue()


Mq.Path=”.\private$\jiang”;


使用 Create 方法可以在计算机上创建队列:


System.Messaging.MessageQueue.Create(@".private$jiang");


 


发送消息


 


         队列引用过后,就可以发送消息了。消息的发送可以分为简单消息和复杂消息,简单消息类型就是常用的数据类型,例如整型、字符串等数据;复杂消息的数据类型通常对应于系统中的复杂数据类型,例如结构,对象等等。


 


         简单消息的发送示例如下:


         Mq.Send(1000); //发送整型数据


         Mq.Send(“This is a test message!”); //发送字符串


 


         复杂消息的发送和简单消息的发送大同小异,只是发送时,通常不是直接给出发送的消息内容,而是代表发送消息内容的变量。下面的代码分别通过消息变量和复杂数据类型变量发送一条复杂消息。


 


         //下面的代码中发送的消息由消息变量表示


         Message Msg;


         Msg=new Message(“A Complex Message!”);


         Msg.Label=”This is the label”;


         Msg.Priority=MessagePriority.High;


         Mq.Send(Msg);


 


         //下面的代码中发送的消息由复杂数据类型变量表示,Customer为自定义的一个类

          Customer customer = new Customer();

    customer.LastName = "Copernicus";


    customer.FirstName = "Nicolaus";       


Mq.Send(customer);


 


接收消息


 


       接收消息相比发送消息要复杂一点。接收消息由两种方式:通过Receive方法接收消息同时永久性地从队列中删除消息;通过Peek方法从队列中取出消息而不从队列中移除该消息。如果知道消息的标识符(ID),还可以通过ReceiveById方法和PeekById方法完成相应的操作。


 


         接收消息的代码很简单:


         Mq.Receive(); //Mq.ReceiveById(ID);


         Mq.Peek();  // Mq.PeekById(ID);


 


阅读消息


 


         接收到的消息只有能够读出来才是有用的消息,因此接收到消息以后还必须能读出消息,而读出消息算是最复杂的一部操作了。在应用程序能够阅读的消息和消息队列中的消息格式不同,因而应用程序发送出去的消息经过序列化以后才发送给了消息队列,这一过程由系统自动完成了,程序开发人员不必为此编写代码,然而在接收到消息后就面临着消息序列化的问题。


 


         消息的序列化可以通过Visual Studio .NET Framework 附带的三个预定义的格式化程序来完成:XMLMessageFormatter 对象( MessageQueue 组件的默认格式化程序设置)、BinaryMessageFormatter 对象、ActiveXMessageFormatter 对象。由于后两者格式化后的消息通常不能为人阅读,所以我们经常用到的是XMLMessageFormatter对象。


 


         使用XMLMessageFormatter对象格式化消息的代码如下所示:

          string[] types = { "System.String" };

       ((XmlMessageFormatter)mq.Formatter).TargetTypeNames = types;

              Message m=mq.Receive(new TimeSpan(0,0,3));
       将接收到的消息传送给消息变量以后,通过消息变量mBody属性就可以读出消息了:
       MessageBox.Show((string)m.Body);
posted @ 2005-11-28 14:22 Ansel 阅读(740) | 评论 (1)编辑

2005年9月8日 #

在数据库访问时。如果处理并发访问的问题
或者当一个操作员对一个对象作读操作时。另一个操作员对此对象作写操作的时候
如何避免死锁发生
/**********  加锁   ***************
设table1(A,B,C)
A    B    C
a1   b1   c1
a2   b2   c2
a3   b3   c3

1)排它锁
新建两个连接
在第一个连接中执行以下语句
begin tran
   update table1
   set A='aa'
   where B='b2'
   waitfor delay '00:00:30'  --等待30秒
commit tran
在第二个连接中执行以下语句
begin tran
   select * from table1
   where B='b2'
commit tran

若同时执行上述两个语句,则select查询必须等待update执行完毕才能执行即要等待30秒

2)共享锁
在第一个连接中执行以下语句
begin tran
   select * from table1 holdlock -holdlock人为加锁
   where B='b2'
   waitfor delay '00:00:30'  --等待30秒
commit tran

在第二个连接中执行以下语句
begin tran
   select A,C from table1
   where B='b2'
   update table1
   set A='aa'
   where B='b2'
commit tran

若同时执行上述两个语句,则第二个连接中的select查询可以执行
而update必须等待第一个连接中的共享锁结束后才能执行 即要等待30秒

3)死锁
增设table2(D,E)
D    E
d1   e1
d2   e2
在第一个连接中执行以下语句
begin tran
   update table1
   set A='aa'
   where B='b2'
   waitfor  delay '00:00:30'
   update table2
   set D='d5'
   where E='e1'
commit tran

在第二个连接中执行以下语句
begin tran
   update table2
   set D='d5'
   where E='e1'
   waitfor  delay '00:00:10'
   update table1
   set A='aa'
   where B='b2'
commit tran

同时执行,系统会检测出死锁,并中止进程
--------------------------------------------------------------
SET IMPLICIT_TRANSACTIONS  ON --用户每次必须显式提交或回滚。否则当用户断开连接时,
                              --事务及其所包含的所有数据更改将回滚

SET IMPLICIT_TRANSACTIONS  OFF --自动提交模式。在自动提交模式下,如果各个语句成功
                               --完成则提交。




1:如上

2: 如何锁一个表的某一行


A 连接中执行

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

begin tran

select * from tablename with (rowlock) where id=3

waitfor delay '00:00:05'

commit tran

B连接中如果执行

update tablename set colname='10' where id=3 --则要等待5秒

update tablename set colname='10' where id<>3 --可立即执行

2 锁定数据库的一个表

SELECT * FROM table WITH (HOLDLOCK)


注意: 锁定数据库的一个表的区别

SELECT * FROM table WITH (HOLDLOCK)
其他事务可以读取表,但不能更新删除

SELECT * FROM table WITH (TABLOCKX)
其他事务不能读取表,更新和删除


SELECT 语句中“加锁选项”的功能说明
  SQL Server提供了强大而完备的锁机制来帮助实现数据库系统的并发性和高性能。用户既能使用SQL Server的缺省设置也可以在select 语句中使用“加锁选项”来实现预期的效果。 本文介绍了SELECT语句中的各项“加锁选项”以及相应的功能说明。
  功能说明: 
  NOLOCK(不加锁)
  此选项被选中时,SQL Server 在读取或修改数据时不加任何锁。 在这种情况下,用户有可能读取到未完成事务(Uncommited Transaction)或回滚(Roll Back)中的数据, 即所谓的“脏数据”。

  HOLDLOCK(保持锁)
  此选项被选中时,SQL Server 会将此共享锁保持至整个事务结束,而不会在途中释放。

  UPDLOCK(修改锁)
  此选项被选中时,SQL Server 在读取数据时使用修改锁来代替共享锁,并将此锁保持至整个事务或命令结束。使用此选项能够保证多个进程能同时读取数据但只有该进程能修改数据。

  TABLOCK(表锁)
  此选项被选中时,SQL Server 将在整个表上置共享锁直至该命令结束。 这个选项保证其他进程只能读取而不能修改数据。

  PAGLOCK(页锁)
  此选项为默认选项, 当被选中时,SQL Server 使用共享页锁。

  TABLOCKX(排它表锁)
  此选项被选中时,SQL Server 将在整个表上置排它锁直至该命令或事务结束。这将防止其他进程读取或修改表中的数据。


--或者自己加锁(控制更灵活)

--锁定记录,只允许单用户修改的例子:

--创建测试环境
--创建测试表--部门表
create table 部门(departmentid int,name varchar(10))

--记录锁定表
create table lock(departmentid int,dt datetime)

go
--因为函数中不可以用getdate,所以用个视图,得到当前时间
create view v_getdate as select dt=getdate()
go
--创建自定义函数,判断记录是否锁定
create function f_chk(@departmentid int)
returns bit
as
begin
declare @re bit,@dt datetime
select @dt=dt from v_getdate
if exists(select 1 from lock where departmentid=@departmentid
and datediff(ss,dt,@dt)<5)
set @re=1
else
set @re=0
return(@re)
end
go

--数据处理测试
if dbo.f_chk(3)=1
print '记录被锁定'
else
begin
--也可以是查询
begin tran
insert into lock values(3,getdate())
update 部门 set name='A' where departmentid=3
delete from lock where departmentid=3
commit tran
end

--删除测试环境
drop table 部门
drop view v_getdate
drop function f_chk

如果是死锁可以查一下:
1:sp_who 或 sp_who2
2: Select * from sysprocesses where blocked <> 0
3: 企业管理器->服务器->管理工具->活动->当前活动 然后把他kill掉。。。
   进程信息中,如果发现旁边有一个锁状的图标,就表明这个进程是死锁,kill掉
4:SQL事件探查器,监控一下,看主要是那些处理引起的死锁.然后做相应的处理.
用事件探查器new一个trace,监视一下造成你sqlserver停顿的情况。。。

最好的办法还是检查一下引起锁的原因,一般是由你的代码引起的。

经过根踪调试。我发现问题如下:
1。当一个操作对一张表进行读操作的时候。这时如果另一个表进行读操作没有问题。如果
另一个操作对这个表进行写操作的时候。就会出现这样的情况。在单击保存时。会持续等。
只有另一个读操作的程序。退出读表的界面。这个就会保存成功。
2。如果把同样的环境改到我的笔记本上没有这个问题。如果再放到IBM服务器上就会出现上述所讲的问题。

现有疑问如下:
1。为何笔记本做服务(P41。8CPU。256M)没有问题。面用IBM做服务器有问题?
2。如果我把SQLCA。AUTOCOMMIT=FALSE改为SQLCA。AUTOCOMMIT=TRUE。这个问题就不存在了。但是我想这只是从表面上解决了这个问题。没有从根上解决这个问题。
3。如果是多个工作站。一台用SQLCA。AUTOCOMMIT=TRUE,另一台AUTOCOMMIT=FALSE会有问题吗。?如果我想进行ROLLBACK操作会有问题吗?
4。如果在同一个网段上有两个SQLSERVER2000服务器会有影响吗?

posted @ 2005-09-08 12:01 Ansel 阅读(1084) | 评论 (0)编辑

2005年9月7日 #

It's very nice to have talked with you via phone just now, the person I am looking for should have much more experiences in
the field of training, according to the prospective clients' needs, he or she need to customized what prospective clients'
requirements, especially quite familiar with training program which focus on HR and leadership.
I need your personal help.
posted @ 2005-09-07 15:35 Ansel 阅读(383) | 评论 (0)编辑