qileilove

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

论如何进行有效的需求管理

 论文摘要:
  本文主要讨论如何更有效的进行需求管理,需求管理中需求考虑的一些问题,项目中事先识别的风险和没有预料到而发生的变更等风险的应对措施的分析,也包括项目中发生的变更和项目中发生问题的分析统计,以及需求管理中的一些应对措施。
  关键字:
  需求管理, 业务建模、项目管理、数据流图
  通过高级项目经理5天课程的培训,个人感觉对于原先的工作实践有了一个很好的指导,从原先的实践上升了一个层次,对于实践有了一个很好的理论指导。
  我想很多人可能会与我同感,一个项目做了很久,感觉总是做不完,就像一个“无底洞”。你想加人尽快完成这个项目,而用户总是有新的需求要项目开发方来做,就像用户是一个不知廉耻的要求者,而开发方是在苦苦接收的接受者。实际上,这里涉及到一个需求管理的概念。项目中哪些该做,哪些不该做,做到什么程度,都是由需求管理来决定的。那么,到底什么是需求管理,从这几天的学习中,我从理论上对此问题做了一个分析,表达一些自已的想法。
  影响项目的最后成功的因素是多方面的,包括项目管理的九大知识领域(包括项目的整体管理、范围管理、时间管理、费用管理、质量管理、沟通管理、成本管理、人力资源管理、采购管理)。然而,要这九大知识领域对项目成功产生的影响的轻重程度上进行比较的话,我个人认为其中项目范围管理中的需求管理是最为重要的。本文主要讲述范围管理中的需求管理部分。
  需求管理是软件项目中一项十分重要的工作,据调查显示在众多失败的软件项目中,由于需求原因导致的约占了很大的一部分,本人从事的工作经历中有好2次就是因为需求不明确,导致最终的系统不可控,项目陷入困境。因此,需求工作将对软件项目能否最终实现产生至关重要的影响。虽然如此,在项目开发工作中,很多人对需求的认识还远远不够,从本人参与或接触到的一些项目来看,小到几万元,大到上千万元的软件项目的需求都或多多少的存在问题。
  有的是开发者本身不重视原因,有的是技术原因、有的是人员组织原因、有的是沟通原因、有的是机制原因,以上种种原因都表明做好软件需求开发是一项系统工作,而不是简单的技术工作,只有系统的了解和掌握需求的基本概念、方法、手段、评估标准、风险等相关知识,并在实践中加以应用,才能真正做好需求的开发和管理工作。在软件项目的开发过程中,需求变更贯穿了软件项目的整个生命周期,从软件的项目立项,研发,维护,用户的经验在增加,对使用软件的感受有变化,以及整个行业的新动态,都为软件带来不断完善功能,优化性能,提高用户友好性的要求。在软件项目管理过程中,项目经理经常面对用户的需求变更。如果不能有效处理这些需求变更,项目计划会一再调整,软件交付日期一再拖延,项目研发人员的士气将越来越低落,将直接导致项目成本增加、质量下降及项目交付日期推后。这决定了项目组必须拥有需求管理策略。
  下面主要针对需求开发及需求管理两个方面对需求进行分析。
  1. 需求开发,从目前我们的实际工作情况来看按顺序主要分成如下几个部分:
  请教行业专家
  行业客户对信息化的需求越来越细化,对专业性以及行业能力的全面性要求越来越高,惟有深入行业,洞察其需求,研发出更适合客户需求的产品,才能成功。因此有必要先请这方面的行业专家对于客户的业务需求进行从流程上的梳理。为什么请行业专家,而不是直接请客户进行交谈,得到其实需求,个人认为主要是因为目前各政府部门、企事业单位对于信息化与业需求的整合这一块缺少经验,大部分情况还不能完全整理出完善、清晰的系统需求来。只有通过行业专家对其实业务流程进行梳理,一方面更容易与客户产生共鸣,另一方面也可以大大减少因为知识方面的差异导致错识需求的产生。
  和客户交谈
  你要面对“正确”的客户区分不同层次的客户需求,要面对不同层级,不同部门的客户,把客户分类,区分需求的优先级别.如果你做的项目业务是你熟悉的,那还好,如果是你不熟悉的,一定要花点精力学习一下这个行业业务的背景资料,这也是我上面谈到的先请行业专家的原因。毕竟,客户是不可能给你系统地介绍业务的。只有你通晓了行业业务,才能和用户交流,并正确而有效地引导客户,做好需求分析,你不能指望客户能明确地说出需求。当然,这也是系统分析人员的职责所在。在开始做需求的时候,你最后花一点时间搞清楚你接触的客户是不是做实际业务的客户,如果你面对的客户不是将来的系统的实际使用者。你就有点麻烦了。可能他是客户公司派过来的IT部的人,他会提一大堆东西,而这些东西可能根本不是实际业务需要的功能,而他一般还会兴致勃勃地给你一些技术实现的建议。这个时候你就要小心了,如果你听了他的话,你可能在最后才发现,你花了大量精力解决的问题,其实并不是客户真正需要的。而你真正需要关注的,却做得远远不够。
 参考其他类似软件和系统
  在经过与客户的沟通,并形成初步的需求之后,不要急成正式的需求,请先参考一下以前的一些系统,去理解一下了解到的需求与原先系统的差异,并去发现是否有些需求会产生错识需求。
  业务建模
  为需求建立模型,需求的图形分析模型是软件需求规格说明极好的补充说明。它们能提供不同的信息与关系以有助于找到不正确的、不一致的、遗漏的和冗余的需求。这样的模型包括数据流图、实体关系图、状态变换图、对话框图、对象类及交互作用图。
  需求整理并形成需求规格说明书
  需求规格说明书的模板我想每家公司都是不一样的,也没有必要都一样,但我认为每个需求规格说明书至少应包括
  软件需求一旦通过了评审,就应该基线化,纳入配置管理库.而在配置管理库中的文档或代码不能再轻易进行修改.当有需求要进行变更的时候,就必须提出申请,写需求变更计划,审核通过,才有权限进行需求变更.然后配置管理员一定要做好需求的跟踪.,凡是跟变更需求有牵连的开发人员和测试人员都要同步的通知到和及时让他们做好相应部分的各类文档的修改。
  需求变更管理
  需求的变更管理我个人认为是最容易出问题,一般项目做不完也主要是由此产生。需求变更的出现主要是因为在项目的需求确定阶段,用户往往不能确切地定义自己需要什么。用户常常以为自己清楚,但实际上他们提出的需求只是依据当前的工作所需,而采用的新设备、新技术通常会改变他们的工作方式;或者要开发的系统对用户来说也是个未知数,他们以前没有过相关的使用经验。随着开发工作的不断进展,系统开始展现功能的雏形,用户对系统的了解也逐步深入。于是,他们可能会想到各种新的功能和特色,或对以前提出的要求进行改动。他们了解得越多,新的要求也就越多,需求变更因此不可避免地一次又一次出现。如何有效的管理需求变更,下面是我公司目前的做法。公司采用Test Director作为需求管理工具,需求人员每次与客户沟通后形成需求调查表,统一录入Test Director,并进行综合及整理后形成需求规格说明书, 之后由研发部、产品部、及销售代表(如果有客户参加就更好了)进行需求评审,建立需求基线。制订简单、有效的变更控制流程,并形成文档。在建立了需求基线后提出的所有变更都必须遵循变更控制流程进行控制,同时每一笔重要的需求变更都需要客户签字确认才认为需求变更生效。需求变更后,受影响的软件计划、产品、活动都要进行相应的变更,以保持和更新的需求一致。因为Test Director提供了需求变更记录,可以帮助我们形成良好的文档,便于进行管理。
  2. 需求管理
  首先要针对需求做出分析,随后应用于产品并提出方案。需求分析的模型正是产品的原型样本,优秀的需求管理提高了这样的可能性:它使最终产品更接近于解决需求,提高了用户对产品的满意度,从而使产品成为真正优质合格的产品。从这层意义上说,需求管理是产品质量的基础。
  需求管理的目的是在客户与开发方之间建立对需求的共同理解,维护需求与其它工作成果的一致性,并控制需求的变更。
  需求确认是指开发方和客户共同对需求文档进行评审,双方对需求达成共识后作出书面承诺,使需求文档具有商业合同效果。
  需求跟踪是指通过比较需求文档与后续工作成果之间的对应关系,建立与维护“需求跟踪矩阵”,确保产品依据需求文档进行开发。
  需求变更控制是指依据“变更申请-审批-更改-重新确认”的流程处理需求的变更,防止需求变更失去控制而导致项目发生混乱。
  根据上面描述的具体方法及步骤,由于需求分析的参与人员、业务模式、投资、时间等客观因素的影响和需求本身具有主观性和可描述性差的特点,因此,需求分析工作往往面临着一些潜在的风险,应引起项目相关干系人的注意。这些风险主要表现如下:
  1)用户不能正确表达自身的需求。在实际开发过程中,常常碰到用户对自己真正的需求并不是十分明确的情况,他们认为计算机是万能的,只要简单的说说自己想干什么就是把需求说明白了,而对业务的规则、工作流程却不愿多谈,也讲不清楚。这种情况往往会增加需求分析工作难度,分析人员需要花费更多的时间和精力与用户交流,帮助他们梳理思路,搞清用户的真实需求。从另一方面来看,他们对于计算机的理解肯定不是很到位,而我们如何引导,正确梳理出正确的需求就需要先从工作业务流程出发,而不是先从计算机方面来考虑问题。
  2)业务人员配合力度不够。有的用户日常工作繁忙,他们不愿意付出更多的时间和精力向分析人员讲解业务,这样会加大分析人员的工作难度和工作量,也可能导致因业务需求不足而使系统无法使用。针对此类问题我们一般的做法是在项目开始阶段先确定好一个与客户沟通过的需求调研计划,当然这样还是经常会有变动,但相对来讲从责任上来讲,客户也会有一定的压力,因为如果不配合可能会导致系统进度的延误,其实这也不是客户希望看到的。
  3)用户需求的不断变更。由于需求识别不全、业务发生变化、需求本身错误、需求不清楚等原因,需求在项目的整个生命周期都可能发生变化,因此,我们要认识到,软件开发的过程实际上是同变化做斗争的过程,需求变化是每个开发人员、项目管理人员都会遇到的问题,也是最头痛的问题,一旦发生了需求变化,就不得不修改设计、重写代码、修改测试用例、调整项目计划等等,需求的变化就像是万恶之源,为项目的正常的进展带来不尽的麻烦。针对这类需求变更的问题,个人认为是影响进度的最大的敌人,目前我们的做法是每次根据客户的需求整理出一个书面的文件,由客户签字确认。当然这里还有一个很重要的问题就是不是每个需求都是必须做的,我们要学习如何拒绝客户。
  4)需求的完整程度。需求如何做到没有遗漏?这是一个大问题,大的系统要想穷举需求几乎是不可能的,即使小的系统,新的需求也总会不时地冒出来。一个系统很难确定明确的范围并把所有需求一次性提出来,这会导致开发人员在项目进展中去不断完善需求,先建立系统结构再完成需求说明,造成返工的可能性很大,会给开发人员带来挫折感,降低他们完成项目的信心。
  5)需求的细化程度。需求到底描述到多细,才算可以结束了?虽然国家标准有需求说明的编写规范,但具体到某一个需求上,很难给出一个具体的指标,可谓仁者见仁,智者见智,并没有定论。需求越细,周期越长,可能的变化越多,对设计的限制越严格,对需求的共性提取要求也越高,相反,需求越粗,开发人员在技术设计时不清楚的地方就越多,影响技术设计。
  6)需求描述的多义性。需求描述的多义性一方面是指不同读者对需求说明产生了不同的理解;另一方面是指同一读者能用不同的方式来解释某个需求说明。多义性会使用户和开发人员等项目参与者产生不同的期望,也会使开发、测试人员为不同的理解而浪费时间,带来不可避免的后果便是返工重做。
  7)忽略了用户的特点分析。分析人员往往容易忽略了系统用户的特点,系统是由不同的人使用其不同的特性,使用频繁程度有所差异,使用者受教育程度和经验水平不尽相同。如果忽略这些的话,将会导致有的用户对产品感到失望。
  8)需求开发的时间保障。为了确保需求的正确性和完整性,项目负责人往往坚持要在需求阶段花费较多的时间,但用户和开发部门的领导却会因为项目迟迟看不到实际成果而焦虑,他们往往会强迫项目尽快往前推进,需求开发人员也会被需求的复杂和善变折腾的筋疲力尽,他们也希望尽快结束需求阶段。


  在实际的工作中,我列了一些需要关注的问题,以避免一些不必要的麻烦。
  1)抓住决策者最迫切和最关心的问题,引起重视。用户方决策者对项目的关心重视程度是项目能否顺利开展的关键,决策者的真实意图也是用户方的最终需求,因此,在开发过程中要利用一切机会了解决策者关心的问题,同时也要让他们了解项目的情况。在诸如谈判、专题汇报、协调会议、领导视察、阶段性成果演示等过程中用简短明确的语言或文字抓住领导最关心的问题,引导他们了解和重视项目的开发,当决策者认识到项目的重要性时,需求分析工作在人力、物力、时间上就有了保障。
  2)建立组织保障,明确的责任分工。项目开发一般都会成立相应的项目组或工程组,目前,常见的组织形式是:产品管理组、质量与测试组、程序开发组、用户代表组和后勤保障组,各组的主要分工是:产品管理组负责确定和设置项目目标,根据需求的优先级确定功能规范,向相关人员通报项目进展。程序管理组负责系统分析,根据软件开发标准协调日常开发工作确保及时交付开发任务,控制项目进度。程序开发组负责按照功能规范要求交付软件系统。质量与测试组负责保证系统符合功能规范的要求,测试工作与开发工作是独立并行的。用户代表组负责代表用户方提出需求,负责软件的用户方测试。后勤保障组负责确保项目顺利进行的后勤保障工作。
  3)建立良好的沟通环境和氛围。分析人员与用户沟通的程度关系到需求分析的质量,因此建立一个良好的沟通氛围、处理好分析人员与用户之间的关系显得尤其重要,一般情况,用户作为投资方会有一些心理优势,希望他们的意见得到足够的重视,分析人员应该充分的认识到这一点,做好心理准备,尽量避免与他们发生争执,因为我们的目的是帮助用户说出他们的最终需要。在沟通时分析人员应注意以下几个方面:1)态度上要尊重对方,但不谦恭。谦恭可能会让用户一时感到满意,但对长期合作并没有好处,尤其是在发生冲突的时候,用户会习惯性地感到自己的优势,而忽略分析人员地意见。2)分析人员要努力适应不同用户的语言表达方式。每个人都有自己的表达方式,所以优秀的分析人员应该是一个优秀的“倾听者”,他们能很快的适应用户的语言风格,理解他们的意思。 3)善于表达自己,善于提问。分析人员在开口前应该先让对方充分表达他的意思,在领会了后,自己再说,尽量不要抢话。4)工作外的交流有助于增进理解,加强沟通。
  4)需求质量控制要制度化需求的变化是软件项目不可避免的事实,因此需求质量控制是一项艰苦的工作,要保证该项工作的顺利实施,就必须有制度保证,这个制度可以在项目质量控制方案中制定,该方案主要是具体化、定量化的描述用户要求,形成全面、一致、规范的软件需求分析规格说明书,明确需求分析规格说明书的工作程序和要素,规范开发活动,为后续软件设计、实现、测试、评审及验收提供依据。在方案中要明确项目组各部门关于需求质量控制的职责,制定需求分析的工作程序,包括编制需求分析工作计划、编制《需求分析说明书》、《需求分析规格说明书》的评审和确认、《需求分析规格说明书》修改控制、确定需求质量控制的质量记录文档规范等内容。
  本文论述围绕于需求管理,需求管理是开发工作有效进行的确证。很明显需求管理是一种很高层次的系统行为,涉及整个开发过程和产品本身。需求管理首先要针对需求做出分析,随后应用于产品并提出方案。需求分析的模型正是产品的原型样本,优秀的需求管理提高了这样的可能性:它使最终产品更接近于解决需求,提高了用户对产品的满意度,从而使产品成为真正优质合格的产品。从这层意义上说,需求管理是产品质量的基础。

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

你应当知道的7个Java工具

 AlexZhitnitsky告诉我们这7个辅助工具的主要功能特点,这些工具每个java程序员都应该了解一下。这篇文章最初发表在takipi的博客–Java与Scala异常分析和性能监控.
  在准备进行锁和负载测试之前,应该对一些最新的最具创新性的工具有一个快速了解。为了防止你错过这些信息,rebellabs最近公布了对Java工具和技术全景的一个全球性调查结果。除了一些已有的或知名度很高的工具,现在市场上还充满了很多不为人知的全新的工具和框架。
  在这篇文章中我们决定收集制作一个关于这类工具的简略名单,他们中的大多数工具只是最近推出的。其中一些工具是为Java定制的,但也有一些是支持其他语言。但对于Java项目而言,他们都是非常好的,并且拥有同一个愿景:简单化。让我们开始吧。
  1.JClarity–性能监测工具
  它发布于去年9月。围绕java性能,当前这款工具提供了两个产品:Illuminate和Censum。
  Illuminate是一款性能监测工具,而censum是一种聚焦于垃圾收集日志分析的应用。
  它不仅仅提供了数据收集功能和可视化,对于检测到的问题,这两个工具能够提供具有实践性强的建议,帮助开发人员去解决问题。
  “我们要做的是把问题从数据收集阶段转移到数据分析和观察阶段”–JClarityCo-FounderBenEvans.
  主要特性:
  瓶颈检测(磁盘I/O,垃圾收集,死锁等)
  实施计划–提出解决问题的具体建议,如“应用程序需要增加活动线程数”。
  解释–一般性问题的定义以及引起该问题的常见原因,例如“垃圾回收时停顿时间耗时比例过高,可能意味着堆内存不够,太小了”。
  独特之处:进行监测和性能问题确认后,他会立即提供可行性的意见来解决这些问题
  幕后故事:JClarity是在伦敦建立的,他的创始人包括MartijnVerburg,KirkPepperdin和BenEvans,都是在java性能领域有着非常丰富经验的人。
  想要获取更多关于JClarity的信息,点击这里
  2.Bintray-二元次的社交平台
  当从一些”匿名”仓库中导入库文件时,Java开发人员在某种程度上被蒙在鼓里。Bintray给这些代码添了“一张脸”,作为一个社会化平台为java开发者服务,分享开源的软件包(会不会有人说这是二元次的github?).它拥有超过85000个文件包,涵盖18000个库,展示了当前流行的和新版本的包。
  主要特性:
  上传你的二进制文件,让全世界都可以看到,并且可以和其他开发者进行交流,并得到一些反馈。
  使用Gradle/Maven/Yum/Apt工具下载包文件,或者直接从平台下载。
  管理包的版本说明和相关文档
  REST风格的API-查询/检索文件接口和自动分发接口
  独特之处:Bintray的基础功能类似于maven中央仓库。但他增加了一个社交层,提供了一个将文件分发到CDN服务器的简单办法。
  幕后故事:JFrog基于Israel和California,开发了Bintray。该工具是去年4月公开的,并在上次JavaOne大会上赢得了Duke’schoiceaward奖项
  JFrog也开发Artifactory,Artifactory当然也是跑在Bintray上的。
  3.Librato–监控和可视化云服务
  Librato作为一个监控和管理云应用的托管服务,它可以瞬间完成自定义面板的创建,而不需要用户去配置或者安装任何软件。
  相比其他面板,他的外观和感受如黄油般顺滑。
  “仅当你能够从数据中获得具有实际意义的信息时,数据才是有价值的”—JoeRuscio,Co-Founder&CTO
  主要特性:
  数据收集:集成了Heroku、AWS、数十种集成代理,以及绑定了java、Clojure等语言。
  自定义报告:性能指标和告警可以通过邮件、HipChat、Campfire以及HTTPPOST请求与你所想到的任何东西进行整合
  数据可视化:带有注释、相关性分析,共享和嵌入选项的美观的图片展示
  告警:当指标超过一定阈值时会自动发出通知告警
  特别之处:很难找到任何Librato不知道如何表述以及对数据的理解。
  幕后故事:FredvandenBosch,JoeRuscio,MikeHeffnerandDanStodin几个人在SanFrancisco创建了Librato
  4.Takipi的建立基于一个简单的目的:告诉开发人员到底在何时什么原因代码出现异常。每当一个新的异常抛出,或者一个错误日志发生,Takipi就会捕获它,给用户展示可能引起该异常的变量状态,经过的方法和设备。Takipi在错误发生时刻将会覆盖实际执行代码—所以在你分析异常时,就如同当异常发生时你正好在场。
  主要特性
  监控-捕获/未捕获的异常,http错误,和被日志记录的错误
  优先排序-如果异常错误涉及到新增的代码或者修改过的代码,工具会统计集群中这样的错误发生的频率,以及错误发生的概率是否在递增。
  分析-观测实际代码和变量状态,甚至跨越不同的机器和应用
  独特之处:
  生产环境的GodMode模式。错误发生时展示实际执行的异常代码和变量状态。这样你分析异常时,就如同当异常发生时你在场。
  幕后故事:Takipi创建于2012年的SanFrancisco和TelAviv。每种异常类型和错误都有唯一的怪物来代表他。\ 5.Elasticsearch–搜索和分析平台
  Elasticsearch已经存在一段时间了,但是他的1.0.0版本在2月份才发布。他是一个基于lucene的,托管在github上的开源项目,他有200位开发者。你可以从这checkout出代码.Elasticsearch提供的主要特性是易于使用的,可扩展的,分布式的,rest风格的检索。
  主要特性
  实时文档存储,文档对象的每个field都建立了索引,都能被检索
  构建适应于不同规模的应用的体系结构,在此之上实现分布式搜索。
  为其他平台系统提供了具有rest风格的和原生javaapi。他也有hadoop的依赖包
  简单可用性强,不需要对搜索原理有深入的理解。该平台有免费模式,所以你可以快速开始应用起来。
  独特之处:如他所说,他具有可伸缩性,灵活的构建和易用性。提供一个易用性的平台,进行规模扩展时无需考虑核心功能与用户自定义选项间妥协。
  幕后故事:Elasticsearch由ShayBanonback创建于2010年,最近募集到了7000万刀的资金。在创建该项目前,Banon就经营一个Compass的开源项目,现在他是一个著名的搜索专家。那他进入搜索领域的动机呢?原来是为了让他妻子能够保存和检索所喜欢的食谱,进而开发的一个应用。
  6.Spark–微型Web框架
  回到java语言,Spark是一个极具自由灵感的,能够快速创建Web应用程序的微型Web框架。为了支持java8和lambdas,今年早些时候他被重写了。Spark是一个开源项目,源代码可以在github上可以看到(请点击这里),目前开发该框架的人是PerWendel和过去几年为了实现只需要付出很小的努力,便可以快速构建一个web应用这样使命的一小撮人。
  主要特性:
  快速上手,配置简单
  直观的路由匹配器
  创建可复用组建的模板引擎,它支持Freemarker,ApacheVelocity和Mustache
  Spark可以运行在Jetty上,也可以在tomcat上跑
  独特之处:图片胜过千言万语,图片更加直观,把代码check出来感受一下吧
  幕后故事:Spark的创始人是PerWendel,瑞典人。目前与其他20个人开发Spark。去看看讨论组,学习更多的关于Spark的知识,了解如何去给这个开源项目做贡献,解决bug。
  7.Plumbr–内存泄漏检测
  深入研究java虚拟机,其中的GC(GarbageCollector垃圾收集器)将那些不再使用的对象进行回收,释放内存。尽管如此,有时候,开发人员仍旧会持有那些不再使用的对象引用,占用内存。这样就会发生内存泄漏,这个时候,Plumer就该登场了。如果应用发生了内存泄漏问题,Plumer就会进行检测,生成报告,并且提供切实可行的方案去fix掉这个问题。
  主要特性
  实时的内存泄漏检测和告警
  一份包含时间,内存大小,速度(MB/h)以及泄漏事件的重要级别的报告。
  内存泄漏的代码位置
  独特之处:快,切中要点,从代码中分析并给出建议帮你修复Bug
  幕后故事:Plumbr创建于Estonia,创始人是PriitPotter,IvoM?gi,NikitaSalnikov-Tarnovski和Vladimir?or。加入这样一个拥有非常丰富经验的java团队吧,这些家伙都是非常厉害的救火队员。嗯,是这样的

posted @ 2014-12-03 13:38 顺其自然EVO 阅读(253) | 评论 (0)编辑 收藏

你真的懂产品管理吗?实际上你一直都做错了

 有人会雇佣个销售代表,让更新网站,然后在思考为什么销售不肯来了呢?
  或者聘请个会计师,让她去管理开发团队,然后问她账目为什么不是最新的?
  或者让几个程序猿花时间准备营销邮件,然后问他们为什么代码总被延期交付?
  或招聘个产品经理,让他更新网站,管理开发团队和撰写营销邮件,然后问他为什么产品战略不够高效,产品路线图为什么不够完善。
  好吧,前3种情况可能并不多见,但最后一种,产品管理的不幸总在许多公司上演,并在涉及到定义产品管理责任时,都会清晰地显现出来。
  产品经理名言
  我们曾调查,什么事阻止了产品经理高效地工作?我们脑海里显现出一幅清晰的画面,产品经理做的一切,从技术支持到项目管理,就如别人所说,“像个打杂的”。
  大部分公司会聘请员工来长期或短期地关注一些成功的产品,但这些员工过来后,往往会偏离招聘地初衷,干些其它的事情。
  产品管理是一个跨职能部分角色。但这并不意味着产品经理就应该做其它部分的工作。他们应该确保工作是由合适的人在做,并与产品整体目标保持一致。
  成功需要协调
  为了最大限度地提高产品的成功,需要做好以下4点:
  业务活动和目标
  组织准备(内部和外部)
  产品上市的计划和活动
  产品计划和能力
  每个目标可被分解成一系列活动及里程碑,一些工作应该由产品经理完成,或在产品经理的监督下,由其它组完成。如果产品管理不注重在这几个方面调整和优化每个产品的话,那么你在公司将失去核心价值。
  管理层需要确保该被其他组完成的工作,最后也是由这些组完成,而不是由(通常人员不足时)产品经理完成。
  否则,你就像让销售代表来更新你的网站一样。当然,企业的效益也跟这一样。

posted @ 2014-12-03 13:38 顺其自然EVO 阅读(142) | 评论 (0)编辑 收藏

Java数组的定义及用法

数组是有序数据的集合,数组中的每一个元素具有同样的数组名和下标来唯一地确定数组中的元素。
  1. 一维数组
  1.1 一维数组的定义
  type arrayName[];
  type[] arrayName;
  当中类型(type)能够为Java中随意的数据类型,包含简单类型组合类型,数组名arrayName为一个合法的标识符,[]指明该变量是一个数组类型变量。
  另外一种形式对C++开发人员可能认为非常奇怪,只是对JAVA或C#这种开发语言来说,另外一种形式可能更直观,由于这里定义的仅仅是个变量而已,系统并未对事实上例化,仅仅需指明变量的类型就可以,也不需在[]指定数组大小。(第一种形式是不是仅仅是为了兼容曾经的习惯,毕竟C语言的影响太大了?)
  比如:
  int intArray[];
  声明了一个整型数组,数组中的每一个元素为整型数据。与C、C++不同,Java在数组的定义中并不为数组元素分配内存,因此[]中不用指出数组中元素个数,即数组长度,并且对于如上定义的一个数组是不能訪问它的不论什么元素的。我们必须为它分配内存空间,这时要用到运算符new,其格式例如以下:
  arrayName=new type[arraySize];
  当中,arraySize指明数组的长度。如:
  intArray=new int[3];
  为一个整型数组分配3个int型整数所占领的内存空间。
  通常,这两部分能够合在一起,格式例如以下:
  type arrayName=new type[arraySize];
  比如:
  int intArray=new int[3];
  1.2 一维数组元素的引用
  定义了一个数组,并用运算符new为它分配了内存空间后,就能够引用数组中的每个元素了。数组元素的引用方式为:
  arrayName[index]
  当中:index为数组下标,它能够为整型常数或表达式。如a[3],b[i](i为整型),c[6*I]等。下标 从0開始,一直到数组的长度减1。对于上面样例中的in-tArray数来说,它有3个元素,分别为:
  intArray[0],intArray[1],intArray[2]。注意:没有intArray[3]。
  另外,与C、C++中不同,Java对数组元素要进行越界检查以保证安全性。同一时候,对于每一个数组都有一个属性length指明它的长度,比如:intArray.length指明数组intArray的长度。
  执行结果例如以下:
  C:/>java ArrayTest
  a[4]=4
  a[3]=3
  a[2]=2
  a[1]=1
  a[0]=0
  该程序对数组中的每一个元素赋值,然后按逆序输出。
  1.3 一维数组的初始化
  对数组元素能够依照上述的样例进行赋值。也能够在定义数组的同一时候进行初始化。
  比如:
  int a[]={1,2,3,4,5};
  用逗号(,)分隔数组的各个元素,系统自己主动为数组分配一定空间。
  与C中不同,这时Java不要求数组为静态(static),事实上这里的变量相似C中的指针,所以将其作为返回值给其他函数使用,仍然是有效的,在C中将局部变量返回给调用函数继续使用是刚開始学习的人非常easy犯的错误。
  2. 多维数组
  与C、C++一样,Java中多维数组被看作数组的数组。比如二维数组为一个特殊的一维数组,其每一个元素又是一个一维数组。以下我们主要以二维数为例来进行说明,高维的情况是相似的。
  2.1 二维数组的定义
  二维数组的定义方式为:
  type arrayName[][];
  比如:
  int intArray[][];
  与一维数组一样,这时对数组元素也没有分配内存空间,同要使用运算符new来分配内存,然后才干够訪问每一个元素。
  对高维数组来说,分配内存空间有以下几种方法:
  1. 直接为每一维分配空间,如:
  int a[][]=new int[2][3];
  2. 从最高维開始,分别为每一维分配空间,如:
  int a[][]=new int[2][];
  a[0]=new int[3];
  a[1]=new int[3];
  完毕1中同样的功能。这一点与C、C++是不同的,在C、C++中必须一次指明每一维的长度。
  2.2 二维数组元素的引用
  对二维数组中每一个元素,引用方式为:arrayName[index1][index2] 当中index1、index2为下标,可为整型常数或表达式,如a[2][3]等,相同,每一维的下标都从0開始。
  2.3 二维数组的初始化
  有两种方式:
  1. 直接对每一个元素进行赋值。
  2. 在定义数组的同一时候进行初始化。
  如:int a[][]={{2,3},{1,5},{3,4}};
  定义了一个3×2的数组,并对每一个元素赋值。

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

Java对象实例化

 JAVA类,只要知道了类名(全名)就可以创建其实例对象,通用的方法是直接使用该类提供的构造方法,如
  NewObject o = new NewObject();
  NewObject o = new NewObject("test");
  NewObject o = new NewObject(new String[]{"aaa","bbb"});
  除此之外,还可以利用java.lang.Class<T>类来实现JAVA类的实例化。
  1、空构造方法
  如果类有空构造方法,如下面的类
public class NewObject
{
String name;
public NewObject(String[] name)
{
this.name = name[0];
System.out.println(“ the object is created!”);
}
public void write()
{
System.out.println(this.name);
}
}
  使用以下代码可实现实例化:
NewObject no = null;
try
{
no = (NewObject)Class.forName(className).newInstance();
no.write();
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}

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

  2、带参数构造方法
public class NewObject
{
String name;
public NewObject()
{
System.out.println(“ the object is created!”);
}
public void write()
{
System.out.println(“”);
}
}
  使用以下代码可实现实例化:
try
{
no=(NewObject)Class.forName(className).getConstructor(String.class).newInstance(names);
//no=(NewObject)Class.forName(className).getConstructor(newObject[]{String.class}).newInstance(names);
}
catch(IllegalArgumentExceptione)
{
e.printStackTrace();
}
catch(SecurityExceptione)
{
e.printStackTrace();
}
catch(InstantiationExceptione)
{
e.printStackTrace();
}
catch(IllegalAccessExceptione)
{
e.printStackTrace();
}
catch(InvocationTargetExceptione)
{
e.printStackTrace();
}
catch(NoSuchMethodExceptione)
{
e.printStackTrace();
}
catch(ClassNotFoundExceptione)
{
e.printStackTrace();
}
  3、带数组参数构造方法
  public class NewObject
  {
  String name;
  public NewObject(String name)
  {
  this.name = name;
  System.out.println(“ the object is created!”);
  }
  public void write()
  {
  System.out.println(this.name);
  }
  }
  使用以下代码可实现实例化:
try
{
Constructor[] cs;
cs = Class.forName(className).getConstructors();
Constructor cc = Class.forName(className).getConstructor(String[].class);
no = (NewObject)cc.newInstance(new Object[]{names});
}
catch (SecurityException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
catch (NoSuchMethodException e)
{
e.printStackTrace();
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
catch (InvocationTargetException e)
{
e.printStackTrace();
}

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

Java 8的6个问题

1. 并行Streams实际上可能会降低你的性能
  Java8带来了最让人期待的新特性之–并行。parallelStream() 方法在集合和流上实现了并行。它将它们分解成子问题,然后分配给不同的线程进行处理,这些任务可以分给不同的CPU核心处理,完成后再合并到一起。实现原理主要是使用了fork/join框架。好吧,听起来很酷对吧!那一定可以在多核环境下使得操作大数据集合速度加快咯,对吗?
  不,如果使用不正确的话实际上会使得你的代码运行的更慢。我们进行了一些基准测试,发现要慢15%,甚至可能更糟糕。假设我们已经运行了多个线程,然后使用.parallelStream() 来增加更多的线程到线程池中,这很容易就超过多核心CPU处理的上限,从而增加了上下文切换次数,使得整体都变慢了。
  基准测试将一个集合分成不同的组(主要/非主要的):
  Map<Boolean, List<Integer>> groupByPrimary = numbers
  .parallelStream().collect(Collectors.groupingBy(s -> Utility.isPrime(s)));
  使得性能降低也有可能是其他的原因。假如我们分成多个任务来处理,其中一个任务可能因为某些原因使得处理时间比其他的任务长很多。.parallelStream() 将任务分解处理,可能要比作为一个完整的任务处理要慢。来看看这篇文章, Lukas Krecan给出的一些例子和代码 。
  提醒:并行带来了很多好处,但是同样也会有一些其他的问题需要考虑到。当你已经在多线程环境中运行了,记住这点,自己要熟悉背后的运行机制。
  2. Lambda 表达式的缺点
  lambda表达式。哦,lambda表达式。没有lambda表达式我们也能做到几乎一切事情,但是lambda是那么的优雅,摆脱了烦人的代码,所以很容易就爱上lambda。比如说早上起来我想遍历世界杯的球员名单并且知道具体的人数(有趣的事实:加起来有254个)。
  List lengths = new ArrayList();
  for (String countries : Arrays.asList(args)) {
  lengths.add(check(country));
  }
  现在我们用一个漂亮的lambda表达式来实现同样的功能:
  Stream lengths = countries.stream().map(countries -< check(country));
  哇塞!这真是超级厉害。增加一些像lambda表达式这样的新元素到Java当中,尽管看起来更像是一件好事,但是实际上却是偏离了Java原本的规范。字节码是完全面向对象的,伴随着lambda的加入 ,这使得实际的代码与运行时的字节码结构上差异变大。阅读更多关于lambda表达式的负面影响可以看Tal Weiss这篇文章。
  从更深层次来看,你写什么代码和调试什么代码是两码事。堆栈跟踪越来越大,使得难以调试代码。一些很简单的事情譬如添加一个空字符串到list中,本来是这样一个很短的堆栈跟踪
  at LmbdaMain.check(LmbdaMain.java:19)
  at LmbdaMain.main(LmbdaMain.java:34)
  变成这样:
at LmbdaMain.check(LmbdaMain.java:19)
at LmbdaMain.lambda$0(LmbdaMain.java:37)
at LmbdaMain$$Lambda$1/821270929.apply(Unknown Source)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.LongPipeline.reduce(LongPipeline.java:438)
at java.util.stream.LongPipeline.sum(LongPipeline.java:396)
at java.util.stream.ReferencePipeline.count(ReferencePipeline.java:526)
at LmbdaMain.main(LmbdaMain.java:39
  lambda表达式带来的另一个问题是关于重载:使用他们调用一个方法时会有一些传参,这些参数可能是多种类型的,这样会使得在某些情况下导致一些引起歧义的调用。Lukas Eder 用示例代码进行了说明。
  提醒:要意识到这一点,跟踪有时候可能会很痛苦,但是这不足以让我们远离宝贵的lambda表达式。
  3. Default方法令人分心
  Default方法允许一个功能接口中有一个默认实现,这无疑是Java8新特性中最酷的一个,但是它与我们之前使用的方式有些冲突。那么既然如此,为什么要引入default方法呢?如果不引入呢?
  Defalut方法背后的主要动机是,如果我们要给现有的接口增加一个方法,我们可以不用重写实现来达到这个目的,并且使它与旧版本兼容。例如,拿这段来自Oracle Java教程中 添加指定一个时区功能的代码来说:
public interface TimeClient {
// ...
static public ZoneId getZoneId (String zoneString) {
try {
return ZoneId.of(zoneString);
} catch (DateTimeException e) {
System.err.println("Invalid time zone: " + zoneString +
"; using default time zone instead.");
return ZoneId.systemDefault();
}
}
default public ZonedDateTime getZonedDateTime(String zoneString) {
return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
}
}
  就是这样,问题迎刃而解了。是这样么?Default方法将接口和实现分离混合了。似乎我们不用再纠结他们本身的分层结构了,现在我们需要解决新的问题了。想要了解更多,阅读Oleg Shelajev在RebelLabs上发表的文章吧。
  提醒:当你手上有一把锤子的时候,看什么都像是钉子。记住它们原本的用法,保持原来的接口而重构引入新的抽象类是没有意义的。
 4. 该如何拯救你,Jagsaw?
  Jigsaw项目的目标是使Java模块化,将JRE分拆成可以相互操作的组件。这背后最主要的动机是渴望有一个更好、更快、更强大的Java嵌入式。我试图避免提及“物联网”,但我还是说了。减少JAR的体积,改进性能,增强安全性等等是这个雄心勃勃的项目所承诺的。
  但是,它在哪呢?Oracle的首席Java架构师, Mark Reinhold说:  Jigsaw,通过了探索阶段 ,最近才进入第二阶段,现在开始进行产品的设计与实现。该项目原本计划在Java8完成。现在推迟到Java9,有可能成为其最主要的新特性。
  提醒:如果这正是你在等待的, Java9应该在2016年间发布。同时,想要密切关注甚至参与其中的话,你可以加入到这个邮件列表。
  5. 那些仍然存在的问题
  受检异常
  没有人喜欢繁琐的代码,那也是为什么lambdas表达式那么受欢迎的的原因。想想讨厌的异常,无论你是否需要在逻辑上catch或者要处理受检异常,你都需要catch它们。即使有些永远也不会发生,像下面这个异常就是永远也不会发生的:
  try {
  httpConn.setRequestMethod("GET");
  }?catch (ProtocolException pe) { /* Why don’t you call me anymore? */ }
  原始类型
  它们依然还在,想要正确使用它们是一件很痛苦的事情。原始类型导致Java没能够成为一种纯面向对象语言,而移除它们对性能也没有显著的影响。顺便提一句,新的JVM语言都没有包含原始类型。
  运算符重载
  James Gosling,Java之父,曾经在接受采访时说:“我抛弃运算符重载是因为我个人主观的原因,因为在C++中我见过太多的人在滥用它。”有道理,但是很多人持不同的观点。其他的JVM语言也提供这一功能,但是另一方面,它导致有些代码像下面这样:
  javascriptEntryPoints <<= (sourceDirectory in Compile)(base =>
  ((base / "assets" ** "*.js") --- (base / "assets" ** "_*")).get
  )
  事实上这行代码来自Scala  Play框架,我现在都有点晕了。
  提醒:这些是真正的问题么?我们都有自己的怪癖,而这些就是Java的怪癖。在未来的版本中可能有会发生一些意外,它将会改变,但向后兼容性等等使得它们现在还在使用。
  6. 函数式编程–为时尚早
  函数式编程出现在java之前,但是它相当的尴尬。Java8在这方面有所改善例如lambdas等等。这是让人受欢迎的,但却不如早期所描绘的那样变化巨大。肯定比Java7更优雅,但是仍需要努力增加一些真正需要的功能。
  其中一个在这个问题上最激烈的评论来自Pierre-yves Saumont,他写了一系列的文章详细的讲述了函数式编程规范和其在Java中实现的差异。
  所以,选择Java还是Scala呢?Java采用现代函数范式是对使用多年Lambda的Scala的一种肯定。Lambdas让我们觉得很迷惑,但是也有许多像traits,lazy evaluation和immutables等一些特性,使得它们相当的不同。
  提醒:不要为lambdas分心,在Java8中使用函数式编程仍然是比较麻烦的。

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

聊聊Oracle外键约束的几个操作选项

关系型数据库是以数据表和关系作为两大对象基础。数据表是以二维关系将数据组织在DBMS中,而关系建立数据表之间的关联,搭建现实对象模型。主外键是任何数据库系统都需存在的约束对象,从对象模型中的业务逻辑加以抽象,作为物理设计的一个部分在数据库中加以实现。
  Oracle外键是维护参照完整性的重要手段,大多数情况下的外键都是紧密关联关系。外键约束的作用,是保证字表某个字段取值全都与另一个数据表主键字段相对应。也就是说,只要外键约束存在并有效,就不允许无参照取值出现在字表列中。具体在Oracle数据库中,外键约束还是存在一些操作选项的。本篇主要从实验入手,介绍常见操作选项。
  二、环境介绍
  笔者选择Oracle 11gR2进行测试,具体版本号为11.2.0.4。
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE      11.2.0.4.0     Production
TNS for 64-bit Windows: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 – Production
  创建数据表Prim和Child,对应数据插入。
SQL> create table prim (v_id number(3), v_name varchar2(100));
Table created
SQL> alter table prim add constraint pk_prim primary key (v_id);
Table altered
SQL> create table child (c_id number(3), v_id number(3), c_name varchar2(100));
Table created
SQL> alter table child add constraint pk_child primary key (c_id);
Table altered
  二、默认外键行为
  首先我们查看默认外键行为方式。
  SQL> alter table CHILD
  2    add constraint FK_CHILD_PRIM foreign key (V_ID)
  3    references prim (V_ID)
  4  ;
  在没有额外参数加入的情况下,Oracle外键将严格按照标准外键方式工作
  --在有子记录情况下,强制删除主表记录;
  SQL> delete prim where v_id=2;
  delete prim where v_id=2
  ORA-02292:违反完整约束条件(A.FK_CHILD_PRIM) - 已找到子记录
  --在存在子表记录情况下,更改主表记录;
  SQL> update prim set v_id=4 where v_id=2;
  update prim set v_id=4 where v_id=2
  ORA-02292:违反完整约束条件(A.FK_CHILD_PRIM) - 已找到子记录
  --修改子表记录
  SQL> update child set v_id=5 where v_id=2;
  update child set v_id=5 where v_id=2
  ORA-02291: 违反完整约束条件 (A.FK_CHILD_PRIM) - 未找到父项关键字
  上面实验说明:在默认的Oracle外键配置条件下,只要有子表记录存在,主表记录是不允许修改或者删除的。子表记录也必须时刻保证参照完整性。
 三、On delete cascade
  对于应用开发人员而言,严格外键约束关系是比较麻烦的。如果直接操作数据库记录,就意味着需要手工处理主子表关系,处理删除顺序问题。On delete cascade允许了一种“先删除主表,连带删除子表记录”的功能,同时确保数据表整体参照完整性。
  创建on delete cascade外键,只需要在创建外键中添加相应的子句。
  SQL> alter table child add constraint FK_CHILD_PRIM foreign key(v_id) references prim(v_id) on delete cascade;
  Table altered
  测试:
SQL> delete prim where v_id=2;
1 row deleted
SQL> select * from prim;
V_ID V_NAME
---- --------------------------------------------------------------------------------
1 kk
3 iowkd
SQL> select * from child;
C_ID V_ID C_NAME
---- ---- --------------------------------------------------------------------------------
1    1 kll
2    1 ddkll
3    1 43kll
SQL> rollback;
Rollback complete
  删除主表操作成功,对应的子表记录被连带自动删除。但是其他操作依然是不允许进行。
  SQL> update prim set v_id=4 where v_id=2;
  update prim set v_id=4 where v_id=2
  ORA-02292:违反完整约束条件(A.FK_CHILD_PRIM) - 已找到子记录
  SQL> update child set v_id=5 where v_id=2;
  update child set v_id=5 where v_id=2
  ORA-02291: 违反完整约束条件 (A.FK_CHILD_PRIM) - 未找到父项关键字
  On delete cascade被称为“级联删除”,对开发人员来讲是一种方便的策略,可以直接“无视”子记录而删掉主记录。但是,一般情况下,数据库设计人员和DBA一般都不推荐这样的策略。
  究其原因,还是由于系统业务规则而定。On delete cascade的确在一定程度上很方便,但是这种自动操作在一些业务系统中是可能存在风险的。例如:一个系统中存在一个参数引用关系,这个参数被引用到诸如合同的主记录中。按照业务规则,如果这个参数被引用过,就不应当被删除。如果我们设置了on delete cascade外键,连带的合同记录就自动的被“干掉”了。开发参数模块的同事一般情况下,也没有足够的“觉悟”去做手工判定。基于这个因素,我们推荐采用默认的强约束关联,起码不会引起数据丢失的情况。
  四、On Delete Set Null
  除了直接删除记录,Oracle还提供了一种保留子表记录的策略。注意:外键约束本身不限制字段为空的问题。如果一个外键被设置为on delete set null,当删除主表记录的时候,无论是否存在子表对应记录,主表记录都会被删除,子表对应列被清空。
  SQL> alter table child drop constraint fk_child_prim;
  Table altered
  SQL> alter table child add constraint FK_CHILD_PRIM foreign key(v_id) references prim(v_id) on delete set null;
  Table altered
  删除主表记录。
SQL> delete prim where v_id=2;
1 row deleted
SQL> select * from prim;
V_ID V_NAME
---- --------------------------------------------------------------------------------
1 kk
3 iowkd
SQL> select * from child;
C_ID V_ID C_NAME
---- ---- --------------------------------------------------------------------------------
1    1 kll
2    1 ddkll
3    1 43kll
4      43kll
5      4ll
SQL> rollback;
Rollback complete
  主表记录删除,子表外键列被清空。其他约束动作没有变化。
  SQL> update prim set v_id=4 where v_id=2;
  update prim set v_id=4 where v_id=2
  ORA-02292:违反完整约束条件(A.FK_CHILD_PRIM) - 已找到子记录
  SQL> update child set v_id=5 where v_id=2;
  update child set v_id=5 where v_id=2
  ORA-02291: 违反完整约束条件 (A.FK_CHILD_PRIM) - 未找到父项关键字
  那么,下一个问题是:如果外键列不能为空,会怎么样呢?
SQL> desc child;
Name   Type          Nullable Default Comments
------ ------------- -------- ------- --------
C_ID   NUMBER(3)
V_ID   NUMBER(3)     Y
C_NAME VARCHAR2(100) Y
SQL> alter table child modify v_id not null;
Table altered
SQL> desc child;
Name   Type          Nullable Default Comments
------ ------------- -------- ------- --------
C_ID   NUMBER(3)
V_ID   NUMBER(3)
C_NAME VARCHAR2(100) Y
SQL> delete prim where v_id=2;
delete prim where v_id=2
ORA-01407: 无法更新 ("A"."CHILD"."V_ID")为 NULL
  更改失败~
  五、传说中的on update cascade
  On update cascade被称为“级联更新”,是关系数据库理论中存在的一种外键操作类型。这种类型指的是:当主表的记录被修改(主键值修改),对应子表的外键列值连带的进行修改。
  SQL> alter table child add constraint FK_CHILD_PRIM foreign key(v_id) references prim(v_id) on update cascade;
  alter table child add constraint FK_CHILD_PRIM foreign key(v_id) references prim(v_id) on update cascade
  ORA-00905: 缺失关键字
  目前的Oracle版本中,似乎还不支持on update cascade功能。Oracle在官方服务中对这个问题的阐述是:在实际系统开发环境中,直接修改主键的情况是比较少的。所以,也许在将来的版本中,这个特性会进行支持。
  六、结论
  Oracle外键是我们日常比较常见的约束类型。在很多专家和业界人员的讨论中,我们经常听到“使用外键还是系统编码”的争论。支持外键策略的一般都是数据库专家和“大撒把”的设计师,借助数据库天然的特性,可以高效实现功能。支持系统编码的人员大都是“对象派”等新派人员,相信可以借助系统前端解决所有问题。
  笔者对外键的观点是“适度外键,双重验证”。外键要设计在最紧密的引用关系中,对验证动作,前端和数据库端都要进行操作。外键虽然可以保证最后安全渠道,但是不能将正确易于接受的信息反馈到前端。前端开发虽然比较直观,但是的确消耗精力。所以,把握适度是重要的出发点。

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

SQL优化中索引列使用函数之灵异事件

 在SQL优化内容中有一种说法说的是避免在索引列上使用函数、运算等操作,否则Oracle优化器将不使用索引而使用全表扫描,但是也有一些例外的情况,今天我们就来看看该灵异事件。
  一般而言,以下情况都会使Oracle的优化器走全表扫描,举例:
  1.         substr(hbs_bh,1,4)=’5400’,优化处理:hbs_bh like ‘5400%’
  2.         trunc(sk_rq)=trunc(sysdate), 优化处理:sk_rq>=trunc(sysdate) and sk_rq<trunc(sysdate+1)
  3.         进行了显式或隐式的运算的字段不能进行索引,如:
  ss_df+20>50,优化处理:ss_df>30
  'X' || hbs_bh>’X5400021452’,优化处理:hbs_bh>'5400021542'
  sk_rq+5=sysdate,优化处理:sk_rq=sysdate-5
  4.         条件内包括了多个本表的字段运算时不能进行索引,如:ys_df>cx_df,无法进行优化
  qc_bh || kh_bh='5400250000',优化处理:qc_bh='5400' and kh_bh='250000'
  5.  避免出现隐式类型转化
  hbs_bh=5401002554,优化处理:hbs_bh='5401002554',注:此条件对hbs_bh 进行隐式的to_number转换,因为hbs_bh字段是字符型。
  有一些其它的例外情况,如果select 后边只有索引列且where查询中的索引列含有非空约束的时候,以上规则不适用,如下示例:
  先给出所有脚本及结论:
  drop table t  purge;
  Create Table t  nologging As select *  from    dba_objects d ;
  create   index ind_objectname on  t(object_name);
  select t.object_name from t where t.object_name ='T';        --走索引
  select t.object_name from t where UPPER(t.object_name) ='T';       --不走索引
  select t.object_name from t where UPPER(t.object_name) ='T' and t.object_name IS NOT NULL ;           --走索引  (INDEX FAST FULL SCAN)
  select t.object_name from t where UPPER(t.object_name) ||'AAA' ='T'||'AAA' and t.object_name IS NOT NULL ;     --走索引  (INDEX FAST FULL SCAN)
  select t.object_name,t.owner from t where UPPER(t.object_name) ||'AAA' ='T'||'AAA' and t.object_name IS NOT NULL ;     --不走索引
  测试代码:
C:\Users\华荣>sqlplus lhr/lhr@orclasm
SQL*Plus: Release 11.2.0.1.0 Production on 星期三 11月 12 10:52:29 2014
Copyright (c) 1982, 2010, Oracle.  All rights reserved.
连接到:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Data Mining
and Real Application Testing options
SQL>
SQL>
SQL> drop table t  purge;
表已删除。
SQL> Create Table t  nologging As select *  from    dba_objects d ;
表已创建。
SQL>  create   index ind_objectname on  t(object_name);
索引已创建。
 ---- t表所有列均可以为空
SQL> desc t
Name                      Null?    Type
----------------------------------------- -------- ----------------------------
OWNER                               VARCHAR2(30)
OBJECT_NAME                         VARCHAR2(128)
SUBOBJECT_NAME                      VARCHAR2(30)
OBJECT_ID                           NUMBER
DATA_OBJECT_ID                      NUMBER
OBJECT_TYPE                         VARCHAR2(19)
CREATED                             DATE
LAST_DDL_TIME                       DATE
TIMESTAMP                           VARCHAR2(19)
STATUS                              VARCHAR2(7)
TEMPORARY                           VARCHAR2(1)
GENERATED                           VARCHAR2(1)
SECONDARY                           VARCHAR2(1)
NAMESPACE                           NUMBER
EDITION_NAME                        VARCHAR2(30)
SQL>
SQL>  set autotrace traceonly;
SQL>  select t.object_name from t where t.object_name ='T';
执行计划
----------------------------------------------------------
Plan hash value: 4280870634
-----------------------------------------------------------------------------------
| Id  | Operation        | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |                |     1 |    66 |     3   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IND_OBJECTNAME |     1 |    66 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T"."OBJECT_NAME"='T')
Note
-----
- dynamic sampling used for this statement (level=2)
- SQL plan baseline "SQL_PLAN_503ygb00mbj6k165e82cd" used for this statement
统计信息
----------------------------------------------------------
34  recursive calls
43  db block gets
127  consistent gets
398  physical reads
15476  redo size
349  bytes sent via SQL*Net to client
359  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
1  rows processed
SQL>  select t.object_name from t where UPPER(t.object_name) ='T';
执行计划
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |    12 |   792 |   305   (1)| 00:00:04 |
|*  1 |  TABLE ACCESS FULL| T    |    12 |   792 |   305   (1)| 00:00:04 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(UPPER("T"."OBJECT_NAME")='T')
Note
-----
- dynamic sampling used for this statement (level=2)
- SQL plan baseline "SQL_PLAN_9p76pys5gdb2b94ecae5c" used for this statement
统计信息
----------------------------------------------------------
29  recursive calls
43  db block gets
1209  consistent gets
1092  physical reads
15484  redo size
349  bytes sent via SQL*Net to client
359  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
1  rows processed
SQL>  select t.object_name from t where UPPER(t.object_name) ='T' and t.object_name IS NOT NULL ;
执行计划
----------------------------------------------------------
Plan hash value: 3379870158
---------------------------------------------------------------------------------------
| Id  | Operation            | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                |    51 |  3366 |   110   (1)| 00:00:02 |
|*  1 |  INDEX FAST FULL SCAN| IND_OBJECTNAME |    51 |  3366 |   110   (1)| 00:00:02 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("T"."OBJECT_NAME" IS NOT NULL AND UPPER("T"."OBJECT_NAME")='T')
Note
-----
- dynamic sampling used for this statement (level=2)
- SQL plan baseline "SQL_PLAN_czkarb71kthws18b0c28f" used for this statement
统计信息
----------------------------------------------------------
29  recursive calls
43  db block gets
505  consistent gets
384  physical reads
15612  redo size
349  bytes sent via SQL*Net to client
359  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
1  rows processed
SQL>  select t.object_name,t.owner from t where UPPER(t.object_name) ||'AAA' ='T'||'AAA' and t.object_name IS NOT NULL ;
执行计划
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |    51 |  4233 |   304   (1)| 00:00:04 |
|*  1 |  TABLE ACCESS FULL| T    |    51 |  4233 |   304   (1)| 00:00:04 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("T"."OBJECT_NAME" IS NOT NULL AND
UPPER("T"."OBJECT_NAME")||'AAA'='TAAA')
Note
-----
- dynamic sampling used for this statement (level=2)
- SQL plan baseline "SQL_PLAN_au9a1c4hwdtb894ecae5c" used for this statement
统计信息
----------------------------------------------------------
30  recursive calls
44  db block gets
1210  consistent gets
1091  physical reads
15748  redo size
408  bytes sent via SQL*Net to client
359  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
1  rows processed
SQL> select t.object_name from t where UPPER(t.object_name) ||'AAA' ='T'||'AAA' and t.object_name IS NOT NULL ;
执行计划
----------------------------------------------------------
Plan hash value: 3379870158
---------------------------------------------------------------------------------------
| Id  | Operation            | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                |    51 |  3366 |   110   (1)| 00:00:02 |
|*  1 |  INDEX FAST FULL SCAN| IND_OBJECTNAME |    51 |  3366 |   110   (1)| 00:00:02 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("T"."OBJECT_NAME" IS NOT NULL AND
UPPER("T"."OBJECT_NAME")||'AAA'='TAAA')
Note
-----
- dynamic sampling used for this statement (level=2)
- SQL plan baseline "SQL_PLAN_1gu36rnh3s2a318b0c28f" used for this statement
统计信息
----------------------------------------------------------
28  recursive calls
44  db block gets
505  consistent gets
6  physical reads
15544  redo size
349  bytes sent via SQL*Net to client
359  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
1  rows processed
SQL>
  其实很好理解的,索引可以看成是小表,一般而言索引总是比表本身要小得多,如果select 后需要检索的项目在索引中就可以检索的到那么Oracle优化器为啥还去大表中寻找数据呢?

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

利用binlog进行数据库的还原

前言:在学习mysql备份的时候,深深的感受到mysql的备份还原功能没有oracle强大;比如一个很常见的恢复场景:基于时间点的恢复,oracle通过rman工具就能够很快的实现数据库的恢复,但是mysql在进行不完全恢复的时候很大的一部分要依赖于mysqlbinlog这个工具运行binlog语句来实现,本文档介绍通过mysqlbinlog实现各种场景的恢复;
  一、测试环境说明:使用mysqlbinlog工具的前提需要一个数据库的完整性备份,所以需要事先对数据库做一个完整的备份,本文档通过mysqlbackup进行数据库的全备
  二、测试步骤说明:
  数据库的插入准备工作
  2.1 在时间点A进行一个数据库的完整备份;
  2.2 在时间点B创建一个数据库BKT,并在BKT下面创建一个表JOHN,并插入5条数据;
  2.3 在时间点C往表JOHN继续插入数据到10条;
  数据库的恢复工作
  2.4 恢复数据库到时间点A,然后检查数据库表的状态;
  2.5 恢复数据库到时间点B,检查相应的系统状态;
  2.6 恢复数据库到时间点C,并检查恢复的状态;
  三、场景模拟测试步骤(备份恢复是一件很重要的事情)
  3.1 执行数据库的全备份;
  [root@mysql01 backup]# mysqlbackup --user=root --password --backup-dir=/backup backup-and-apply-log //运行数据库的完整备份
  3.2 创建数据库、表并插入数据
mysql> SELECT CURRENT_TIMESTAMP;
+---------------------+
| CURRENT_TIMESTAMP |
+---------------------+
| 2014-11-26 17:51:27 |
+---------------------+
1 row in set (0.01 sec)
mysql> show databases; //尚未创建数据库BKT
+--------------------+
| Database |
+--------------------+
| information_schema |
| john |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.03 sec)
mysql> Ctrl-C --
Aborted
[root@mysql02 data]# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \\g.
Your MySQL connection id is 2
Server version: 5.5.36-log Source distribution
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type \'help;\' or \'\\h\' for help. Type \'\\c\' to clear the current input statement.
mysql> show master status;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 | 107 | | | //当前数据库log的pos状态
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
mysql> SELECT CURRENT_TIMESTAMP; //当前的时间戳 当前时间点A
+---------------------+
| CURRENT_TIMESTAMP |
+---------------------+
| 2014-11-26 17:54:12 |
+---------------------+
1 row in set (0.00 sec)
mysql> create database BKT; //创建数据库BKT
Query OK, 1 row affected (0.01 sec)
mysql> create table john (id varchar(32));
ERROR 1046 (3D000): No database selected
mysql> use bkt;
ERROR 1049 (42000): Unknown database \'bkt\'
mysql> use BKT;
Database changed
mysql> create table john (id varchar(32));
Query OK, 0 rows affected (0.02 sec)
mysql> insert into john values(\'1\');
Query OK, 1 row affected (0.01 sec)
mysql> insert into john values(\'2\');
Query OK, 1 row affected (0.01 sec)
mysql> insert into john values(\'3\');
Query OK, 1 row affected (0.00 sec)
mysql> insert into john values(\'4\');
Query OK, 1 row affected (0.01 sec)
mysql> insert into john values(\'5\');
Query OK, 1 row affected (0.01 sec)
mysql> SELECT CURRENT_TIMESTAMP; //插入5条数据后数据库的时间点B,记录该点便于数据库的恢复
+---------------------+
| CURRENT_TIMESTAMP |
+---------------------+
| 2014-11-26 17:55:53 |
+---------------------+
1 row in set (0.00 sec)
mysql> show master status;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 | 1204 | | | //当前binlog的pos位置
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
 3.3 设置时间点C的测试
mysql> insert into john values(\'6\');
Query OK, 1 row affected (0.02 sec)
mysql> insert into john values(\'7\');
Query OK, 1 row affected (0.01 sec)
mysql> insert into john values(\'8\');
Query OK, 1 row affected (0.01 sec)
mysql> insert into john values(\'9\');
Query OK, 1 row affected (0.01 sec)
mysql> insert into john values(\'10\');
Query OK, 1 row affected (0.03 sec)
mysql> show master status;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 | 2125 | | |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
mysql> SELECT CURRENT_TIMESTAMP;
+---------------------+
| CURRENT_TIMESTAMP |
+---------------------+
| 2014-11-26 17:58:08 |
+---------------------+
1 row in set (0.00 sec)
  3.4 以上的操作完成之后,便可以执行数据库的恢复测试
[root@mysql02 data]# mysqlbackup --defaults-file=/backup/server-my.cnf --datadir=/data/mysql --backup-dir=/backup/ copy-back
MySQL Enterprise Backup version 3.11.0 Linux-3.8.13-16.2.1.el6uek.x86_64-x86_64 [2014/08/26]
Copyright (c) 2003, 2014, Oracle and/or its affiliates. All Rights Reserved.
mysqlbackup: INFO: Starting with following command line ...
mysqlbackup --defaults-file=/backup/server-my.cnf --datadir=/data/mysql
--backup-dir=/backup/ copy-back
mysqlbackup: INFO:
IMPORTANT: Please check that mysqlbackup run completes successfully.
At the end of a successful \'copy-back\' run mysqlbackup
prints \"mysqlbackup completed OK!\".
141126 17:59:58 mysqlbackup: INFO: MEB logfile created at /backup/meta/MEB_2014-11-26.17-59-58_copy_back.log
--------------------------------------------------------------------
Server Repository Options:
--------------------------------------------------------------------
datadir = /data/mysql
innodb_data_home_dir = /data/mysql
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = /data/mysql/
innodb_log_files_in_group = 2
innodb_log_file_size = 5242880
innodb_page_size = Null
innodb_checksum_algorithm = none
--------------------------------------------------------------------
Backup Config Options:
--------------------------------------------------------------------
datadir = /backup/datadir
innodb_data_home_dir = /backup/datadir
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = /backup/datadir
innodb_log_files_in_group = 2
innodb_log_file_size = 5242880
innodb_page_size = 16384
innodb_checksum_algorithm = none
mysqlbackup: INFO: Creating 14 buffers each of size 16777216.
141126 17:59:58 mysqlbackup: INFO: Copy-back operation starts with following threads
1 read-threads 1 write-threads
mysqlbackup: INFO: Could not find binlog index file. If this is online backup then server may not have started with --log-bin.
Hence, binlogs will not be copied for this backup. Point-In-Time-Recovery will not be possible.
141126 17:59:58 mysqlbackup: INFO: Copying /backup/datadir/ibdata1.
mysqlbackup: Progress in MB: 200 400 600
141126 18:00:22 mysqlbackup: INFO: Copying the database directory \'john\'
141126 18:00:23 mysqlbackup: INFO: Copying the database directory \'mysql\'
141126 18:00:23 mysqlbackup: INFO: Copying the database directory \'performance_schema\'
141126 18:00:23 mysqlbackup: INFO: Completing the copy of all non-innodb files.
141126 18:00:23 mysqlbackup: INFO: Copying the log file \'ib_logfile0\'
141126 18:00:23 mysqlbackup: INFO: Copying the log file \'ib_logfile1\'
141126 18:00:24 mysqlbackup: INFO: Creating server config files server-my.cnf and server-all.cnf in /data/mysql
141126 18:00:24 mysqlbackup: INFO: Copy-back operation completed successfully.
141126 18:00:24 mysqlbackup: INFO: Finished copying backup files to \'/data/mysql\'
mysqlbackup completed //数据库恢复完成
  授权并打开数据库
  [root@mysql02 data]# chmod -R 777 mysql //需要授权后才能打开
  [root@mysql02 data]# cd mysql
  [root@mysql02 mysql]# ll
  总用量 733220
-rwxrwxrwx. 1 root root 305 11月 26 18:00 backup_variables.txt
-rwxrwxrwx. 1 root root 740294656 11月 26 18:00 ibdata1
-rwxrwxrwx. 1 root root 5242880 11月 26 18:00 ib_logfile0
-rwxrwxrwx. 1 root root 5242880 11月 26 18:00 ib_logfile1
drwxrwxrwx. 2 root root 4096 11月 26 18:00 john
drwxrwxrwx. 2 root root 4096 11月 26 18:00 mysql
drwxrwxrwx. 2 root root 4096 11月 26 18:00 performance_schema
-rwxrwxrwx. 1 root root 8488 11月 26 18:00 server-all.cnf
-rwxrwxrwx. 1 root root 1815 11月 26 18:00 server-my.cnf //没有BKT数据库
[root@mysql02 mysql]# service mysqld start //启动数据库
  3.5 进行数据库的恢复到时间点B
  [root@mysql02 mysql2]# pwd //备份的时候,需要备份binlog日志,之前的binlog目录为/data/mysql2
  /data/mysql2
  [root@mysql02 mysql2]# mysqlbinlog --start-position=107 --stop-position=1203 mysql-bin.000001| mysql -uroot -p //根据post的位置进行恢复,当前的pos位置为107,恢复到pos位置到1203
Enter password:
[root@mysql02 mysql2]# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \\g.
Your MySQL connection id is 3
Server version: 5.5.36-log Source distribution
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type \'help;\' or \'\\h\' for help. Type \'\\c\' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| BKT |
| john |
| mysql |
| performance_schema |
+--------------------+
5 rows in set (0.02 sec)
mysql> use BKT
Database changed
mysql> show tables;
+---------------+
| Tables_in_BKT |
+---------------+
| john |
+---------------+
1 row in set (0.00 sec)
mysql> select * from john;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+------+
5 rows in set (0.01 sec) //查看数据库恢复成功
  3.6 恢复数据库到时间点C
[root@mysql02 mysql2]# mysqlbinlog --start-date=\"2014-11-27 09:21:56\" --stop-date=\"2014-11-27 09:22:33\" mysql-bin.000001| mysql -uroot -p123456 //本次通过基于时间点的恢复,恢复到时间点C
Warning: Using unique option prefix start-date instead of start-datetime is deprecated and will be removed in a future release. Please use the full name instead.
Warning: Using unique option prefix stop-date instead of stop-datetime is deprecated and will be removed in a future release. Please use the full name instead.
[root@mysql02 mysql2]# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \\g.
Your MySQL connection id is 6
Server version: 5.5.36-log Source distribution
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type \'help;\' or \'\\h\' for help. Type \'\\c\' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| BKT |
| john |
| mysql |
| performance_schema |
+--------------------+
5 rows in set (0.00 sec)
mysql> use BKT
Database changed
mysql> select * from john;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
+------+
10 rows in set (0.00 sec) //经过检查成功恢复到时间点C
  四、mysqlbinlog的其他总结:以上是利用binlog文件进行基于时间点和binlog的POS位置恢复的测试,mysqlbinlog的使用还有很多功能,运行mysqlbinlog --help可以查看相应参数;
  4.1 查看binlog的内容:[root@mysql02 mysql2]# mysqlbinlog mysql-bin.000001
  4.2 mysqlbinlog的其他常用参数:
  -h  根据数据库的IP
  -P  根据数据库所占用的端口来分
  -server-id 根据数据库serverid来还原(在集群中很有用)
  -d  根据数据库名称
  例如: [root@mysql02 mysql2]# mysqlbinlog -d BKT mysql-bin.000001 //还原BKT数据库的信息

posted @ 2014-12-03 13:34 顺其自然EVO 阅读(1363) | 评论 (0)编辑 收藏

探索Oracle之数据库升级一 升级补丁修复概述

 一、 升级路线图
  无论你是谁,要想做数据库升级,我想一定离不开如下这张升级线路图;企业中数据库的升级是一个浩大的工程,但是却又必不可少,小在打一个PSU解决一个简单的问题或实现某个功能,大到打安装Patch对数据库版本升级,都是作为一名合格的DBA必备的技能。再后面的几篇博客当中将详细讲述如何将数据库从11.2.0.3.0升级到11.2.0.4并且打上最新的OPATCH之后再升级到Oracle 12c。
  二、 升级类型:
  11.2.0.1.0 ----------11.2.0.4.0---------11.2.0.4.4-----------12.2.0.1.0
  CPU                      PSU
  Update                             upgrade
  1. 什么是PSU/CPU?
  CPU: Critical Patch Update   (SPU: Security Patch Update)
  Oracle对于其产品每个季度发行一次的安全补丁包,通常是为了修复产品中的安全隐患。
  PSU: Patch Set Updates
  Oracle对于其产品每个季度发行一次的补丁包,包含了bug的修复。Oracle选取被用户下载数量多的,并且被验证过具有较低风险的补丁放入到每个季度的PSU中。在每个PSU中不但包含Bug的修复而且还包含了最新的CPU。
  2. 如何查找最新的PSU
  每个数据库版本都有自己的PSU,PSU版本号体现在数据库版本的最后一位,比如最新的10.2.0.5的PSU是10.2.0.5.6,而11.2.0.3的最新PSU则是11.2.0.4.3。
  MOS站点中OracleRecommended Patches — Oracle Database [ID 756671.1] 文档中查到各个产品版本最新的PSU。
  如果你记不住这个文档号,那么在MOS中以“PSU”为关键字搜索,通常这个文档会显示在搜索结果的最前面。
  注意:必须购买了Oracle基本服务获取了CSI号以后才有权限登陆MOS站点。
  Upgrade与Update
  首先,我们针对所使用的数据库可能会进行如下措施,版本升级或补丁包升级,那何为版本升级、何为补丁包升级呢?
  比如我的当前数据库是10GR2版本,但公司最近有个升级计划,把这套数据库升级到当下最新的11GR2,这种大版本间升级动作即为Upgrade。根据公司计划在原厂工程师和DBA共同努力下,数据库已升级到11GR2,当下版本为11.2.0.4.0。这时候原厂工程师推荐把最新的PSU给打上,获得老板的批准之后,我们又把数据库进行补丁包的升级,应用了PSU Patch:18522509之后,数据库版本现在成为11.2.0.4.3,这个过程即是Update。
  不得不再次提醒,Upgrade和Update都希望在获得原厂的支持下进行,尤其是Upgrade,这对于企业来说是个非常大的动作!
  PSR(Patch Set Release)和 PSU(Patch Set Update)
  8i、9i、10g、11g、12c这是其主要版本号,每一版本会陆续有两至三个发行版,如10.1,10.2,和11.1,11.2分别是10g和11g的两个发行版。对于每一个发行版软件中发现的BUG,给出相应的修复补丁。每隔一定时期,会将所有补丁集成到软件中,经过集成测试后,进行发布,也称为PSR(Patch Set Release)。以10.2为例,10.2.0.1.0是基础发行版,至今已有三个PSR发布,每个PSR修改5位版本号的第4位,最新10.2的PSR为10.2.0.4.0。(11.1.0.6.0是11.1的基础发行版,11.1.0.7.0是第一次PSR)。
  在某个PSR之后编写的补丁,在还没有加入到下一个PSR之前,以个别补丁(InterimPatch)的形式提供给客户。某个个别补丁是针对Oracle公司发现的或客户报告的某一个BUG编写的补丁,多个个别补丁之间一同安装时可能会有冲突,即同一个目标模块分别进行了不同的修改。另外,即便在安装时没有发现冲突,由于没有进行严格的集成测试,运行过程中由于相互作用是否会发生意外也不能完全排除。
  除去修改功能和性能BUG的补丁,还有应对安全漏洞的安全补丁。Oracle公司定期(一年四期)发布安全补丁集,称之为CPU(Critical Patch Updates)。
  由于数据库在信息系统的核心地位,对其性能和安全性的要求非常高。理应及时安装所有重要补丁。另外一个方面,基于同样的理由,要求数据库系统必须非常稳定,安装补丁而导致的系统故障和性能下降同样不可接受。DBA经常面临一个非常困难的选择:对于多个修复重要BUG的个别补丁是否安装。不安装,失去预防故障发生的机会,以后故障发生时,自己是无作为;安装,如果这些补丁中存在着倒退BUG,或者相互影响,以后发生由于安装补丁而造成的故障时,自己则是无事生非!而等待下一个PSR,一般又需要一年时间。因此,出了PSU(Patch Set Update)
  三、Oracle 版本说明
  Oracle 的版本号很多,先看11g的一个版本号说明:
  注意:在oracle 9.2 版本之后, oracle 的maintenance release number 是在第二数字位更改。而在之前,是在第三个数字位。
  1. Major Database ReleaseNumber
  第一个数字位,它代表的是一个新版本软件,也标志着一些新的功能。如11g,10g。
  2. Database MaintenanceRelease Number
  第二个数字位,代表一个maintenancerelease 级别,也可能包含一些新的特性。
  3. Fusion Middleware ReleaseNumber
  第三个数字位,反应Oracle 中间件(Oracle Fusion Middleware)的版本号。
  4. Component-Specific ReleaseNumber
  第四个数字位,主要是针对组件的发布级别。不同的组件具有不同的号码。 比如Oracle 的patch包。
  5. Platform-Specific ReleaseNumber
  第五个数字位,这个数字位标识一个平台的版本。 通常表示patch 号。

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

仅列出标题
共394页: First 上一页 7 8 9 10 11 12 13 14 15 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜