??xml version="1.0" encoding="utf-8" standalone="yes"?>欧美成a人免费观看久久,国产精品蜜臀,97人澡人人添人人爽欧美http://www.aygfsteel.com/RongHao/category/4425.html勤学、勤?/description>zh-cnFri, 14 Dec 2012 08:19:34 GMTFri, 14 Dec 2012 08:19:34 GMT60年Pi的奇qL?我们的后台自动化发布Ҏhttp://www.aygfsteel.com/RongHao/archive/2012/12/14/393002.htmlronghaoronghaoFri, 14 Dec 2012 07:54:00 GMThttp://www.aygfsteel.com/RongHao/archive/2012/12/14/393002.htmlhttp://www.aygfsteel.com/RongHao/comments/393002.htmlhttp://www.aygfsteel.com/RongHao/archive/2012/12/14/393002.html#Feedback0http://www.aygfsteel.com/RongHao/comments/commentRss/393002.htmlhttp://www.aygfsteel.com/RongHao/services/trackbacks/393002.html一?/strong>我们要解决的问题

无论是什么样的解x案,一定要牢记我们要解决的问题是什么,切不能将解决Ҏ当做问题本n。具体到q程改进Q不是何种方式的改q,它们所要解决的问题永远只有一个:~短从品想法到可用软g之间的时间周?/strong>。自动化发布正是如此Q如果Y件发布只做一ơ,我们说根本不需要自动化Q但如果三次以上Q那么Y件开发的黄金法则DRY必遵守,让时间真正用到开发当中去?/span>

 

二?/strong>与发布相关的问题

所谓自动化只不q是原先手工做的工作谦让给机器做,所以自动化之前一定要先清楚与发布相关的问题有哪些Q即使不自动化,q些工作也一个也不能:

  1. 应用E序如何打包Q?/span> 发布包能否追t到SVN版本P
  2. 对目标机器环境有什么样的要求?
  3. 配置信息是否需要根据目标机器信息做_
  4. 应用E序如何安装和启动?
  5. 应用E序启动后如何切量Q?/span>
  6. 应用E序如何升Q?/span> 旧版本程序数据如何迁U?
  7. 升q程中和l束后如何切量Q?/span>
  8. 应用E序如何卸蝲Q?/span>

 

三?/strong>我们的方?/span>

李安的少q?/span>Pi正在狂刷房Q我们的自动化发布方案也要跟上潮:Puppet+CI我们的少q?/span>Pi?/span>

Ø 使用CI自动化打包,q踪每个发布包的SVN版本Q?/span>

Ø 使用Puppet理发布包、目标机器环境、应用程序配|信息以及应用程序线上生命周期;

Ø 使用伽利略系l提供应用程序的命名服务和进行流量切换?/span>

现在应用E序的发布需要两步:CI一键打包?/span>puppet指定应用E序版本SVN提交?/span>




 

四?/strong>具体Ҏ

具体Ҏ也就是如何解决与发布相关八个问题的过E?/span>

1.         如何安装、升U和卸蝲应用E序

我们使用操作pȝ原生包管理系l来安装、升U和卸蝲应用E序Q我们的应用E序打出RPM二进制包。免安装Q所有机器自带,l色的,有机的?/span>

打包Q?/span>rpm -ba ./team_member-1.spec

安装Q?/span>rpm –ivh team_ member-2.0.1-48.x86_64.rpm

升Q?/span>rpm –U team_ member-2.0.1-49.x86_64.rpm

卸蝲Q?/span>rpm –e team_ member-2.0.1-48.x86_64.rpm

E序升前要停旧版本服务怎么办?旧版本数据要做处理怎么办?RPM已经帮我们料理好q一切,只要写出spec文gQ剩下的交给我们。尽情的插入吧:


 

2.         如何理目标机器环境和应用配|信?/span>

应用E序已经打好rpm包了Q但q还不够Q应用程序发布到哪台机器上?应用E序对目标机器有什么要求?发布旉要修改哪些配|和参数Q实际发布如何执行,N需要登陆到每台目标机器q行rpm命o吗?

我们使用Puppet来搞定这一切,Puppet是现在应用第一?/span>devops工具Q它通过master/agent的工作模式管理机器。我们通过声明来控制我们的机器辑ֈ目标状态。同Ӟ所?/span>puppet文g全部?/span>SVN里,所有对机器的修改全?/span>codereview和可审计?/span>

 


如何理应用E序发布到哪台机器上Q在回答q个问题前我们必d应用E序在线上的生命周期再进行一ơ封装?/span>


应用E序TeamMember被我们封装成一?/span>puppet moduleQ配|文件和参数被封装在对应templates?/span>files里,每次发布前都要修攚w|文件和传递不同的参数Q?/span>out了吧Q?/span>puppet帮你传参搞定:


Teammember.conf文g内容Q?/span>


装完成后的效果是这LQ?/span>


最后在理部v?/span>site.pp文g里声明一下,应用E序TeamMember?/span>2146版本p自动部v?/span>10.128.34.141.test.back.shequq台机器上了Q我们后l的工作也就是维护这?/span>site.pp文g了,所有应用程序的部v信息都在SVN被集中管理v来:


登陆到每台目标机器运?/span>rpm命oQ?/span>No!现在TeamMember已经被封装,我们修改完毕site.ppq提交后Q?/span>puppetp动执行命令了Q要不怎么说是自动化呢。(现在puppet默认?/span>agent每半时同步一ơ,但同时支持马上触发执行)?/span>

 

3.         如何q踪每次发布?/span>SVN版本?/span>

我们使用CIq行应用E序的打包,?/span>build号作为包命名的一部分Q?/span>


 

4.         如何在发布过E中切换量

q是另外一个很大的话题Q参见伽利略计划?/span>

 

五?/strong>下一步工?/span>

使用CI环境的自动化部|与自动化测试串联v来,搭徏h个研发流E自动化q_Q?/span>


 

六?/strong>

没有银弹Q自动化所做的只是之前手工工作交l计机完成Q需要做的工作一个都不能,此外Q我们还要多做一些封装或脚本工作Q但是,当我们需要重复做q些事情的时候,价值就出现了。我们的目标永远是羃短从产品x到可用Y件之间的旉周期。让旉真正用到开发当中去?/span>



ronghao 2012-12-14 15:54 发表评论
]]>
一个项目的自动化测试实?/title><link>http://www.aygfsteel.com/RongHao/archive/2010/06/16/323669.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Wed, 16 Jun 2010 13:13:00 GMT</pubDate><guid>http://www.aygfsteel.com/RongHao/archive/2010/06/16/323669.html</guid><wfw:comment>http://www.aygfsteel.com/RongHao/comments/323669.html</wfw:comment><comments>http://www.aygfsteel.com/RongHao/archive/2010/06/16/323669.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/RongHao/comments/commentRss/323669.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/RongHao/services/trackbacks/323669.html</trackback:ping><description><![CDATA[<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-family: Arial, sans-serif, Helvetica, Tahoma; font-size: 12px; line-height: 18px; ">目上线Q有旉ȝ一下当前的目Q对自己而言Q一直是一个学习的q程。本ȝ我们的测试实c本文分5部分Q分别是Q项目背景、系l架构与模块划分、我们的试实践、自动化试在项目中的hg对自动化试的进一步思考?br /> <br /> <strong style="font-weight: bold; ">一、项目背?/strong><br /> 所有对目的介l一定是从客户开始?br /> <strong style="font-weight: bold; ">客户</strong>Q我们的客户是一家全球领先的时尚内容提供商,通过遍布全球的员工,客户每天获取大量关于时装发布、品设计、街Ҏ行、城市热点等信息Q这些信息的l大部分以图片的形式上传到公司服务器Q然后由专职~辑对这些图片进行整理和归类Q打标签Q,最后再p计h员根据这些信息书写分析报表?br /> <strong style="font-weight: bold; ">关键内容</strong>Q分cȝ致的量高清囄和具有前L的分析报表?br /> <strong style="font-weight: bold; ">商业模式</strong>Q网站,行业内用戯?付费?br /> <strong style="font-weight: bold; ">客户面的问?/strong>Q同质化竞争、客h失?br /> <strong style="font-weight: bold; ">新系l的关键?/strong>QCMS、更_的内容分cR更好的全文索、更好的用户体验Q更有表现力的内容展玎ͼ、更快的内容发布?br /> <br /> <strong style="font-weight: bold; ">二、系l架构与模块划分</strong><br /> <strong style="font-weight: bold; ">1、REST的架构风?/strong><br /> pȝ采用了Sling作ؓWEB框架QJCR作ؓ了底层内容存储框架?br /> pȝ的特点:<br /> <strong style="font-weight: bold; ">URI唯一标识资源</strong><br /> 通过URI能够直接映射到JCR节点Q例如http://localhost:80/content/section/news.html能够映射到JCR里的/content/section/news节点<br /> <br /> <strong style="font-weight: bold; ">GET/POST/DELETE标准Ҏ对资源进行操?/strong><br /> 支持标准Ҏ对资源的直接操作<br /> <br /> <strong style="font-weight: bold; ">资源的多重表q?/strong><br /> 同一资源可以存在多种表述形式Q例如http://localhost:80/content/section/news.html展现|页Q?/p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-family: Arial, sans-serif, Helvetica, Tahoma; font-size: 12px; line-height: 18px; ">http://localhost:80/content/section/news.json展现资源信息的JSON描述Q?br /> http://localhost:80/content/section/news.pdf展现|页的PDF?br /> <br /> <strong style="font-weight: bold; ">服务器端的无状?/strong><br /> 通过JS获取当前用户信息q缓存在客户端?br /> <br /> 2?strong style="font-weight: bold; ">pȝ分层</strong><br /> pȝ分ؓ四层QJS、Servlet、Domain Model和JCR?br /> 因ؓJCR提供了一套节Ҏ型,所以Domain Model是在节点模型上的行ؓ增强Q例如所有对囄节点的操作我们封装在Asset领域模型里?br /> <img src="http://dl.javaeye.com/upload/attachment/260171/a677675f-f108-3d61-b522-1b435ec0e6f4.png" alt="pȝ分层" width="625" height="401" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; " /><br /> <br /> <strong style="font-weight: bold; ">3、程序划?/strong><br /> E序分ؓ两个大的模块Q?strong style="font-weight: bold; ">Migration和Bundles</strong>。ؓ什么叫BundlesQ因为Sling使用了OSGI框架Felix?br /> Migration负责导入客户的遗留数据到新系l。之前客LCMSq行已有10多年的时_U篏有大量数据。主要是各种cd的报表和囄?br /> Bundles实现pȝ功能。主要包括了定义报表模板、定义报表各U所见即所得的展现lg、实现对囄的管理、搜索(包括Z囄的可视化搜烦Q和其他七七八八?br /> <br /> <strong style="font-weight: bold; ">三、测试实?br /> 1、Migration的测?br />   自动化测?/strong><br /> 对MigrationQ我们采用了TDD的方式?br /> 输入是客户实际提供的xml文gQ输出是JCR里的节点。测试环境的搭徏主要是在本地建立起Jackrabbit实例。我们的工作方式是这P每天早上领到一张migration故事卡,然后先写一个xml到jcr节点的集成测试描q出该类型报表的功能需求,接下来就是让q个试通过。经q开始阶D늚熟悉q程Q我们的速度保持在一对Pair一天一U报表类型的导入?br /> <br />    <strong style="font-weight: bold; ">手工试</strong><br /> xml文g内容正常解析q导入JCR只是W一步,W二步我们需要在Bundles里ؓ该类型的报表~写模板使之正常展现。由于涉及到报表样式Q这个测试我们采用手工测试,q个工作也是QA工作的重要一部分?br /> 在最开始的开发中Q我们没有导入所有报表数据进行测试。这带来了问题,׃客户遗留数据跨越10多年Q各U数据Ş式都可能存在Q特别是04q以前数据,lUI带来了很大挑战)Q而最开始的开发中Q我们只是用了部分数据Q?9?0q数据)q行试Q这个导致了建立UAT环境时程序的很多q工以及QA的测试压力?br /> <br /> <strong style="font-weight: bold; ">2、Bundles的测?br /> 自动化测?/strong><br /> 寚w域模型,我们采用了TDD的方式进行单元测试;在本地Jackrabbit实例里徏立数据,领域模型装数据试行ؓ?br /> 对servletQ我们采用了TDD的方式进行集成测试(同时试了servlet和领域模型)Q在试中对request和responseq行mockQ?br /> 对JSQ我们用数据驱动的selenium功能试q行覆盖?/p> <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-family: Arial, sans-serif, Helvetica, Tahoma; font-size: 12px; line-height: 18px; "><img src="http://dl.javaeye.com/upload/attachment/260173/14882852-ea15-3302-929f-708e92146619.png" alt="试覆盖" width="631" height="405" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; " /><br /> <br /> 我们最后的自动化测试结构:<br /> <img src="http://dl.javaeye.com/upload/attachment/260175/ece5188b-cef1-31cd-a490-574db3d22fc5.png" alt="试的分? width="490" height="335" style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; " /><br /> <br /> <strong style="font-weight: bold; ">手工试</strong><br /> 手工试内容主要是功能测试?br /> 自动化测试hg的部分我们采用手工测试,q部分内容包括报表模板,相对独立Q内容不多,一ơ测试处处通过Q?br /> 自动化测试成本高的部分我们采用手工测试,q部分内容包括报表展现组件的~辑功能Q因为采用了Ext JSQ所以自动化试困难Q?br /> 无法自动化的试Q报表在U生成PDFQ报表样式,WEBDEV扚w上传囄{?<br /> <br /> <strong style="font-weight: bold; ">我们与QA的约定:</strong><br /> 每完成一个用h事,我们会与QA、BA一起mini showcaseQ?br /> QA验收完成后编写功能测试用例;<br /> 我们对QA~写的功能测试用例进行自动化Q共同维护一个功能测试列表;<br /> 对于不能自动化或自动化hg高的试用例QAl箋使用手工试?br /> <br /> <strong style="font-weight: bold; ">四、我们感受到的自动化试价?/strong><br /> 1、通过自动化功能测试,我们使得需求对客户可视化;<br /> 2、QA的回归测试成本降低,管目前频繁的向客户实际使用环境部vQ但QA每次部v只需要做一些简单的冒烟试Q?br /> 3、测试即需求,q点在TDD的开发过E中感觉非常明显Q今天开发的目的是使这个测试通过Q避免了频繁部v到应用中q行试Q最快的甉|不是速度最快的甉|Q而是中间停的楼层最的甉|Q?br /> 4、与持箋集成一P及时反馈。这点在q行JS代码~写Ӟ心理上都非常依赖于selenium试Q对于没有测试覆盖的地方Q没有安全感Q?br /> 5、够的单元、集成测试保证了频繁重构Q没有h愿意引入BUGQ没有够的试Q没人愿意重构;<br /> 6、测试即文档Q良好的试和命名,使得新加入的成员非常Ҏ理解当前代码的功能?br /> <br /> <strong style="font-weight: bold; ">五、思考和讨论</strong><br /> <strong style="font-weight: bold; ">1、自动化功能试做到多少才合适?</strong><br /> 当然是越多越合适,问题在于自动化功能测试成本要大大高于单元试和集成测试,q些成本反映在测试环境的搭徏、数据的准备Q需要准备其他很多关联数据例如用户信息和权限信息、自动化功能试的运行时间长、稳定性(随机成功/p|Q、编写等{,需要权衡成本与收益?br /> 个h认ؓQ自动化功能试需要考虑的着重点包括Q页面是否包含大量功能交互性JSQ与展现性JS相对Q?当前功能是否与其他功能共享一些代码?即独立性,独立性越低越需要着重覆盖(q里又涉及到另外一个问题,即从各个模块里重构出q代码是否L合适?Q。QA每次冒烟试时是否需要重复回归(重复回归ơ数多Q自动化有价|Q经常失败的试一定比不失败的试价值更高?或者从未失败过的测试就没有价|<br /> <br /> <strong style="font-weight: bold; ">2、单元测试?功能单元试Q?/strong><br /> TDD的测试粒度多大才合适?从我个h而言Q几乎天然的反对mockQؓ了满x试覆盖率的追求,强制两个联pd紧密的类分开Q做出各式各样mockQ这真让人气馁;stub也不是什么好东西Q在一个曾l的spring目里,在测试目录里Q一堆一堆的试xml配置文g让h有种呕吐的感觉。那做集成试吧,两个cdpd好,那么整体测试它们的输入和输出,看v来很不错Q功能实CQ测试也没多写,也不用准备太多其他东西,但是打开实现代码Q你发现那个丑陋,到处是复制和_脓Q是啊,不管黑猫白猫抓住老鼠是好猫Q只x了当前结果,完全失去了TDD驱动单设计的好处?br /> <br /> <strong style="font-weight: bold; ">3、测试的重点是测试用例的设计Q它反映出对需求的理解</strong><br /> 那么l论很明显Q我们如果连需求就没有理解Q如何进行实玎ͼ所以测试驱动是很自然的?/p> <img src ="http://www.aygfsteel.com/RongHao/aggbug/323669.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/RongHao/" target="_blank">ronghao</a> 2010-06-16 21:13 <a href="http://www.aygfsteel.com/RongHao/archive/2010/06/16/323669.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>心理学,再谈好代?/title><link>http://www.aygfsteel.com/RongHao/archive/2010/03/21/316100.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Sun, 21 Mar 2010 14:27:00 GMT</pubDate><guid>http://www.aygfsteel.com/RongHao/archive/2010/03/21/316100.html</guid><wfw:comment>http://www.aygfsteel.com/RongHao/comments/316100.html</wfw:comment><comments>http://www.aygfsteel.com/RongHao/archive/2010/03/21/316100.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.aygfsteel.com/RongHao/comments/commentRss/316100.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/RongHao/services/trackbacks/316100.html</trackback:ping><description><![CDATA[<p>什么代码才是好代码Q这真是个老得能拔掉牙齿的话题。好吧,那让我们再在q刮沙尘暴的无聊时光里重复一ơ。好的代码要是易ȝ代码、要做到职责分离、要做到单一职责、要有高的执行效?...<br /> <br /> {等Q等{,q才抽象了,太书面化了。我只是一个菜鸟,刚写代码几年Q也没念q什么书Q能不能说得通俗易懂一些?<br /> <br /> 好吧Q我停下来,惻Iq真是个隄的家伙。我_q样吧,我推荐几本书你去看吧Q《重构》熊节最q再版了Q徏议你M一本。恩Q等{,有个省钱的招Q去囄׃部讨论组注册下,y赠书也很爽Q哈哈?br /> <br /> 可是Q你q没告诉我什么代码才是好代码呢?知道你也没什么好{案Q我自己来说好了?br /> <br /> 省略掉此时我内心p的汗_下面是菜鸟的叙述Q?br /> <br /> <strong>1.一?/strong><br /> 我发现自己有d的强q症Q当我碰C下代码时Q我׃冲动?br /> 冲动前代码:<br /> def imgName<br /> if(XXX){<br />    imgName="meigui"<br /> }else{<br />    imgName=""<br /> }<br /> 冲动后代码:<br /> def imgName=XXX?"meigui":""<br /> <br /> 管两段代码功能一_但一旦我发现出现冲动前代码时Q我׃感到不舒服,感到隑֏Q就好像看到阅兵正步C齐一栗方法名也是一P<br /> 冲动前:<br /> def testXXX(){}<br /> 冲动后:<br /> def should_XXX_when_XXX(){}<br /> <br /> 变量亦是如此:<br /> 冲动前:<br /> def imgNode=resouce.adoptTo(Node)<br /> 冲动后:<br /> def node=resouce.adoptTo(Node)<br /> <br /> MQ我不愿意看到同一个事情有两种实现方式Q如果功能类|那么不管是逻辑q是变量、方法名Q我会强q一_整齐划一?br /> <br /> 关于一_从调试代码的角度看,零星的不一致比大量的不一致更加糟p,因ؓq时大部分地方的一致性会令hȝ大意。在实现查询分页功能Ӟ我们有这样一行代码:<br /> nodeIterator.size<br /> q行代码的意思是获取查询l果的LQ大部分情况下它工作良好Q但是在一U特D情况下它返回了-1。这Ҏ当时几乎是灾难性的Q因试过E中我们始终怿q行代码的行Z_l果是花费了一个下午才扑ֈq个问题?br /> <br /> <strong>2.z?/strong><br /> 我喜Ƣ短的代码,Ҏ而言Q短的程序L比更长一些的代码Ҏ理解Q小学时学课文就已经q样了,一看到大段的段落我L会晕q去Q特别是文言文,首先我就 对自q解这D|字失M信心Q。这里要提到注释Q即是这些注释明是Z提高代码的可L,也会增加我阅M码的困难Q所以我不会在方法里的Q何位|添 加注释,撑死在个别方法声明前dQƈ且这U情况也量避免Q如果这个类实包含了重要的不易理解的算法,我也只会在类声明前添加注释?br /> <br /> 关于自然语言Q有一个基于经验的l论被称为Zipf定律Q即Q自然语a中最常用到的单词Q其长度会趋于最短?br /> <br /> 我写代码的时候,能够写尽量简写,例如Q变量名QimageNodeQ我一定会写成imgNodeQ方法名procedureXXX,我一定会写成 procXXX,和讨厌大D代码一P我非常讨厌命名很长的Ҏ名和变量名,管q些名称q么长是Z更好的增加可L,但可L不是这样增加的?br /> <br /> 在我的第一份代码工作里Q我们用拼x命名Ҏ和变量(q好Q没有包括类名)Q我讨厌q种命名方式的原因ƈ不是因ؓ我的语文老师不好以至于我前后鼻音不分Q而是q种写法Ҏ排除了简写的可能性,甚至Qؓ了避免歧义,有时不得不变得更ѝ?br /> <br /> <strong>3.联觉和顺?/strong><br /> 关于记忆QhcL两种重要的记忆能力:联觉和顺序记忆?br /> <br /> 关于联觉Q一个例子是Q你d以一D住一个h的脸Q比如范冰冰Q尽我到现在也不清楚她到底是单眼皮q是双眼皮,也不清楚她到底是厚嘴唇还是薄嘴唇?br /> <br /> 那么Q在代码里,q里的表现就是局部,即一个功能的所有相关代码都集中在一个地斏V我最讨厌的代码是q样的:最开始我打开一个文Ӟ在阅ȝq程中,我发 C个不清楚的方法,于是我按下ctrlq点击鼠标,于是我蟩到另外一个文Ӟ接下来,在阅d外一个方法里Q我再次发现了一个不清楚的方法,于是我再? 按下ctrlq点击鼠标,哇哈Q新的文件打开?...如此反复Q终于当我打开最后一个文件时Q我发现IDE的文件条里已l密密麻ȝ排满了好几排文gQ? 于是Q我Ud鼠标Q右键,弹出一个关闭菜单,我选择了close othersQ瞬_哦米拖佛Q整个世界清静了Q但是,{等Q我最初是打算q嘛来着Q?br /> <br /> 所以,h所有相兌的代码都集中在一个地方,求您了。哦Q对了,能不用接口请不要用接口,M到q样的情况,打开好几排的文gQ接口文件占了一半,我靠Q少几个接口会死啊。对了,q可能是您的一致性心理在作怪,对不P对不赗?br /> <br /> 关于局部,一个范例同样与调试有关Q在很久之前的一ơ调试中Q我们始l找不到一个变量错误的原因Q因为在q段代码里,Ҏ找不CQ何错误,很久以后Q终? 发现Q这个变量竟然是个全局变量Q嘿嘿,告诉你吧Q这个变量在servlet里,04q的时候,|上很火的一文章,标题是Q不要在servlet里 用全局变量Q?br /> <br /> 关于序Q最典型的例子出现在高中化学里,我M不能瞬间说出W?2?3个化学元素是什么,我通常会这栯忆:氢氦锂铍碳氮氧氟氖钠镁铝硅P啊哈Q第12个元素是镁,W?3个元素时铝,合v来就?-女Q?br /> <br /> 所以,在代码里Q请互相调用的Ҏ按顺序摆放,Ҏ1先调用了Ҏ2Q那么请方?紧放在方?后边。我讨厌q样的配|:打开Ҏ1Q发现其调用了方 ?Q点L?Q编辑器里的滚动条瞬间从最上端滚到最下端Q紧接着Q滚动条又从最下端滚动C_再接着Q又是最下端Q接着Q归零到最上端....人生 l不赯L大v大落Q真的,那得要多么大的心脏啊Q麦蒂才有过那么一ơ,13U?...<br /> <br /> q有Q知道ؓ什么gotoZ么那么臭名昭著了吧?br /> <br /> <strong>4.自然</strong><br /> 使得代码hL的表达方式,同时把错误率降到最低,一U最重要的方法就是代码变?#8220;自然”Q即向自然语a靠拢。因Z码ƈ不仅仅是与机器交的Q更重要的是Q需要在Z间交?br /> <br /> 机器语言到高U语aQ面向过E语a到面向对象语aQjdbc到hibernateQjava到动态语aQ这些都促代码变得更加自然?br /> <br /> Ruby里有个不L的特性,是Ҏ调用不用再写括号Q这一Ҏ是如此的微不道但是却被很多hz|乐道Q原因就是它更加自然Q更加脓q我们的自然语言。于是,我看刎ͼ我的同事晓娜Q在groovy里,一遍遍的将她力所能及的括号去掉?br /> <br /> 此外Q程序语a和自然语a是有区别的,除了不能在代码里利用感情词抒发情感之外(我想Q如果可以,一定会看到很多的冯特)Q程序语a没有口语。很看到程 序员之间q样交流Q来吧,我们来说D代码(当然也有Q徐昊就可以Q哈哈)Q他们更多的会用白板和W或者直接是~辑器。所以,l束招聘时是否需要笔试的? 论吧Q我真ؓ那些不经q笔试就直接招h的公司感到羞愧,因ؓ他们Ҏ׃懂程序语a?br /> <br /> 此处省略华丽的分割线?br /> <br /> 此文谢谢我们目lWGSN的激烈讨论,谢谢讨论中徐昊的_ֽ点评?/p> <img src ="http://www.aygfsteel.com/RongHao/aggbug/316100.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/RongHao/" target="_blank">ronghao</a> 2010-03-21 22:27 <a href="http://www.aygfsteel.com/RongHao/archive/2010/03/21/316100.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据驱动试http://www.aygfsteel.com/RongHao/archive/2010/01/17/309837.htmlronghaoronghaoSun, 17 Jan 2010 04:08:00 GMThttp://www.aygfsteel.com/RongHao/archive/2010/01/17/309837.htmlhttp://www.aygfsteel.com/RongHao/comments/309837.htmlhttp://www.aygfsteel.com/RongHao/archive/2010/01/17/309837.html#Feedback0http://www.aygfsteel.com/RongHao/comments/commentRss/309837.htmlhttp://www.aygfsteel.com/RongHao/services/trackbacks/309837.html
最开始我们需要验证在用户名和密码都正的情况下,能够正常dpȝQ我们这L写测试代码(以下都是伪代码,使用TestNG和SeleniumQ:

@Test
def should_login_success_with_exist_username_and_correct_password(){
    LoginPage page 
= user.open(LoginPage,"/login.html")
    user.perform(
"login",['user1','1234'],on(page))
    
assert page.successLogin
}


恩,很不错,q行一下,出现U条。ؓ什么呢Q原来测试数据库里没有用户名为user1的用P好吧Q写个数据库数据初始化脚本。再q行QOKQ绿条!

那么Q接下来我们再增加一个测试,需要覆盖密码错误时不能dpȝ的情况,很快试完成了Q?br />

@Test
def should_login_success_with_exist_username_and_incorrect_password(){
    LoginPage page 
= user.open(LoginPage,"/login.html")
    user.perform(
"login",['user1','4321'],on(page))
    
assert page.successLogin,false
}


再运行一下测试,l条。好啦,现在可以看下q段代码Q恩Q有些重复,重构一下:

@Test
def should_login_success_with_exist_username_and_correct_password(){
    
assert login('user1','1234')
}

@Test
def should_login_success_with_exist_username_and_incorrect_password(){
    
assert login('user1','4321'),false
}

def login(username,password){
    LoginPage page 
= user.open(LoginPage,"/login.html")
    user.perform(
"login",[username,password],on(page))
    
return page.successLogin
}


重构完成Q可以看刎ͼ我们的测试方法里现在没有了Q何行为,仅仅是数据!q样让我感觉有点怪,不管了,先用TestNG提供的@dataProvider整理一下:

@Test(dataProvider="testdata")
def testLogin(username,password,expected){
    LoginPage page 
= user.open(LoginPage,"/login.html")
    user.perform(
"login",[username,password],on(page))
    
assert page.successLogin,expected
}

@DataProvider(name
="testdata")
def Object[][] dataForLogin(){
    def data
=new Object[2][]
    data[
0]=['user1','1234',true] as Object[]
    data[
1]=['user1','4321',false] as Object[]
}


试Ҏ只剩下了一个!如果要测试不存在的用户不能登录系l呢Q很单,增加数据卛_Q?br />
@DataProvider(name="testdata")
def Object[][] dataForLogin(){
    def data
=new Object[2][]
    data[
0]=['user1','1234',true] as Object[]
    data[
1]=['user1','4321',false] as Object[]
    data[
1]=['inexistuser','1234',false] as Object[]
}


在我们的试Ҏ里,试数据和测试的行ؓq行了完全的分离。从pȝ的功能来_功能一旦实玎ͼ那么是一个黑盒,我们只要提供数据卛_q行试Q这个数据包括两部分Q输入和期待的输出。我开始暗自嘀咕:N我以前那么多的洋z得意测试方法很多都是不需要的吗?q些方式Z么会存在呢?恩,惌v来了Q这些方法是Z覆盖功能的各个\径的Q是提高试覆盖率的。那么ؓ什么会产生q么多的试Ҏ呢?哦,在这些测试方法里Q测试数据和试行ؓ是耦合在一LQ?br />
我了个懒腰Q突然想Q这下好了,我已l封装好了功能行为,QA惛_加测试用例只需要自己增加数据就可以了,嘿嘿Q爽啊。说ҎQQA到。QA mm_你的某个功能实现有问题。我瞅了一|_不可能啊Q这是dev面对bug的第一反应Q,俺有试的,持箋集成一直是l条的。QA mm_在你的开发环境下试是没有问题的Q但是在QA环境Q因为数据库变了Q数据变了,应用服务器变了,所以会有些问题。我极不情愿的登录到QA环境Q一试Q还真是Q郁闗?br />
怎么办?修复完BUGQ第一反应是自动化测试能不能跑在QA环境呢?一般情况下Q这些测试需要干净的测试环境,我们会制造很多的试数据Q可是在QA环境下,QA有她自己的测试数据,q些数据都不存在了哈。恩Q看看刚才的试代码Q哈Q就用QA的数据也可以啊,心情愉悦的改下:

@DataProvider(name="testdata")
def Object[][] dataForLogin(){
    def data
=new Object[2][]
    data[
0]=['hrong','1234',true] as Object[]
    data[
1]=['hrong','4321',false] as Object[]
    data[
1]=['rhao','1234',false] as Object[]
}


OK,完成Qؓ了该试既能在开发测试环境运行又能在QA环境下运行,我们可以引入一个环境变量,测试数据扔到文仉Q通过环境变量来加载不同的试数据Q测试文Ӟ?br />
好吧Q喝点东西(甲流很厉宻I喝板蓝根好了Q,ȝ一下:

数据驱动试Q?strong>试数据与测试行为分,通过数据来驱动测试?/strong>

好处Q?strong>在对试行ؓ装好的情况下,QA mm能够自己通过数据修改自动化测试;
      自动化测试能够运行在多个环境下(开发环境、QA环境、品环境)
      试的可L?br />       试Ҏ大量压羃


适用范围Q?strong>功能试Qselenium试Q?br />           通过环境准备试数据Q非试用例自己准备数据Q?/strong>

可能存在的问题:比一般的试~写困难Q特别是在静态语a?/strong>

最后:该文章的思考来自于徐昊在团队内部的相应Session.






ronghao 2010-01-17 12:08 发表评论
]]>
使用Selenium试showModalDialog模态对话框http://www.aygfsteel.com/RongHao/archive/2009/07/27/288640.htmlronghaoronghaoMon, 27 Jul 2009 13:17:00 GMThttp://www.aygfsteel.com/RongHao/archive/2009/07/27/288640.htmlhttp://www.aygfsteel.com/RongHao/comments/288640.htmlhttp://www.aygfsteel.com/RongHao/archive/2009/07/27/288640.html#Feedback0http://www.aygfsteel.com/RongHao/comments/commentRss/288640.htmlhttp://www.aygfsteel.com/RongHao/services/trackbacks/288640.html阅读全文

ronghao 2009-07-27 21:17 发表评论
]]>
QMulti-stage Continuous IntegrationQ多阶段持箋集成http://www.aygfsteel.com/RongHao/archive/2009/05/26/278114.htmlronghaoronghaoTue, 26 May 2009 15:13:00 GMThttp://www.aygfsteel.com/RongHao/archive/2009/05/26/278114.htmlhttp://www.aygfsteel.com/RongHao/comments/278114.htmlhttp://www.aygfsteel.com/RongHao/archive/2009/05/26/278114.html#Feedback0http://www.aygfsteel.com/RongHao/comments/commentRss/278114.htmlhttp://www.aygfsteel.com/RongHao/services/trackbacks/278114.html一、目前的情况

目前我们要进行持l集成的对象是一个有着100人左右的开发团队,他们开发着一套很庞大的系l。整个开发团队划分ؓ多个开发小l进行协同开发,每个开发小l负?-3个模块的开发,实际q里的模块已l相当于一个中型pȝ。各模块所有的c都通过eclipse整体~译在一P直接攄在WEB-INF/classes下。本地是无法启动整个pȝ的,需要耗费大量的资源?br />
二、碰到的问题
在了解具体情况之前,我们最初的x是ؓ整个产品做一个持l集成,但是很快发现这一x存在很多的问题:
1、整个品每ơ构建的旉会很长,q个旉包括代码的编译、启动WeblogicQ完成自动化试Q同时对服务器的g要求非常?br /> 2、因为构建时间长Q所以如果本地构建通过后再提交会严重媄响开发效率,况且本地的硬件条件很可能启动不了
3、如果本C构徏提交Q则׃开发hC多,构徏会非怸E_Q会l常处于p|状态。而构建失败会D后箋提交的阻塞?br /> 4、作Z?00人的开发团队,代码提交会引发频J的服务器构建,服务器无法负担?br />
同时作ؓ客户Q他们有q样一U想法:敏捷开发是好的Q但是不适合于大的项目和大的团队?br />
最重要的问题集中在两个斚wQ?br /> 1、启动整个品过于重量Q不包括自动化测试的情况下已l如此)
2、如何不影响开发h员的频繁提交

三、我们的x
我们现在的想法是做多阶段的持l集成(multi-stage CIQ?br />
可以参考这?a target="_blank">http://www.ddj.com/development-tools/212201506

具体而言Q?br /> 1、各个开发小l内做小l内的持l集?br /> 2、开发小l间集成做整个品的持箋集成


大概Q?br /> 1、每个开发小l一个分支,整个产品一条主U?br /> 2、在组分支上搭建持l集成环境,组内的开发向该分支上提交Q各个小l可以ƈ发开发,互不影响
3、小l完成一个完整的功能后,从主U更新合q代码,本地构徏通过Q提交,触发整个产品的持l集?br />
Zɞ组内持l集成构建加快,组内尽量划分清楚对其他模块的依赖,不必要的模块Q这里的模块包括基础模块Q例如工作流模块Q不必加载?br /> 同时推荐轻量U的web服务器例如Tomcat来完成小l内的测试环境。需要启动weblogic的情冉|功能依赖q多的情况下Q徏议在产品持箋集成时进行测试?br /> 同时保留原有的启动单独测试服务器q行手工试的习惯?br />

ronghao 2009-05-26 23:13 发表评论
]]>Zmemcached的SNA实现http://www.aygfsteel.com/RongHao/archive/2008/10/28/237207.htmlronghaoronghaoTue, 28 Oct 2008 12:41:00 GMThttp://www.aygfsteel.com/RongHao/archive/2008/10/28/237207.htmlhttp://www.aygfsteel.com/RongHao/comments/237207.htmlhttp://www.aygfsteel.com/RongHao/archive/2008/10/28/237207.html#Feedback3http://www.aygfsteel.com/RongHao/comments/commentRss/237207.htmlhttp://www.aygfsteel.com/RongHao/services/trackbacks/237207.htmlpȝ要集,使用SNAҎ?br /> 一?~存的处?/strong>
~存要用统一的缓存服务器Q集中式~存?br /> 原先的实现采用ehcache?br /> 在spring里的配置Q以资源~存ZQ?/p>
<!-- EhCache Manager -->
    
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        
<property name="configLocation">
            
<value>classpath:ehcache.xml</value>
        
</property>
</bean>

<bean id="resourceCacheBackend"
          class
="org.springframework.cache.ehcache.EhCacheFactoryBean">
        
<property name="cacheManager" ref="cacheManager"/>
        
<property name="cacheName" value="resourceCache"/>
    
</bean>

    
<bean id="resourceCache"
          class
="com.framework.extcomponent.security.authentication.services.acegi.cache.EhCacheBasedResourceCache"
          autowire
="byName">
        
<property name="cache" ref="resourceCacheBackend"/>
    
</bean>


cacheManager负责对ehcacheq行理Q初始化、启动、停止?br /> resourceCacheBackend负责实际执行~存操作Qput 、get、remove?br /> resourceCache实现h业务语义的业务应用层面的~存操作Q内部调用resourceCacheBackend操作?br />
现在采用memcached?br /> 关于客户端,采用文初装的客LQ地址?a mce_>http://code.google.com/p/memcache-client-forjava/?br /> 使用spring的FactoryBeanq行二次装。同理:
memcachedManager负责对memcachedq行理Q初始化、启动、停止?br /> 代码Q?/p>

/**
* User: ronghao
* Date: 2008-10-14
* Time: 10:36:30
* 理Memcached 的CacheManager
*/
public class MemcachedCacheManagerFactoryBean implements FactoryBean, InitializingBean, DisposableBean {

    
protected final Log logger = LogFactory.getLog(getClass());

    
private ICacheManager<IMemcachedCache> cacheManager;

    
public Object getObject() throws Exception {
        
return cacheManager;
    }

    
public Class getObjectType() {
        
return this.cacheManager.getClass();
    }

    
public boolean isSingleton() {
        
return true;
    }

    
public void afterPropertiesSet() throws Exception {
        logger.info(
"Initializing Memcached CacheManager");
        cacheManager 
= CacheUtil.getCacheManager(IMemcachedCache.class,
                MemcachedCacheManager.
class.getName());
        cacheManager.start();
    }

    
public void destroy() throws Exception {
        logger.info(
"Shutting down Memcached CacheManager");
        cacheManager.stop();
    }
}
 

配置Q?/p>


<bean id="memcachedManager"
          class
="com.framework.extcomponent.cache.MemcachedCacheManagerFactoryBean"/>

 

resourceCacheBackend负责实际执行~存操作Qput 、get、remove?br /> 代码Q?/p>

/**
* User: ronghao
* Date: 2008-10-14
* Time: 10:37:16
* q回  MemcachedCache
*/
public class MemcachedCacheFactoryBean implements FactoryBean, BeanNameAware, InitializingBean {

    
protected final Log logger = LogFactory.getLog(getClass());

    
private ICacheManager<IMemcachedCache> cacheManager;
    
private String cacheName;
    
private String beanName;
    
private IMemcachedCache cache;

    
public void setCacheManager(ICacheManager<IMemcachedCache> cacheManager) {
        
this.cacheManager = cacheManager;
    }

    
public void setCacheName(String cacheName) {
        
this.cacheName = cacheName;
    }

    
public Object getObject() throws Exception {
        
return cache;
    }

    
public Class getObjectType() {
        
return this.cache.getClass();
    }

    
public boolean isSingleton() {
        
return true
    }

    
public void setBeanName(String name) {
        
this.beanName=name;
    }

    
public void afterPropertiesSet() throws Exception {
        
// If no cache name given, use bean name as cache name.
       if (this.cacheName == null) {
        
this.cacheName = this.beanName;
    }
        cache 
= cacheManager.getCache(cacheName);
    }
}

配置Q?/p>

<bean id="resourceCacheBackend"
          class
="com.framework.extcomponent.cache.MemcachedCacheFactoryBean">
        
<property name="cacheManager" ref="memcachedManager"/>
        
<property name="cacheName" value="memcache"/>
    
</bean>
  resourceCache同上Q替换新的实现类MemcachedBasedResourceCache卛_?br />

二?Session失效的处?/strong>
采用memcached作ؓhttpsession的存储,q不直接保存httpsession对象Q自定义SessionMapQSessionMap直接l承HashMapQ保存SessionMap?br />
会话胶粘Q未p|转发的情况下没必要在memcached保存的SessionMap和httpsession之间复制来复制去Q眉来眼厅R?br />
利用memcached计数器保存在Uh数?br />
pȝ权限采用了acegiQ在acegi的拦截器N配置snaFilter

<bean id="filterChainProxy"
          class
="org.acegisecurity.util.FilterChainProxy">
        
<property name="filterInvocationDefinitionSource">
            
<value>
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
                /**=snaFilter,httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,exceptionTranslationFilter,filterInvocationInterceptor
            
</value>
        
</property>
</bean>


注意需要配|在W一个?br /> snaFilter的职责:
1?没有HttpSessionӞ创徏HttpSession;
2?创徏Cookie保存HttpSession id;
3?如果Cookie保存的HttpSession id与当前HttpSession id一_说明是正常请求;
4?如果Cookie保存的HttpSession id与当前HttpSession id不一_说明是失败{发;p|转发的处理:
     4.1、根据Cookie保存的HttpSession id从memcached获取SessionMapQ?br />      4.2、SessionMap属性复制到当前HttpSessionQ?br />      4.3、memcached删除SessionMap?br /> 5?判断当前hurl是否是登出urlQ是则删除SessionMapQ在Uh数减1.

代码Q?/p>

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) 
throws IOException, ServletException {
        
final HttpServletRequest hrequest = (HttpServletRequest) servletRequest;
        
final HttpServletResponse hresponse = (HttpServletResponse) servletResponse;
        String uri 
= hrequest.getRequestURI();
        logger.debug(
"开始SNA拦截-----------------" + uri);
        HttpSession httpSession 
= hrequest.getSession();
        String sessionId 
= httpSession.getId();
        
//如果是登?则直接干掉sessionMap
        if (uri.equals(logoutUrl)) {
            logger.debug(
"remove sessionmap:" + sessionId);
            
//在线人数?
            getCache().addOrDecr("userCount",1);
            getCache().remove(sessionId);
        } 
else {
            String cookiesessionid 
= getSessionIdFromCookie(hrequest, hresponse);
            
if (!sessionId.equals(cookiesessionid)) {
                createCookie(sessionId, hresponse);
                SessionMap sessionMap 
= getSessionMap(cookiesessionid);
                
if (sessionMap != null) {
                    logger.debug(
"fail over--------sessionid:" + sessionId + "cookiesessionid:" + cookiesessionid);
                    initialHttpSession(sessionMap, httpSession);
                    cache.remove(cookiesessionid);
                }
            }
        }
        filterChain.doFilter(hrequest, hresponse);
}

利用HttpSessionAttributeListener监听httpsession的属性变?同步到memecached中的sessionmap?
public void attributeAdded(HttpSessionBindingEvent event) {
        HttpSession httpSession 
= event.getSession();
        String attrName 
= event.getName();
        Object attrValue 
= event.getValue();
        String sessionId 
= httpSession.getId();
        logger.debug(
"attributeAdded sessionId:" + sessionId + "name:" + attrName + ",value:" + attrValue);
        SessionMap sessionMap 
= getSessionMap(sessionId);
        
if (sessionMap == null){
            
//在线人数?
            getCache().addOrIncr("userCount",1);
            sessionMap 
= new SessionMap();
        }
        logger.debug(
"name:" + attrName + ",value:" + attrValue);
        sessionMap.put(attrName, attrValue);
        getCache().put(sessionId, sessionMap);
    }

    
public void attributeRemoved(HttpSessionBindingEvent event) {
        HttpSession httpSession 
= event.getSession();

        String attrName 
= event.getName();
        String sessionId 
= httpSession.getId();
        logger.debug(
"attributeRemoved sessionId:" + sessionId + "name:" + attrName);
        SessionMap sessionMap 
= getSessionMap(sessionId);
        
if (sessionMap != null) {
            logger.debug(
"remove:" + attrName);
            sessionMap.remove(attrName);
            getCache().put(sessionId, sessionMap);
        }
    }

    
public void attributeReplaced(HttpSessionBindingEvent event) {
        attributeAdded(event);
    }

 
利用HttpSessionListenerQsessionDestroyed事g时根据sessionid删除memcached里的sessionMapQ如果存在)。不再担心httpsession的过期问题?
public void sessionDestroyed(HttpSessionEvent event) {
        HttpSession httpSession 
= event.getSession();
        String sessionId 
= httpSession.getId();
        logger.debug(
"session Removed sessionId:" + sessionId);
        SessionMap sessionMap 
= getSessionMap(sessionId);
        
if (sessionMap != null) {
            logger.debug(
"remove sessionmap:" + sessionId);
            
//在线人数?
            getCache().addOrDecr("userCount",1);
            getCache().remove(sessionId);
        }
    }

  三?文g保存的处?/strong>

和缓存类|采用集中式的文g服务。对于linuxQ采用nfs。参考文?a mce_>http://linux.vbird.org/linux_server/0330nfs.php#What_NFS_perm。关键在于对权限的分配?br /> 应用E序本n不用修改?/p>




ronghao 2008-10-28 20:41 发表评论
]]>
SNAҎ之session炒冷?/title><link>http://www.aygfsteel.com/RongHao/archive/2008/09/04/226940.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Thu, 04 Sep 2008 06:31:00 GMT</pubDate><guid>http://www.aygfsteel.com/RongHao/archive/2008/09/04/226940.html</guid><wfw:comment>http://www.aygfsteel.com/RongHao/comments/226940.html</wfw:comment><comments>http://www.aygfsteel.com/RongHao/archive/2008/09/04/226940.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/RongHao/comments/commentRss/226940.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/RongHao/services/trackbacks/226940.html</trackback:ping><description><![CDATA[<p style="margin-left: 24pt; text-indent: 0cm;"><span style="font-size: 12pt; font-family: 宋体;">在集部|的情况下,应用E序需要做_主要集中在四个方面:?/span><span style="font-size: 12pt;">httpsession</span><span style="font-size: 12pt; font-family: 宋体;">的处理、对~存的处理、共享的文gpȝ?/span><span style="font-size: 12pt;">synchronized</span><span style="font-size: 12pt; font-family: 宋体;">关键字的失效?/span></p> <p style="margin-left: 42pt; text-indent: -18pt;"><strong><span style="font-size: 12pt; font-family: 宋体;">?/span><span style="font-size: 12pt;">httpsession</span><span style="font-size: 12pt; font-family: 宋体;">的处?/span></strong></p> <p style="margin-left: 42pt; text-indent: 0cm;"><span style="font-size: 12pt; font-family: 宋体;">?/span><span style="font-size: 12pt;">httpsession</span><span style="font-size: 12pt; font-family: 宋体;">的处理最为重要,因ؓ?/span><span style="font-size: 12pt;">WEB</span><span style="font-size: 12pt; font-family: 宋体;">E序而言Q?/span><span style="font-size: 12pt;">httpsession</span><span style="font-size: 12pt; font-family: 宋体;">无疑是最重要的全局资源Q它需要被多个</span><span style="font-size: 12pt;">web</span><span style="font-size: 12pt; font-family: 宋体;">服务器所׃n?/span></p> <p style="margin-left: 42pt; text-indent: 0cm;"><strong><span style="font-size: 12pt; font-family: 宋体; font-weight: normal;">无共享的集群架构Q?/span></strong><strong><span style="font-size: 12pt; font-family: "Calibri","sans-serif"; font-weight: normal;">SNA</span></strong><strong><span style="font-size: 12pt; font-family: 宋体; font-weight: normal;">Q,</span></strong><span style="font-size: 12pt; font-family: 宋体;">在这L集群中,每个节点具备完全相同的功能,q且不需要知道其他节点存在与否。每个节?/span><span style="font-size: 12pt;">JVM</span><span style="font-size: 12pt; font-family: 宋体;">q程不保持全局状态,才能够保?/span><span style="font-size: 12pt;">n</span><span style="font-size: 12pt; font-family: 宋体;">?/span><span style="font-size: 12pt;">JVM</span><span style="font-size: 12pt; font-family: 宋体;">节点的幂{性,那些所有涉及到全局状态的Q必L?/span><span style="font-size: 12pt;">JVM</span><span style="font-size: 12pt; font-family: 宋体;">q程之外Q例如用?/span><span style="font-size: 12pt;">ID</span><span style="font-size: 12pt; font-family: 宋体;">可以使用</span><span style="font-size: 12pt;">cookie</span><span style="font-size: 12pt; font-family: 宋体;">Q?/span><span style="font-size: 12pt;">session</span><span style="font-size: 12pt; font-family: 宋体;">可以攑օ数据库(qƈ不是一个好的选择Q,文g可以攑֜׃n存储pȝ中?/span></p> <p style="margin-left: 42pt; text-indent: 0cm;"><span style="font-size: 12pt; font-family: 宋体;">也就是说</span><span style="font-size: 12pt;">httpsession</span><span style="font-size: 12pt; font-family: 宋体;">的信息需要被保存?/span><span style="font-size: 12pt;">JVM</span><span style="font-size: 12pt; font-family: 宋体;">q程之外Q例如分布式~存、数据库?/span></p> <p style="margin-left: 42pt; text-indent: 0cm;"><span style="font-size: 12pt; font-family: 宋体;"><br /> </span></p> <p style="margin-left: 42pt; text-indent: 0cm;"><span style="font-size: 12pt; font-family: 宋体;">q里是方案:</span></p> 1、用会话cookie保存web服务器生的sessionid<br />    Z么是sessionid而不是useridQ原因在于谁也不知道除去d外其他h会在httpsession里干些什?br /> <br /> 2、自定义SessionMap<String,Serializable>同步保存httpsession内的信息<br />    自定义SessionMap同步httpsessionQ在操作httpsession时不用改变调用接口,不用东张西望<br /> <br /> 3、用分布式~存memcached保存自定义SessionMap<String,Serializable><br /> <br /> 4、会话胶_?br />    未失败{发的情况下没必要在memcached和httpsession之间复制来复制去Q眉来眼?br /> <br /> 5、用SnaFilter处理p|转发<br /> <br /> 6、用HttpSessionListener实现SessionMap<String,Serializable>的过?br />    利用容器session 机制的好?httpsessionq期的时候干掉memecached里的SessionMap <p style="margin-left: 60.75pt; text-indent: -18.75pt;"><span style="font-family: 宋体;"><br /> </span></p> <p style="margin-left: 42pt; text-indent: 0cm;"><span style="font-family: 宋体;">下面Ҏ</span>web<span style="font-family: 宋体;">h的过E分情况讨论该方案:</span></p> <p style="margin-left: 60pt; text-indent: -18pt;"><strong><span style="font-family: 宋体;">A、登?/span></strong></p> <p style="margin-left: 60pt; text-indent: -18pt;"><strong><span style="font-family: 宋体;"><img src="http://www.aygfsteel.com/images/blogjava_net/ronghao/login1.gif" alt="" border="0" height="420" width="567" /><br /> </span></strong></p> <p style="margin-left: 60pt; text-indent: 0cm;"><span><!--[if gte vml 1]> <![endif]--></span></p> <p style="margin-left: 60pt; text-indent: 0cm;"><span style="font-family: 宋体;">Ҏh?/span>url<span style="font-family: 宋体;">判断是否是登录请?/span></p> <p style="margin-left: 60pt; text-indent: 0cm;"><span style="font-family: 宋体;">在线人数保存?/span>memcached<span style="font-family: 宋体;">?/span></p> <p style="margin-left: 60pt; text-indent: -18pt;"><strong><span style="font-size: 12pt;">B?nbsp;</span><span style="font-family: 宋体;">正常h</span></strong></p> <p style="margin-left: 60pt; text-indent: -18pt;"><strong><span style="font-family: 宋体;"><img src="http://www.aygfsteel.com/images/blogjava_net/ronghao/normal1.gif" alt="" border="0" height="445" width="567" /><br /> </span></strong></p> <p style="margin-left: 60pt; text-indent: 0cm;"><span><!--[if gte vml 1]> <![endif]--></span></p> <p style="margin-left: 60pt; text-indent: -18pt;"><strong><span style="font-size: 12pt;">C?nbsp;</span><span style="font-family: 宋体;">p|转发</span></strong></p> <p style="margin-left: 60pt; text-indent: -18pt;"><strong><span style="font-family: 宋体;"><img src="http://www.aygfsteel.com/images/blogjava_net/ronghao/fail1.gif" alt="" border="0" height="424" width="581" /><br /> </span></strong></p> <p style="margin-left: 60pt; text-indent: 0cm;"><span><!--[if gte vml 1]> <![endif]--></span></p> <p style="margin-left: 60pt; text-indent: -18pt;"><strong><span style="font-size: 12pt;">D?/span><span style="font-family: 宋体;">d</span></strong></p> <p style="margin-left: 60pt; text-indent: -18pt;"><strong><span style="font-family: 宋体;"><img src="http://www.aygfsteel.com/images/blogjava_net/ronghao/logout1.gif" alt="" border="0" height="458" width="567" /><br /> </span></strong></p> <p style="margin-left: 60pt; text-indent: 0cm;"><span><!--[if gte vml 1]> <![endif]--></span></p> <p style="margin-left: 60pt; text-indent: 0cm;"><span style="font-family: 宋体;">Ҏh?/span>url<span style="font-family: 宋体;">判断是否是登?/span></p> <p style="margin-left: 60pt; text-indent: -18pt;"><strong>E、HttpSession<span style="font-family: 宋体;">q期</span></strong></p> <p style="margin-left: 60pt; text-indent: 0cm;"><span style="font-family: 宋体;">?/span>hack memcached<span style="font-family: 宋体;">Q?/span>HttpSessionListener<span style="font-family: 宋体;">Q?/span>sessionDestroyed<span style="font-family: 宋体;">事g时根?/span>sessionid<span style="font-family: 宋体;">删除</span>memcached<span style="font-family: 宋体;">里的</span>sessionMap<span style="font-family: 宋体;">Q如果存在)</span></p> <p style="margin-left: 21pt; text-indent: 0cm;"><span style="font-family: 宋体;">关于在线人数的统计:在线人数存储?/span>memcached<span style="font-family: 宋体;">里,在UhC</span>sessionMap<span style="font-family: 宋体;">l定Q往</span>memcached<span style="font-family: 宋体;">里增?/span>sessionMap<span style="font-family: 宋体;">时在Uh?/span>+1<span style="font-family: 宋体;">Q删除时</span>-1.</p> <img src ="http://www.aygfsteel.com/RongHao/aggbug/226940.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/RongHao/" target="_blank">ronghao</a> 2008-09-04 14:31 <a href="http://www.aygfsteel.com/RongHao/archive/2008/09/04/226940.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一ơ性能调优的实?/title><link>http://www.aygfsteel.com/RongHao/archive/2008/09/01/226068.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Mon, 01 Sep 2008 05:49:00 GMT</pubDate><guid>http://www.aygfsteel.com/RongHao/archive/2008/09/01/226068.html</guid><wfw:comment>http://www.aygfsteel.com/RongHao/comments/226068.html</wfw:comment><comments>http://www.aygfsteel.com/RongHao/archive/2008/09/01/226068.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.aygfsteel.com/RongHao/comments/commentRss/226068.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/RongHao/services/trackbacks/226068.html</trackback:ping><description><![CDATA[目情况Q是一个大型公司的内部办公pȝQ该pȝ有两个和一般企业应用不太一L特点Q一是用户量非常多,人员数达?W左右Q另一个是采用分񔽎理的Ş式,各个分公司数据分开理? <br /> <br /> 我们的定位:我们是作Z务^台的提供商参与这个项目的Q我们提供底层的开发^収ͼpȝ集成商在此基上进行二ơ开发? <br /> <br /> 在项目从开发到部v的过E中遇到了很多的问题Q也反映出很多问题? <br /> <br /> <strong>一、怎么回事Q跑得比猫还?/strong> <br /> 目开发完毕后部v在Ibm aix 型ZQ?2G内存Q?6个cpu。应用服务器采用的是weblogic9.2Q数据库是oracle10.0.2。上U后发现pȝq行的非常缓慢,? x开发环境下的tomcatq要慢。于是开始排查原因,最开始是对SQLq行监控Q优先考虑是数据库讉K性能产生瓉。通过监控Q发现很多业务需要执? 大量的SQL语句Q查看客L写的相关代码Q发现在查询数据时@环执行了大量SQL。主要原因在于他们在代码中@环调用了我们相关APIQ一个最典型的例 子是通过用户ID查找用户NAMEQ他们在业务表格里没有保存用户nameQ而是在查询的时候通过用户ID查找用户name填充到页面,几乎每一个查询都 是n+1?br />  <br /> 另外׃q_使用了hibernateQ得oo~程得非常爽快,D开发h员完全忽略了相应的数据库操作所带来的压力。很多业务逻辑直接通过PO叠加完成Q把一些可以通过很少SQL完成的逻辑全部分散攄到PO里,D了大量PO的交互和SQL语句? <br /> <br /> 开始优化SQLQ优化的同时增加大量业务~存。但优化完毕后运行缓慢的现象依旧存在Q性能有了一定的提升但是不是非常明显。l优化,其中考虑q? 多频J访问的数据使用内存数据库的方式。但是优化过后在tomcat上效果明显,部v到生产环境就问题依旧。于是考虑weblogic的配|问题,作ؓ开 发^台提供商Q我们只是提供系l开发相x面的支持Q对于应用服务器和数据库服务器只是做基本的配|系l可q行卛_。但是在q个问题上系l集成商咬定是我 们^台的问题不放Qƈ且存在一个很严重的问题:他们使用的是盗版的weblogicQ这h本就没有相应的技术支持? <br /> <br /> 问题的解冻I最后是找了一个BEA曄的开发h员,问题实际非常的简单,现场部v的weblogic默认是运行在32位机器上Q与64位机器存 在一定的不兼宏V通过替换相应的jar包,问题得到了解冻I主要是IO斚w。替换完毕后Q速度提升了进30% 。该开发h员说Q如果没有lisenceQ根本就不会得到q些替换的jar包? <br /> <br /> <strong>二、内存耗尽?/strong> <br /> 讉K速度的问题解决了Q系l的使用量很快上来,马上遇到新的问题Q内存耗尽了。严重到几乎每天都要out of memory一ơ。这U问题在客户现场频繁出现? <br /> <br /> 本地试QtomcatQsun jdk 通过Jprofiler监测内存使用情况。在q发讉K门户的情况下Q内存确实存在暴涨的情况Q?00q发Q内存用立M升了150m左右Qlƈ? 100Q再增长150m。但是很快在抵达高峰时会有一ơgc发生Q内存用稳定在200mQ内存里大量char[]数组对象。疲x试,内存使用曲线q没 有出现逐渐上升泄露的情c换weblogic和jrocket试Qgc发生的更加频J,内存使用E_?br />  <br /> 但是现场依旧频繁当机Q内存根本释放不了,一直逐渐增长Q典型的内存泄露。对pȝ~存、单态对象包括spring理的对象、IO进行了l一 排查Q依旧没有找到内存泄露的原因。用IBM 工具分析heapdump文gQ结果还是大量的char[]数组对象占据内存Q查扑ֺ用,找不到相关业务对象引用?br />  <br /> 问题解决Q问题解x一偶搜到的oracle论坛的帖子,q里<a >http://forums.oracle.com/forums/message.jspa?messageID=1040570 </a>。原因在于oracle10的数据库驱动对statement最后执行的l果集有着引用Qƈ且不会释放,目的在于通过内存而换取更好的性能。数据库q接? 用的是weblogic的连接池Q关于connection有个相关的statement cache讑֮Q设定一个connection能够被缓存的statement个数Q最大是1024Q而现场就被设定ؓ?024Qconnection pool的connection个数被设|ؓ?00 。真是个恐怖的讄。在?024改ؓ10后,内存使用量蘪然倒地Q稳定在1g左右。这个设|是在前面系l访问速度存在问题时由pȝ集成商的开发h员设|? 上去的,他们所有和优化相关的参数全部开C最大。这个问题要是用戯买的是正版的weblogic和oracle的话Q相信也会很快得到解冟? <br /> <br /> <strong>三、线E阻?/strong> <br /> 内存泄露的问题解军_Q线E阻塞的问题出水面。系l集成商报告是线E死锁,通过分析工具其实是线E阻塞,主要问题在于pȝ用到? synchronized关键字,对工作流相关API全部使用了synchronizedQ原因在q里Q?a href="http: //ronghao.javaeye.com/blog/205731">http: //ronghao.javaeye.com/blog/205731</a> 。分析发C个工作项提交的操作在q接数据库时被挂起了20分钟Q造成了大量线E的排队d。被挂v的原因有很多U。我们采用的Ҏ是将接口拆分和设|事 务timeout旉。但是这昄不是一个好Ҏ。最后是L所有的synchronized关键字,同步的问题交由数据库解冻I问题解决? <br /> <br /> <strong>四、反?/strong> <br /> 1、系l集成商Z么不购买正版Q? <br /> 2、开发^台提供商I竟在项目开发中处于一U什么样的位|?开发^台是否对所有Y件开发问题都要负责? <br /> 3、开发^台是封装越快乐吗?q是封装越丑陋Q?br /> <br /> 更具体的l节在这里:<br /> <h1> <a ><a >AIX+weblogic性能诊断记录</a></a><a ></a></h1> <img src ="http://www.aygfsteel.com/RongHao/aggbug/226068.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/RongHao/" target="_blank">ronghao</a> 2008-09-01 13:49 <a href="http://www.aygfsteel.com/RongHao/archive/2008/09/01/226068.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从血到充血Domain Modelhttp://www.aygfsteel.com/RongHao/archive/2008/07/03/212402.htmlronghaoronghaoThu, 03 Jul 2008 10:23:00 GMThttp://www.aygfsteel.com/RongHao/archive/2008/07/03/212402.htmlhttp://www.aygfsteel.com/RongHao/comments/212402.htmlhttp://www.aygfsteel.com/RongHao/archive/2008/07/03/212402.html#Feedback2http://www.aygfsteel.com/RongHao/comments/commentRss/212402.htmlhttp://www.aygfsteel.com/RongHao/services/trackbacks/212402.html 以WorkitemQ工作流里的工作)作ؓ例子

最开始的做法Q?/strong>
一个实体类叫做WorkitemQ指的是一个工作项或者称ZQ务项
一个DAOcd做WorkitemDao
一个业务逻辑cd做WorkitemManager(或者叫做WorkitemService)

主要看看WorkitemManagerQ因Z要逻辑集中在这?br />
public class WorkitemManager {

        
private WorkItemDAO workItemDAO;

    
public void setWorkItemDAO(WorkItemDAO workItemDAO) {
        
this.workItemDAO = workItemDAO;
    }
    
    
/**
     * 提交工作?br />      * 
@param workitemId 工作ID
     
*/
    
public void commitWorkitem(String workitemId){
            WorkItem workitem 
= workItemDAO.getWorkItem(workitemId);
            
//当前工作结?/span>
        workitem.complete();
        
int sID = workitem.getSequenceId();
        
//扑ֈ所对应的节?/span>
        InstActivity instActivity=workitem.getInstActivity();
        
//查找是否存在下一工作?/span>
        WorkItem sequenceWorkitem = workItemDAO.findSequenceWorkItem(instActivity.getId(), sID + 1);
        
//如果不存在则触发节点{
        if (sequenceWorkitem == null) {
            instActivity.signal();
        }
        
//否则把下一工作Ҏz?/span>
        else {
            sequenceWorkitem.setExecutive();
        }
    }
    
}


Workitemc里有一些状态{换的逻辑Q这样避免直接调用get/set属性方?br />
public class Workitem{

        
private int state = WorkitemInfo.PREPARE;

        
/**
     * 委派工作?br />      
*/
    
public void commission() {
        
if (state != WorkitemInfo.EXECUTE && state != WorkitemInfo.SIGNINED
                
&& state != WorkitemInfo.TOREAD&& state != WorkitemInfo.SUSPEND)
            
throw new WorkflowException(Messages.CANNOT_ALTER_WORKITEM_STATE);
        setState(WorkitemInfo.COMMISSIONED);
        setCommitted(
new Timestamp(System.currentTimeMillis()));
    }

    
/**
     * 完成工作?br />      
*/
    
public void complete() {
        
if (state != WorkitemInfo.SIGNINED)
            
throw new WorkflowException(Messages.CANNOT_ALTER_WORKITEM_STATE);
        setState(WorkitemInfo.COMPLETE);
        setCompleted(
new Timestamp(System.currentTimeMillis()));
    }
}


接下来的做法Q?/strong>
三个cM变,WorkitemManager打^Q将逻辑Ud到Workitem

public class WorkitemManager {

        
private WorkItemDAO workItemDAO;

    
public void setWorkItemDAO(WorkItemDAO workItemDAO) {
        
this.workItemDAO = workItemDAO;
    }
    
    
/**
     * 提交工作?br />      * 
@param workitemId 工作ID
     
*/
    
public void commitWorkitem(String workitemId){
            WorkItem workitem 
= workItemDAO.getWorkItem(workitemId);
            
//当前工作Ҏ?/span>
        workitem.commit();
    }
    
}

实际上此时WorkitemManager的功能非常有限,仅仅是事务边界和获取workitem对象Q甚臛_一些情况下可以省略?br />
通过一个Containercdspring的applicationContextq行装Q然后通过getBean()的静态方法即可访问被spring所理的bean。实际是workItemDAO隐式注入了Workitem?br />
public class Workitem{

        
/**
     * 提交工作?br />      
*/
    
public void commit() {
        
if (state != WorkitemInfo.EXECUTE && state != WorkitemInfo.SIGNINED
                
&& state != WorkitemInfo.TOREAD&& state != WorkitemInfo.SUSPEND)
            
throw new WorkflowException(Messages.CANNOT_ALTER_WORKITEM_STATE);
        setState(WorkitemInfo.COMMISSIONED);
        setCommitted(
new Timestamp(System.currentTimeMillis()));
        
int sID = workitem.getSequenceId();
        WorkItemDAO workItemDAO
=(WorkItemDAO)Container.getBean("workItemDAO");
        
//查找是否存在下一工作?/span>
        WorkItem sequenceWorkitem = workItemDAO.findSequenceWorkItem(instActivity.getId(), sID + 1);
        
//如果不存在则触发节点{
        if (sequenceWorkitem == null) {
            instActivity.signal();
        }
        
//否则把下一工作Ҏz?/span>
        else {
            sequenceWorkitem.setExecutive();
        }
    }

}


q样带来的好处是业务逻辑全部被封装到Domain ModelQDomain Model之间的交互变得非常的单,没有频繁的set/getQ直接调用有业务语义的Domain Model的方法即可。问题在于单元测试时q不了spring的容器,workItemDAO需要stub。我觉得q个问题不大Q问题是Domain Model开始变得臃肿,在业务逻辑复杂时代码行急剧膨胀?br />
现在的做?/strong>
以上三个cM持不变,增加一个类WorkitemExecutorQ将业务逻辑UL?br />

public class Workitem{

        
/**
     * 提交工作?br />      
*/
    
public void commit() {
        
if (state != WorkitemInfo.EXECUTE && state != WorkitemInfo.SIGNINED
                
&& state != WorkitemInfo.TOREAD&& state != WorkitemInfo.SUSPEND)
            
throw new WorkflowException(Messages.CANNOT_ALTER_WORKITEM_STATE);
        setState(WorkitemInfo.COMMISSIONED);
        setCommitted(
new Timestamp(System.currentTimeMillis()));
        WorkitemExecutor workitemExecutor
=(WorkitemExecutor)Container.getBean("workitemExecutor");
        workitemExecutor.commitWorkitem(
this);
    }

}

public class WorkitemExecutor {

        
private WorkItemDAO workItemDAO;

    
public void setWorkItemDAO(WorkItemDAO workItemDAO) {
        
this.workItemDAO = workItemDAO;
    }
    
    
/**
     * 提交工作?br />      * 
@param workitemId 工作ID
     
*/
    
public void commitWorkitem(Workitem workitem){
        
int sID = workitem.getSequenceId();
        
//扑ֈ所对应的节?/span>
        InstActivity instActivity=workitem.getInstActivity();
        
//查找是否存在下一工作?/span>
        WorkItem sequenceWorkitem = workItemDAO.findSequenceWorkItem(instActivity.getId(), sID + 1);
        
//如果不存在则触发节点{
        if (sequenceWorkitem == null) {
            instActivity.signal();
        }
        
//否则把下一工作Ҏz?/span>
        else {
            sequenceWorkitem.setExecutive();
        }
    }
    
}


业务逻辑拆分成两部分Q一部分在WorkitemQ另一部分委托lWorkitemExecutor。实际上是Domain Model复杂逻辑的情况重新外包出厅R调用的时候,面向的接口还是Domain Model的方法。注意到WorkitemExecutor和WorkitemManager的API是非常相似的。实际可以这栯为,传统的方?
Client->(Business Facade)->service(Business Logic 部分依赖Domain Model)->Data Access(DAO)?br /> 现在的方?br /> Client->(Business Facade)->Domain Model->service->Data Access(DAO)?br />
另外Q在q回client端的查询的时候还是們֐于直接调用DAOQ而不是通过Domain Model?br />
改进Q?br /> 注意C码中有这么一?br />
WorkItemDAO workItemDAO=(WorkItemDAO)Container.getBean("workItemDAO");

实是一个bad smell.当代码中大量出现后,q种造型是很恐怖的。所以采取了一U处理方式:l所有Domain Modell承一个父c,在父c里集中理所有Domain Model所依赖的servicesQ在父类里进行造型?br />



ronghao 2008-07-03 18:23 发表评论
]]>
高ƈ发测试下的一些问题及解决http://www.aygfsteel.com/RongHao/archive/2008/06/19/209140.htmlronghaoronghaoThu, 19 Jun 2008 05:34:00 GMThttp://www.aygfsteel.com/RongHao/archive/2008/06/19/209140.htmlhttp://www.aygfsteel.com/RongHao/comments/209140.htmlhttp://www.aygfsteel.com/RongHao/archive/2008/06/19/209140.html#Feedback22http://www.aygfsteel.com/RongHao/comments/commentRss/209140.htmlhttp://www.aygfsteel.com/RongHao/services/trackbacks/209140.html
1、对同一张表先insert再update是很快会引v死锁的,不管操作的是否是同一记录
解决ҎQ对于同一记录Q需要调整hibernate的映策略,使得一ơinsert完成操作。对于不同的记录需要在代码中手动flushQ得update先于insert?br />
2、对两张表进行多ơupdate操作Ӟ两张表交替update也会很快引v死锁
解决ҎQ在代码中手动flushQ保证对两张表的update不会出现交替的情c?br />
3、部分大范围扫描的select和update混合也会D死锁
解决ҎQ优化sqlQ尽量减sql语句Q通过lpo增加持久化字D늚方式减少兌查询

l过优化Q大部分情况下数据库死锁的情况得以避免,另外奇怪的是通过事g探查器在死锁时ƈ未发现锁升的事件。但是在一些特D情况下Q例如多个ƈ发汇聚的直接联合Q,死锁依旧发生。最后不得不Ҏ法进行synchronized关键字同步,q个通过synchronized flush完成。业务方法不必同步,最后批量操作数据库时进行同步?br />
换oracleq行试Q在未synchronized的情况下Q未发生死锁情况。由此可见sqlserver与oracle锁实现机制存在很大的差别。对sqlserver鄙视之。另Q同事说Qsqlserver2005后性能和机制发生了很大的变化,未测试?br />
补充一下我的一个最单情况下的测试用例:
POQ?br />
public class TestPO {
    String id;
    String name;
    
int num;
    
    .
}

映射文g hibernate3Q?br />
<hibernate-mapping default-access="field">
  
<class table="WFMS_TESTPO" name="com.eway.workflow.test.po.TestPO">

    
<id name="id" column="ID"><generator class="uuid" /></id>

    
<property name="name" column="NAME" type="string"/>

    
<property name="num" column="NUM" type="integer"/>

  
</class>
</hibernate-mapping>

被测试方法(都配|有事务Q:
    public void testSave(int num) {
        TestPO po 
= new TestPO();
        po.setName(
"ronghao");
        po.setNum(num);
        theadTestDao.save(po);
        po.setName(
"haorong");
    }

    
public void testSaveByJdbc(int num) {
        String sql 
= "insert into WFMS_TESTPO (ID,NAME,NUM) values (?,'RONGHAO',?)";
        Object[] params 
= new Object[]{num,num};
        jdbcTemplate.update(sql, params);
        sql
="update WFMS_TESTPO set name='haorong' where id=?"  ;
        params 
= new Object[]{num};
        jdbcTemplate.update(sql, params);
    }

试用例Q?br />
     public void testSave() throws Exception {
        TheadtestTemplate template 
= new TheadtestTemplate();
        template.execute(
new TheadtestCallback() {
            
public void doInThead(int suquence) {
//               theadTestManager.testSave(suquence);
                theadTestManager.testSaveByJdbc(suquence);
            }
        }, 
10);
    }

试l果Q不论是hibernateq是jdbcQƈ发情况下都很快就会引起sqlserver2000的死锁,换用两种数据库驱动jtds和jturbo死锁的情冉|有变化?br />
l论Qsqlserver2000数据库的lock配置{略Q不支持Q或者数据库本nQ就不支持对不同的行做同时操作(或者支持不完善Q,所谓的行锁支持很不完善Q死锁情况非常容易发生?br />
补充Q我Ҏ据库的一些实现机制也q不是很了解Q所以这里也只能列出现象而不能解释死锁的Ҏ原因。另外感谢Alex的讨论?br />

ronghao 2008-06-19 13:34 发表评论
]]>
failed batch HSQLDB http://www.aygfsteel.com/RongHao/archive/2008/05/30/204166.htmlronghaoronghaoFri, 30 May 2008 10:40:00 GMThttp://www.aygfsteel.com/RongHao/archive/2008/05/30/204166.htmlhttp://www.aygfsteel.com/RongHao/comments/204166.htmlhttp://www.aygfsteel.com/RongHao/archive/2008/05/30/204166.html#Feedback1http://www.aygfsteel.com/RongHao/comments/commentRss/204166.htmlhttp://www.aygfsteel.com/RongHao/services/trackbacks/204166.html failed batch; nested exception is java.sql.BatchUpdateException: failed batch
l过查发现是HSQLDB的问?br /> The bug is in HSQLDB - a well known one (any Google search for HSQLDB and that "failed batch"
message would have told you it).
https://sourceforge.net/tracker/?func=detail&atid=378131&aid=1407528&group_id=23316
解决Ҏ : turn off batching with HSQLDB it doesnt work.
讄<prop key="hibernate.jdbc.batch_size">0</prop>卛_

ronghao 2008-05-30 18:40 发表评论
]]>
使用solr搭徏你的全文?/title><link>http://www.aygfsteel.com/RongHao/archive/2007/11/06/158621.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Tue, 06 Nov 2007 10:03:00 GMT</pubDate><guid>http://www.aygfsteel.com/RongHao/archive/2007/11/06/158621.html</guid><wfw:comment>http://www.aygfsteel.com/RongHao/comments/158621.html</wfw:comment><comments>http://www.aygfsteel.com/RongHao/archive/2007/11/06/158621.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.aygfsteel.com/RongHao/comments/commentRss/158621.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/RongHao/services/trackbacks/158621.html</trackback:ping><description><![CDATA[<p><span style="font-size: 9pt; font-family: 宋体;">Solr </span><span style="font-size: 9pt; font-family: 宋体;">是一个可供企业用的、基?Lucene 的开即用的搜烦服务器。对Lucene不熟Q那么徏议先看看下面两篇文档Q?/span></p> <p><span style="font-size: 9pt; font-family: 宋体;">实战</span><span style="font-size: 9pt; font-family: 宋体;">Lucene</span><span style="font-size: 9pt; font-family: 宋体;">Q第 1 部分: 初识 LuceneQ?a >http://www.ibm.com/developerworks/cn/java/j-lo-lucene1/</a></span></p> <p><span style="font-size: 9pt; font-family: 宋体;">?/span><span style="font-size: 9pt; font-family: 宋体;">Lucene</span><span style="font-size: 9pt; font-family: 宋体;">加速Web搜烦应用E序的开发:<a >http://www.ibm.com/developerworks/cn/web/wa-lucene2/</a></span></p> <p style="margin-left: 25.5pt; text-indent: -25.5pt;"><strong><span style="font-size: 9pt; font-family: 宋体;">一?nbsp;</span></strong><strong><span style="font-size: 9pt; font-family: 宋体;">solr</span></strong><strong><span style="font-size: 9pt; font-family: 宋体;">介绍</span></strong></p> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt; font-family: 宋体; color: #cc0033;">solr</span><span style="font-size: 9pt; font-family: 宋体;">是基于Lucene Java搜烦库的企业U全文搜索引擎,目前是apache的一个项目。它的官方网址?a >http://lucene.apache.org/solr/</a> 。solr需要运行在一?/span><span style="font-size: 9pt;">servlet </span><span style="font-size: 9pt; font-family: 宋体;">容器里,例如</span><span style="font-size: 9pt;">tomcat5.5</span><span style="font-size: 9pt; font-family: 宋体;">?/span><span style="font-size: 9pt;">solr</span><span style="font-size: 9pt; font-family: 宋体;">?/span><span style="font-size: 9pt;">lucene</span><span style="font-size: 9pt; font-family: 宋体;">的上层提供了一个基?/span><span style="font-size: 9pt;">HTTP/XML</span><span style="font-size: 9pt; font-family: 宋体;">?/span><span style="font-size: 9pt;">Web Services</span><span style="font-size: 9pt; font-family: 宋体;">Q我们的应用需要通过q个服务?/span><span style="font-size: 9pt;">solr</span><span style="font-size: 9pt; font-family: 宋体;">q行交互?/span></p> <p style="margin-left: 25.5pt; text-indent: -25.5pt;"><strong><span style="font-size: 9pt; font-family: 宋体;">二?nbsp;</span></strong><strong><span style="font-size: 9pt; font-family: 宋体;">solr</span></strong><strong><span style="font-size: 9pt; font-family: 宋体;">安装和配|?/span></strong></p> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt; font-family: 宋体;">关于solr的安装和配置Q这里也有两非常好的文档,作者同时也</span><span style="font-size: 9pt; font-family: 宋体;">?/span><span style="font-size: 9pt;"> Lucene Java </span><span style="font-size: 9pt; font-family: 宋体;">目的提交h和发a人:</span></p> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt; font-family: 宋体;">使用</span><span style="font-size: 9pt;">Apache Solr</span><span style="font-size: 9pt; font-family: 宋体;">实现更加灵y的搜索:</span><span style="font-size: 9pt;"><a >http://www.ibm.com/developerworks/cn/java/j-solr1/index.html</a></span></p> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt;"><a >http://www.ibm.com/developerworks/cn/java/j-solr2/index.html</a></span></p> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt; font-family: 宋体;">下面主要说说需要注意的地方?/span></p> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt;">Solr</span><span style="font-size: 9pt; font-family: 宋体;">的安装非常简单,下蝲</span><span style="font-size: 9pt;">solr</span><span style="font-size: 9pt; font-family: 宋体;">?/span><span style="font-size: 9pt;">zip</span><span style="font-size: 9pt; font-family: 宋体;">包后解压~将</span><span style="font-size: 9pt;">dist</span><span style="font-size: 9pt; font-family: 宋体;">目录下的</span><span style="font-size: 9pt;">war</span><span style="font-size: 9pt; font-family: 宋体;">文g改名?/span><span style="font-size: 9pt;">solr.war</span><span style="font-size: 9pt; font-family: 宋体;">直接复制?/span><span style="font-size: 9pt;">tomcat5.5</span><span style="font-size: 9pt; font-family: 宋体;">?/span><span style="font-size: 9pt;">webapps</span><span style="font-size: 9pt; font-family: 宋体;">目录卛_。注意一定要讄</span><span style="font-size: 9pt;">solr</span><span style="font-size: 9pt; font-family: 宋体;">的主位置。有三种Ҏ。我采用的是</span><span style="font-size: 9pt; font-family: 宋体;">在tomcat里配|java:comp/env/solr/home的一个JNDI指向solr的主目录Qexample目录下)Q徏?tomcat55/conf/Catalina/localhost/solr.xml文g?/span></p> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;"><</span><span style="color: #800000;">Context </span><span style="color: #ff0000;">docBase</span><span style="color: #0000ff;">="D:/solr.war"</span><span style="color: #ff0000;"> debug</span><span style="color: #0000ff;">="0"</span><span style="color: #ff0000;"> crossContext</span><span style="color: #0000ff;">="true"</span><span style="color: #ff0000;"> </span><span style="color: #0000ff;">></span><span style="color: #000000;"><br /> <br />    </span><span style="color: #0000ff;"><</span><span style="color: #800000;">Environment </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="solr/home"</span><span style="color: #ff0000;"> type</span><span style="color: #0000ff;">="java.lang.String"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="D:/solr/solr"</span><span style="color: #ff0000;"> override</span><span style="color: #0000ff;">="true"</span><span style="color: #ff0000;"> </span><span style="color: #0000ff;">/></span><span style="color: #000000;"><br /> <br /> </span><span style="color: #0000ff;"></</span><span style="color: #800000;">Context</span><span style="color: #0000ff;">></span><span style="color: #000000;"><br /> </span></div> <p style="margin-left: 22.5pt; text-indent: -22.5pt;"><span style="font-size: 9pt; font-family: 宋体;">     </span><span style="font-size: 9pt; font-family: 宋体;">观察q个指定的solrM|,里面存在两个文g夹:conf和data。其中conf里存放了对solr而言最为重要的两个配置文gschema.xml和solrconfig.xml。data则用于存攄引文件?/span></p> <p style="margin-left: 22.5pt; text-indent: -22.5pt;"><span style="font-size: 9pt; font-family: 宋体;">     schema.xml</span><span style="font-size: 9pt; font-family: 宋体;">主要包括</span><span style="font-size: 9pt;">types</span><span style="font-size: 9pt; font-family: 宋体;">?/span><span style="font-size: 9pt;">fields</span><span style="font-size: 9pt; font-family: 宋体;">和其他的一些缺省设|?/span></p> <p style="margin-left: 22.55pt;"><span style="font-size: 9pt; font-family: 宋体;">solrconfig.xml</span><span style="font-size: 9pt; font-family: 宋体;">用来配置</span><span style="font-size: 9pt;">Solr</span><span style="font-size: 9pt; font-family: 宋体;">的一些系l属性,例如与烦引和查询处理有关的一些常见的配置选项Q以及缓存、扩展等{?/span></p> <p style="margin-left: 22.55pt;"><span style="font-size: 9pt; font-family: 宋体;">上面的文档对q两个文件有比较详细的说明,非常Ҏ上手。注意到</span><span style="font-size: 9pt; font-family: 宋体;">schema.xml</span><span style="font-size: 9pt; font-family: 宋体;">里有一?/span></p> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;"><</span><span style="color: #800000;">uniqueKey</span><span style="color: #0000ff;">></span><span style="color: #000000;">url</span><span style="color: #0000ff;"></</span><span style="color: #800000;">uniqueKey</span><span style="color: #0000ff;">></span></div> <p style="margin-left: 22.55pt;"><span style="font-size: 9pt; font-family: 宋体;">的配|,q里?/span><span style="font-size: 9pt;">url</span><span style="font-size: 9pt; font-family: 宋体;">字段作ؓ索引文档的唯一标识W,非常重要?/span></p> <p style="margin-left: 25.5pt; text-indent: -25.5pt;"><strong><span style="font-size: 9pt; font-family: 宋体;">三?nbsp;</span></strong><strong><span style="font-size: 9pt; font-family: 宋体;">加入中文分词</span></strong></p> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt; font-family: 宋体;">对全文检索而言Q中文分词非常的重要Q这里采用了qieqie庖丁分词Q非怸错:Q)。集成非常的ҎQ我下蝲的是2.0.4-alpha2版本Q其中它支持最多切分和按最大切分。创q一个中文TokenizerFactoryl承自solr的BaseTokenizerFactory?/span></p> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #008000;">/**</span><span style="color: #008000;"><br /> <br />  * Created by IntelliJ IDEA.<br /> <br />  * User: ronghao<br /> <br />  * Date: 2007-11-3<br /> <br />  * Time: 14:40:59<br /> <br />  * 中文切词 对庖丁切词的装<br /> <br />  </span><span style="color: #008000;">*/</span><span style="color: #000000;"><br /> <br /> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> ChineseTokenizerFactory </span><span style="color: #0000ff;">extends</span><span style="color: #000000;"> BaseTokenizerFactory {<br /> <br />     </span><span style="color: #008000;">/**</span><span style="color: #008000;"><br /> <br />      * 最多切?nbsp;  默认模式<br /> <br />      </span><span style="color: #008000;">*/</span><span style="color: #000000;"><br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> </span><span style="color: #0000ff;">final</span><span style="color: #000000;"> String MOST_WORDS_MODE </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">"</span><span style="color: #000000;">most-words</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br /> <br />     </span><span style="color: #008000;">/**</span><span style="color: #008000;"><br /> <br />      * 按最大切?br /> <br />      </span><span style="color: #008000;">*/</span><span style="color: #000000;"><br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> </span><span style="color: #0000ff;">final</span><span style="color: #000000;"> String MAX_WORD_LENGTH_MODE </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">"</span><span style="color: #000000;">max-word-length</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> String mode </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> setMode(String mode) {<br /> <br />              </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (mode</span><span style="color: #000000;">==</span><span style="color: #0000ff;">null</span><span style="color: #000000;">||</span><span style="color: #000000;">MOST_WORDS_MODE.equalsIgnoreCase(mode)<br /> <br />                       </span><span style="color: #000000;">||</span><span style="color: #000000;"> </span><span style="color: #000000;">"</span><span style="color: #000000;">default</span><span style="color: #000000;">"</span><span style="color: #000000;">.equalsIgnoreCase(mode)) {<br /> <br />                   </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.mode</span><span style="color: #000000;">=</span><span style="color: #000000;">MOST_WORDS_MODE;<br /> <br />              } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (MAX_WORD_LENGTH_MODE.equalsIgnoreCase(mode)) {<br /> <br />                   </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.mode</span><span style="color: #000000;">=</span><span style="color: #000000;">MAX_WORD_LENGTH_MODE;<br /> <br />              }<br /> <br />              </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {<br /> <br />                   </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> IllegalArgumentException(</span><span style="color: #000000;">"</span><span style="color: #000000;">不合法的分析器Mode参数讄:</span><span style="color: #000000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> mode);<br /> <br />              }<br /> <br />         }<br /> <br />     @Override<br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> init(Map</span><span style="color: #000000;"><</span><span style="color: #000000;">String, String</span><span style="color: #000000;">></span><span style="color: #000000;"> args) {<br /> <br />         </span><span style="color: #0000ff;">super</span><span style="color: #000000;">.init(args);<br /> <br />         setMode(args.get(</span><span style="color: #000000;">"</span><span style="color: #000000;">mode</span><span style="color: #000000;">"</span><span style="color: #000000;">));<br /> <br />     }<br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> TokenStream create(Reader input) {<br /> <br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> PaodingTokenizer(input, PaodingMaker.make(),<br /> <br />                   createTokenCollector());<br /> <br />     }<br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> TokenCollector createTokenCollector() {<br /> <br />         </span><span style="color: #0000ff;">if</span><span style="color: #000000;">( MOST_WORDS_MODE.equals(mode))<br /> <br />              </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> MostWordsTokenCollector();<br /> <br />         </span><span style="color: #0000ff;">if</span><span style="color: #000000;">( MAX_WORD_LENGTH_MODE.equals(mode))<br /> <br />              </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> MaxWordLengthTokenCollector();<br /> <br />         </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> Error(</span><span style="color: #000000;">"</span><span style="color: #000000;">never happened</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br /> <br />     }<br /> <br /> }<br /> </span></div> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt; font-family: 宋体;">在schema.xml的字Dtext配置里加入该分词器?/span></p> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;"><</span><span style="color: #800000;">fieldtype </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="text"</span><span style="color: #ff0000;"> class</span><span style="color: #0000ff;">="solr.TextField"</span><span style="color: #ff0000;"> positionIncrementGap</span><span style="color: #0000ff;">="100"</span><span style="color: #0000ff;">></span><span style="color: #000000;"><br /> <br />             </span><span style="color: #0000ff;"><</span><span style="color: #800000;">analyzer </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="index"</span><span style="color: #0000ff;">></span><span style="color: #000000;"><br /> <br />                 </span><span style="color: #0000ff;"><</span><span style="color: #800000;">tokenizer </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="com.ronghao.fulltextsearch.analyzer.ChineseTokenizerFactory"</span><span style="color: #ff0000;"> mode</span><span style="color: #0000ff;">="most-words"</span><span style="color: #0000ff;">/></span><span style="color: #000000;"><br /> </span><span style="color: #000000;"><br /> <br />                 </span><span style="color: #0000ff;"><</span><span style="color: #800000;">filter </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="solr.StopFilterFactory"</span><span style="color: #ff0000;"> ignoreCase</span><span style="color: #0000ff;">="true"</span><span style="color: #ff0000;"> words</span><span style="color: #0000ff;">="stopwords.txt"</span><span style="color: #0000ff;">/></span><span style="color: #000000;"><br /> <br />                 </span><span style="color: #0000ff;"><</span><span style="color: #800000;">filter </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="solr.WordDelimiterFilterFactory"</span><span style="color: #ff0000;"> generateWordParts</span><span style="color: #0000ff;">="1"</span><span style="color: #ff0000;"> generateNumberParts</span><span style="color: #0000ff;">="1"</span><span style="color: #ff0000;"> catenateWords</span><span style="color: #0000ff;">="1"</span><span style="color: #ff0000;"> catenateNumbers</span><span style="color: #0000ff;">="1"</span><span style="color: #ff0000;"> catenateAll</span><span style="color: #0000ff;">="0"</span><span style="color: #0000ff;">/></span><span style="color: #000000;"><br /> <br />                 </span><span style="color: #0000ff;"><</span><span style="color: #800000;">filter </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="solr.LowerCaseFilterFactory"</span><span style="color: #0000ff;">/></span><span style="color: #000000;"><br /> </span><span style="color: #000000;"><br /> <br />                 </span><span style="color: #0000ff;"><</span><span style="color: #800000;">filter </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="solr.RemoveDuplicatesTokenFilterFactory"</span><span style="color: #0000ff;">/></span><span style="color: #000000;"><br /> <br />             </span><span style="color: #0000ff;"></</span><span style="color: #800000;">analyzer</span><span style="color: #0000ff;">></span><span style="color: #000000;"><br /> <br />             </span><span style="color: #0000ff;"><</span><span style="color: #800000;">analyzer </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="query"</span><span style="color: #0000ff;">></span><span style="color: #000000;"><br /> <br />                 </span><span style="color: #0000ff;"><</span><span style="color: #800000;">tokenizer </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="com.ronghao.fulltextsearch.analyzer.ChineseTokenizerFactory"</span><span style="color: #ff0000;"> mode</span><span style="color: #0000ff;">="most-words"</span><span style="color: #0000ff;">/></span><span style="color: #000000;">               <br /> <br />                 </span><span style="color: #0000ff;"><</span><span style="color: #800000;">filter </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="solr.SynonymFilterFactory"</span><span style="color: #ff0000;"> synonyms</span><span style="color: #0000ff;">="synonyms.txt"</span><span style="color: #ff0000;"> ignoreCase</span><span style="color: #0000ff;">="true"</span><span style="color: #ff0000;"> expand</span><span style="color: #0000ff;">="true"</span><span style="color: #0000ff;">/></span><span style="color: #000000;"><br /> <br />                 </span><span style="color: #0000ff;"><</span><span style="color: #800000;">filter </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="solr.StopFilterFactory"</span><span style="color: #ff0000;"> ignoreCase</span><span style="color: #0000ff;">="true"</span><span style="color: #ff0000;"> words</span><span style="color: #0000ff;">="stopwords.txt"</span><span style="color: #0000ff;">/></span><span style="color: #000000;"><br /> <br />                 </span><span style="color: #0000ff;"><</span><span style="color: #800000;">filter </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="solr.WordDelimiterFilterFactory"</span><span style="color: #ff0000;"> generateWordParts</span><span style="color: #0000ff;">="1"</span><span style="color: #ff0000;"> generateNumberParts</span><span style="color: #0000ff;">="1"</span><span style="color: #ff0000;"> catenateWords</span><span style="color: #0000ff;">="0"</span><span style="color: #ff0000;"> catenateNumbers</span><span style="color: #0000ff;">="0"</span><span style="color: #ff0000;"> catenateAll</span><span style="color: #0000ff;">="0"</span><span style="color: #0000ff;">/></span><span style="color: #000000;"><br /> <br />                 </span><span style="color: #0000ff;"><</span><span style="color: #800000;">filter </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="solr.LowerCaseFilterFactory"</span><span style="color: #0000ff;">/></span><span style="color: #000000;"><br /> <br />                 </span><span style="color: #0000ff;"><</span><span style="color: #800000;">filter </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="solr.RemoveDuplicatesTokenFilterFactory"</span><span style="color: #0000ff;">/></span><span style="color: #000000;"><br /> <br />             </span><span style="color: #0000ff;"></</span><span style="color: #800000;">analyzer</span><span style="color: #0000ff;">></span><span style="color: #000000;"><br /> <br />         </span><span style="color: #0000ff;"></</span><span style="color: #800000;">fieldtype</span><span style="color: #0000ff;">></span><span style="color: #000000;"><br /> <br /> </span><span style="color: #0000ff;"></</span><span style="color: #800000;">types</span><span style="color: #0000ff;">></span><span style="color: #000000;"><br /> </span></div> <p style="margin-left: 18pt; text-indent: -18pt;"><span style="font-size: 9pt; font-family: 宋体;">    </span><span style="font-size: 9pt; font-family: 宋体;">完成后重启tomcatQ即可在<a href="http://localhost:8080/solr/admin/analysis.jsp">http://localhost:8080/solr/admin/analysis.jsp</a></span></p> <p style="margin-left: 18.05pt;"><span style="font-size: 9pt; font-family: 宋体;">体验到庖丁的中文分词。注意要paoding-analysis.jar复制到solr的lib下,注意修改jar包里字典的home?/span></p> <p style="margin-left: 25.5pt; text-indent: -25.5pt;"><strong><span style="font-size: 9pt; font-family: 宋体;">四?nbsp;</span></strong><strong><span style="font-size: 9pt; font-family: 宋体;">与自己应用进行集?/span></strong></p> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt; font-family: 宋体;">Solr</span><span style="font-size: 9pt; font-family: 宋体;">安装完毕Q现在可以将自己的应用与solr集成。其实过E非常的单,应用增加数据--></span><span style="font-size: 9pt; font-family: 宋体;">Ҏ配置的字D|建add的xml文档</span><span style="font-size: 9pt; font-family: Wingdings;">--></span><span style="font-size: 9pt; font-family: 宋体;">post</span><span style="font-size: 9pt; font-family: 宋体;">至solr/update?/span></p> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt; font-family: 宋体;">应用删除数据</span><span style="font-size: 9pt; font-family: Wingdings;">à</span><span style="font-size: 9pt; font-family: 宋体;">Ҏ配置的烦引文档唯一标识W构建delete的xml文档</span><span style="font-size: 9pt; font-family: Wingdings;">--></span><span style="font-size: 9pt; font-family: 宋体;">post</span><span style="font-size: 9pt; font-family: 宋体;">至solr/update?/span></p> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt; font-family: 宋体;">索数?/span><span style="font-size: 9pt; font-family: Wingdings;">à</span><span style="font-size: 9pt; font-family: 宋体;">构徏查询xml?gt;get?solr/select/--></span><span style="font-size: 9pt; font-family: 宋体;">对solrq回的xmlq行处理</span><span style="font-size: 9pt; font-family: Wingdings;">--></span><span style="font-size: 9pt; font-family: 宋体;">面展现?/span></p> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt; font-family: 宋体;">具体的xml格式可以在solr|站扑ֈ。另外就是solr支持高亮昄Q非常方ѝ?/span></p> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt; font-family: 宋体;">关于中文Qsolr</span><span style="font-size: 9pt; font-family: 宋体;">内核支持</span><span style="font-size: 9pt;">UTF-8</span><span style="font-size: 9pt; font-family: 宋体;">~码Q所以在</span><span style="font-size: 9pt;">tomcat</span><span style="font-size: 9pt; font-family: 宋体;">里的</span><span style="font-size: 9pt;">server.xml</span><span style="font-size: 9pt; font-family: 宋体;">需要进行配|?/span></p> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;"><</span><span style="color: #800000;">Connector </span><span style="color: #ff0000;">port</span><span style="color: #0000ff;">="8080"</span><span style="color: #ff0000;"> maxHttpHeaderSize</span><span style="color: #0000ff;">="8192"</span><span style="color: #ff0000;"> URIEncoding</span><span style="color: #0000ff;">="UTF-8"</span><span style="color: #ff0000;"> …</span><span style="color: #0000ff;">/></span></div> <p style="margin-left: 25.5pt;"><span style="font-size: 9pt; font-family: 宋体;">另外Q向solr Posth的时候需要{为utf-8~码。对solr q回的查询结果也需要进行一ơutf-8的{码。检索数据时Ҏ询的关键字也需要{码,然后?#8220;+”q接?/span></p> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #000000;">String[] array </span><span style="color: #000000;">=</span><span style="color: #000000;"> StringUtils.split(query, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">, </span><span style="color: #000000;">0</span><span style="color: #000000;">);<br /> <br />         </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> (String str : array) {<br /> <br />             result </span><span style="color: #000000;">=</span><span style="color: #000000;"> result </span><span style="color: #000000;">+</span><span style="color: #000000;"> URLEncoder.encode(str, </span><span style="color: #000000;">"</span><span style="color: #000000;">UTF-8</span><span style="color: #000000;">"</span><span style="color: #000000;">) </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br /> <br />         }<br /> </span></div> <img src ="http://www.aygfsteel.com/RongHao/aggbug/158621.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/RongHao/" target="_blank">ronghao</a> 2007-11-06 18:03 <a href="http://www.aygfsteel.com/RongHao/archive/2007/11/06/158621.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>l合spring+hibernate与jdbc的事?/title><link>http://www.aygfsteel.com/RongHao/archive/2007/10/09/151411.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Tue, 09 Oct 2007 07:11:00 GMT</pubDate><guid>http://www.aygfsteel.com/RongHao/archive/2007/10/09/151411.html</guid><wfw:comment>http://www.aygfsteel.com/RongHao/comments/151411.html</wfw:comment><comments>http://www.aygfsteel.com/RongHao/archive/2007/10/09/151411.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.aygfsteel.com/RongHao/comments/commentRss/151411.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/RongHao/services/trackbacks/151411.html</trackback:ping><description><![CDATA[<strong>问题背景</strong>Q我们是一家工作流公司Q客户采购我们的产品后,其嵌入光目中。我们的工作采用的?nbsp;  spring+hibernate的方式,客户目则是jdbc直接q行数据库操作?br /> <strong>问题</strong>Q客户在其数据库操作q程中需要调用我们的工作接口,q样需要将我们的工作流操作与他们的?nbsp; 务操作置于同一个事务中。我们的服务采用的都是spring的声明式事务Q而客户采用的是对         connectionq行事务处理。如何保证事务的一致性?<br /> <strong>惛_的解x案一</strong>Q用jta事务Q用tomcat+jotm提供事务理器。ؓ什么一开始就惛_要用jta事务Q?实际上我们和客户都是使用的同一个数据库Qؓ了方便,各自使用了不同的数据库连接方式,使用jta的话实有bt的意思在里面。但是事实上是我们的W一反应都是jta。最后没有采用该Ҏ的原因也很简单:我没有将jotm配置成功Q汗一个?br /> <strong>惛_的解x案二</strong>Q将客户的这些特定代码用spring理h。因修改客户部分代码Q这个方案遭C客户的强烈反寏V于是放弃?br /> <strong>惛_的解x案三</strong>Q客h据库操作与我们的服务使用同一个数据库q接。然后编E处理事务。存在两U方式:一U是把客Lq接传给我们Q另一U则是把我们的连接传l客戗第一U方式对我们的媄响太大,所以最后决定采用后一U方式:从hibernate session中获取connection然后传递给客户。接下来查看一下HibernateTemplate的execute()ҎQ思\很单了Q获取定义的sessionFactory-->创徏一个新的sessionq打开-->session与当前线E绑?->l客户代码返回connection-->打开事务-->客户使用我们传递的connectionq行数据库操?->我们不带声明事务的服务操?->提交事务-->解除l定?br /> <strong>实际要注意的地方?/strong>Q?、将session与当前线E绑定用的TransactionSynchronizationManager.bindResource()ҎQ这样在HibernateTemplate里才能找到sessionQ?br />                     2、我们的服务一定要把声明式事务dq掉Q否则会有commit;<br />                     3、我们服务调用完毕后一定要flush sessionQ否则客户代码不会感知数据库里的数据变化?br /> 最l解冻I使用了spring里常用的模板和回调。代码如下:<br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> TransactionTemplate {<br /> <br />     </span><span style="color: #0000ff;">protected</span><span style="color: #000000;"> </span><span style="color: #0000ff;">final</span><span style="color: #000000;"> Log logger </span><span style="color: #000000;">=</span><span style="color: #000000;"> LogFactory.getLog(TransactionTemplate.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">);<br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> FlushMode flushMode </span><span style="color: #000000;">=</span><span style="color: #000000;"> FlushMode.ALWAYS;<br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Object execute(TransactionCallback callback) {<br />         </span><span style="color: #008000;">//</span><span style="color: #008000;">首先获取sessionFactory</span><span style="color: #008000;"><br /> </span><span style="color: #000000;">        SessionFactory sessionFactory </span><span style="color: #000000;">=</span><span style="color: #000000;"> (SessionFactory) Framework.getEngine()<br />                 .getContainer().getComponent(</span><span style="color: #000000;">"</span><span style="color: #000000;">sessionFactory</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />         </span><span style="color: #008000;">//</span><span style="color: #008000;">创徏一个新的sessionq打开</span><span style="color: #008000;"><br /> </span><span style="color: #000000;">        logger.debug(</span><span style="color: #000000;">"</span><span style="color: #000000;">Opening single Hibernate Session in TransactionTemplate</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />         Session session </span><span style="color: #000000;">=</span><span style="color: #000000;"> getSession(sessionFactory);<br />         </span><span style="color: #008000;">//</span><span style="color: #008000;">session与当前线E绑?/span><span style="color: #008000;"><br /> </span><span style="color: #000000;">        TransactionSynchronizationManager.bindResource(sessionFactory, </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SessionHolder(session));<br />         </span><span style="color: #008000;">//</span><span style="color: #008000;">获取数据库连?/span><span style="color: #008000;"><br /> </span><span style="color: #000000;">        Connection conn </span><span style="color: #000000;">=</span><span style="color: #000000;"> session.connection();<br />         Object result </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />         Transaction transaction </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br />         </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {<br />             </span><span style="color: #008000;">//</span><span style="color: #008000;">开始处理事?/span><span style="color: #008000;"><br /> </span><span style="color: #000000;">            transaction </span><span style="color: #000000;">=</span><span style="color: #000000;"> session.beginTransaction();<br />             </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {<br />                 result </span><span style="color: #000000;">=</span><span style="color: #000000;"> callback.doInTransaction(conn);<br />             }<br />             </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (RuntimeException ex) {<br />                 doRollback(session, transaction);<br />                 </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> ex;<br />             }<br />             </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Error err) {<br />                 doRollback(session, transaction);<br />                 </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> err;<br />             }<br />             </span><span style="color: #008000;">//</span><span style="color: #008000;">如果数据库操作过E中没有发生异常则提交事?/span><span style="color: #008000;"><br /> </span><span style="color: #000000;">            transaction.commit();<br />         } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (WorkflowException e) {<br />             logger.error(</span><span style="color: #000000;">"</span><span style="color: #000000;">数据库操作失败,事务回滚也失败!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />             </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> e;<br />         } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (RuntimeException ex) {<br />             logger.error(</span><span style="color: #000000;">"</span><span style="color: #000000;">数据库操作失败,事务被回滚!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />             </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> ex;<br />         } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Error err) {<br />             logger.error(</span><span style="color: #000000;">"</span><span style="color: #000000;">数据库操作失败,事务被回滚!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />             </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> err;<br />         } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {<br />             </span><span style="color: #008000;">//</span><span style="color: #008000;"> session与当前线E解除绑?/span><span style="color: #008000;"><br /> </span><span style="color: #000000;">            TransactionSynchronizationManager.unbindResource(sessionFactory);<br />             doClose(session);<br />         }<br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> result;<br />     }<br /> <br />     </span><span style="color: #0000ff;">protected</span><span style="color: #000000;"> Session getSession(SessionFactory sessionFactory) {<br />         Session session </span><span style="color: #000000;">=</span><span style="color: #000000;"> SessionFactoryUtils.getSession(sessionFactory, </span><span style="color: #0000ff;">true</span><span style="color: #000000;">);<br />         FlushMode flushMode </span><span style="color: #000000;">=</span><span style="color: #000000;"> getFlushMode();<br />         </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (flushMode </span><span style="color: #000000;">!=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">) {<br />             session.setFlushMode(flushMode);<br />         }<br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> session;<br />     }<br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> doRollback(Session session, Transaction transaction) {<br />         logger.debug(</span><span style="color: #000000;">"</span><span style="color: #000000;">数据库操作异常,开始回滚事?/span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />         </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {<br />             transaction.rollback();<br />             logger.debug(</span><span style="color: #000000;">"</span><span style="color: #000000;">回滚事务成功Q?/span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />         }<br />         </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {<br />             logger.error(</span><span style="color: #000000;">"</span><span style="color: #000000;">回滚事务p|Q?/span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />             </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> WorkflowException(</span><span style="color: #000000;">"</span><span style="color: #000000;">回滚事务p|Q?/span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />         } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {<br />             session.clear();<br />         }<br />     }<br /> <br />     </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> doClose(Session session) {<br />         logger.debug(</span><span style="color: #000000;">"</span><span style="color: #000000;">开始关闭连?/span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />         </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {<br />             session.close();<br />         }<br />         </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {<br />             logger.error(</span><span style="color: #000000;">"</span><span style="color: #000000;">关闭q接p|Q?/span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />             </span><span style="color: #0000ff;">throw</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> WorkflowException(</span><span style="color: #000000;">"</span><span style="color: #000000;">关闭q接p|Q?/span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />         }<br />     }<br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> FlushMode getFlushMode() {<br />         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> flushMode;<br />     }<br /> <br />     </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> setFlushMode(FlushMode flushMode) {<br />         </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.flushMode </span><span style="color: #000000;">=</span><span style="color: #000000;"> flushMode;<br />     }<br /> }</span></div> <br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">interface</span><span style="color: #000000;"> TransactionCallback {<br /> <br />     Object doInTransaction(Connection conn);<br /> }</span></div> 调用伪代码:<br /> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><span style="color: #000000;">    </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> methodA(){<br />         TransactionTemplate transactionTemplate</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> TransactionTemplate();<br />         transactionTemplate.execute(</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> TransactionCallback(){<br />             </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Object doInTransaction(Connection conn) {<br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;">客户代码</span><span style="color: #008000;"><br /> </span><span style="color: #000000;">                client.method1(</span><span style="color: #000000;">"</span><span style="color: #000000;">1</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;">我们代码 直接使用</span><span style="color: #008000;"><br /> </span><span style="color: #000000;">                our.method2();<br />                 </span><span style="color: #008000;">//</span><span style="color: #008000;">客户代码</span><span style="color: #008000;"><br /> </span><span style="color: #000000;">                client.method3(</span><span style="color: #000000;">"</span><span style="color: #000000;">l</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />                 </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #0000ff;">null</span><span style="color: #000000;">;  <br />             }<br />         });<br />     }</span></div> <br /> <br /> <img src ="http://www.aygfsteel.com/RongHao/aggbug/151411.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/RongHao/" target="_blank">ronghao</a> 2007-10-09 15:11 <a href="http://www.aygfsteel.com/RongHao/archive/2007/10/09/151411.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>REST个h认知Q一Q?/title><link>http://www.aygfsteel.com/RongHao/archive/2007/07/11/129662.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Wed, 11 Jul 2007 09:37:00 GMT</pubDate><guid>http://www.aygfsteel.com/RongHao/archive/2007/07/11/129662.html</guid><wfw:comment>http://www.aygfsteel.com/RongHao/comments/129662.html</wfw:comment><comments>http://www.aygfsteel.com/RongHao/archive/2007/07/11/129662.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/RongHao/comments/commentRss/129662.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/RongHao/services/trackbacks/129662.html</trackback:ping><description><![CDATA[今天l于有空看看了Fielding的rest论文Q没有看完,很多文字实难懂Q但有些q是很有感触的,做个记号?br>一?span style="font-weight: bold;">软g架构</span>是一个Y件系l在其操作的某个阶段的运行时元素的抽象?br><span style="font-weight: bold;">架构元素</span>Q组Ӟq接器,数据Q配|?br><span style="font-weight: bold;">架构风格</span>Q一l协作的架构U束?br>一U特定的架构可以由多U架构风格组成?br><span style="font-weight: bold;">关键x点的架构属?/span><br><span style="font-weight: bold;">性能</span><br>最佳的应用性能是通过不用网l而获得的。这意味着对于一个基于网l的应用Q最高效的架构风格是在可能的情况下能够将对于|络使用减少到最的架构风格?br><span style="font-weight: bold;">可׾~?/span><br>表示在一个主动的配置中,架构支持大量的组件或大量的组件之间交互的能力?br><span style="font-weight: bold;">单?/span><br>对组件之间的功能分配应用分离x点原则。得单个的lg_单,更容易被理解和实现?br><span style="font-weight: bold;">可修Ҏ?/span><br>Z|络的系l的一个特D的xҎ动态的可修Ҏ,它要求在对一个已部v的应用做ZҎQ无需停止和重启整个系l。包括:可进化性,可扩展性,可定制性,可配|性,可重用性?br><span style="font-weight: bold;">可见?/span><br>能够通过限制必须使用通用性的接口Q或者提供访问监视功能的ҎQ来影响Z|络的应用中交互的可见性。在q种情况下,可见性是指一个组件对于其他两个组件之间的交互q行监视或仲裁的能力?br><span style="font-weight: bold;">可移植?/span><br>能够在不同的环境下运行?br><span style="font-weight: bold;">可靠?/span><br>当在lg、连接器或数据之中出现部分故障时Q一个架构容易受到系l层面故障媄响的E度?br> <img src ="http://www.aygfsteel.com/RongHao/aggbug/129662.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/RongHao/" target="_blank">ronghao</a> 2007-07-11 17:37 <a href="http://www.aygfsteel.com/RongHao/archive/2007/07/11/129662.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>sqlserver2000下USER表名与系l表重名http://www.aygfsteel.com/RongHao/archive/2007/03/11/103086.htmlronghaoronghaoSun, 11 Mar 2007 03:29:00 GMThttp://www.aygfsteel.com/RongHao/archive/2007/03/11/103086.htmlhttp://www.aygfsteel.com/RongHao/comments/103086.htmlhttp://www.aygfsteel.com/RongHao/archive/2007/03/11/103086.html#Feedback4http://www.aygfsteel.com/RongHao/comments/commentRss/103086.htmlhttp://www.aygfsteel.com/RongHao/services/trackbacks/103086.html

ronghao 2007-03-11 11:29 发表评论
]]>
关于集群的补?/title><link>http://www.aygfsteel.com/RongHao/archive/2007/02/12/99560.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Mon, 12 Feb 2007 15:18:00 GMT</pubDate><guid>http://www.aygfsteel.com/RongHao/archive/2007/02/12/99560.html</guid><wfw:comment>http://www.aygfsteel.com/RongHao/comments/99560.html</wfw:comment><comments>http://www.aygfsteel.com/RongHao/archive/2007/02/12/99560.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/RongHao/comments/commentRss/99560.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/RongHao/services/trackbacks/99560.html</trackback:ping><description><![CDATA[昨天发了个很什么的随笔Q今天把与集有关的东西搜了搜。整理一下?br />什么是集群Q集的概念。下面这个BLOG讲的非常清楚Q?br /><a >http://blog.csdn.net/ESoftWind/archive/2006/10/19/1341089.aspx</a><br />web层次的集方案讨论,看完javaeye相关的讨论,你会大概了解Q?br /><a >http://www.javaeye.com/topic/20298</a><br />注意里面robbin的无׃n架构QShare Nothing ArchitectureQSNA?br /><b>web层次的集主要技术就是:负蝲均衡和http session的失败{UR?/b><br />负蝲均衡不再多说Q焦点在于http session的失败{UR各个节点的http session复制会极大的影响性能。如何避免,robbin提出保持每个节点的无状态性,不再使用Session来保持全局状态。用hCZcookie取得Q假设不使用分布式CacheQsession直接攑֜数据库中。他推荐了memcached作ؓ分布式CacheQ这样在从数据库dsession时中间又隔了一层Cache来提高性能?br /><b>大致的方法是q样Q?/b>用户登陆的时候给他一个cookieQ存放userIdQ同时给q个用户分配一个SessionQ存放user对象Q然? 把这个session保存到数据库和分布式 Cache里。黏性会话。写一个filter或? webwork拦截器对用户hq行拦截Q如果他有cookieQ但是session里面没有user对象Q说明前一个节点down掉了Q就Ҏ cookie里面的userId查数据库或者是分布? Cache获得先前保存的sessionQ把原先的session复制C的新session里面。这样各个节炚w?session׃用复Ӟ因ؓ session是没有状态的。我们的E序对用session不受影响Q只是session里的对象要可序列化,当改变session里的对象旉要同? 到cache和数据库。当Ӟ效率的原因,session里面东西少好Q越E_好?br />谁有q方面的l验Q?br /><img src ="http://www.aygfsteel.com/RongHao/aggbug/99560.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/RongHao/" target="_blank">ronghao</a> 2007-02-12 23:18 <a href="http://www.aygfsteel.com/RongHao/archive/2007/02/12/99560.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>探讨一个可能的大访问量交易|站的开发注意事?/title><link>http://www.aygfsteel.com/RongHao/archive/2007/02/10/99106.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Sat, 10 Feb 2007 03:41:00 GMT</pubDate><guid>http://www.aygfsteel.com/RongHao/archive/2007/02/10/99106.html</guid><wfw:comment>http://www.aygfsteel.com/RongHao/comments/99106.html</wfw:comment><comments>http://www.aygfsteel.com/RongHao/archive/2007/02/10/99106.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.aygfsteel.com/RongHao/comments/commentRss/99106.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/RongHao/services/trackbacks/99106.html</trackback:ping><description><![CDATA[最q要开发一个与拍卖有关的大讉K量交易网站。一直做电子政务Q对q方面没有Q何经验。一开始考虑用php,mysql开发,后来׃觉得和交易相养I数据的一致性和安全一定很重要Q最后考虑用java开发? <br />我不清楚在做q个开发时和^时相比有哪些需要注意的地方Q我惛_的有Q? <br />1.webwork+spring+hibernateq种l合方式是否可行。据说tobao用了ejbQ虽说个人ƈ未觉得ejb哪点好,但别? 既然用了p定有它的一定道理; <br />2.数据的缓存肯定是必须的,但哪些是最需要被~存的数据? <br />3.dba肯定需要,在没有dba的情况下Q涉及数据库时应该注意什么; <br />4.q样的一个系l,它的性能肯定非常主要。它最有可能的瓉会发生在什么地方? <br />5.我们的理惛_期会有多长,3?个开发h员? <br />6.jmsq程异步调用的支持? <br />目前惛_的大概这些,希望有经验的朋友l些。我对这个项目目前还没有很大的把握?img src ="http://www.aygfsteel.com/RongHao/aggbug/99106.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/RongHao/" target="_blank">ronghao</a> 2007-02-10 11:41 <a href="http://www.aygfsteel.com/RongHao/archive/2007/02/10/99106.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>什么是JAVA内容仓库(Java Content RepositoryQ?2)http://www.aygfsteel.com/RongHao/archive/2007/01/23/95637.htmlronghaoronghaoTue, 23 Jan 2007 15:57:00 GMThttp://www.aygfsteel.com/RongHao/archive/2007/01/23/95637.htmlhttp://www.aygfsteel.com/RongHao/comments/95637.htmlhttp://www.aygfsteel.com/RongHao/archive/2007/01/23/95637.html#Feedback25http://www.aygfsteel.com/RongHao/comments/commentRss/95637.htmlhttp://www.aygfsteel.com/RongHao/services/trackbacks/95637.html内容仓库模型
JSR-170 是这样定义内容仓库的Q内容仓库由一l?workspaceQ工作空_l成Q这些workspace通常应该包含怼的内宏V一个内容仓库有一个到多个 workspace。每个workspace都是一个树状结构,都有一个唯一的树根节点(root nodeQ。树上的itemQ元素)或者是个nodeQ节点)或者是个propertyQ属性)。每个node都可以有零个到多个子节点和零个到多个子属性。只有根节点没有父节点,其余所有的节点都有一个父节点。property 也必L一个父节点Q但它没有子节点或是子属性,property 是叶子元素。property是真正存储数据的元素?br />
下图描述了一个blog应用E序的内容仓库模型。每个root nodeQ根节点Q的子节炚w代表了一个blog实体。与q个blog实体有关的数据都存储?bolgEntry 节点的属性里Q其中一?blogAttachment property 存储了一个二q制囄文g?br />repositorymodel3.gif
Ҏ内容仓库实现的功能,JSR-170定义了三U别:
Level 1Q定义了一个只ȝ内容仓库。功能包括读取内容,内容导ZؓXML和查扑ֆ宏V?br />Level 2Q定义了可写的内容仓库。Level 2是Level 1的扩展,新增的功能包括往内容仓库里写入内容,和从XML导入数据C库?br />Advanced optionsQ定义实CU附加功能,版本控制、JTA、SQL查询、清晰的内容锁定和监视?br />
什么是Apache JackRabbitQ?/b>
Apache JackRabbit是一个开放源码的JSR-170 实现Q实CLevel 2Q但它还有许多扩展的功能。详l可以去它的官方|站?br />
下面我们军_用Apache JackRabbit来作为我们示例程序的内容仓库?br />
如何配置Apache JackRabbit
JackRabbit需要两个参数来配置一个内容仓库实例?br />1.内容仓库ȝ录:q个文g目录下通常包含了所有的内容Q搜索烦引,内部配置文g和其他持久化信息。它的结构看h会像下面q个样子Q?br />
   c:/temp
        
|
        
|--Blogging
                
|
                
|-repository
                
|       |
                
|       |-index
                
|       |-meta
                
|       |-namespaces
                
|       |-nodetypes             
                
|
                
|-version
                
|
                
|-workspace
                        
|
                        
|--default

  在上面的情况下,内容仓库ȝ录是c:/temp/Blogging.
2.内容仓库配置文gQ一个典型的配置文g如下Q?br />
<Repository>
 
<FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
  
<param name="path" value="${rep.home}/repository"/>
 
</FileSystem>
 
<Security appName="Jackrabbit">
  
<AccessManager class="org.apache.jackrabbit.core.security.SimpleAccessManager"/>
  
<LoginModule class="org.apache.jackrabbit.core.security.SimpleLoginModule">
    
<param name="anonymousId" value="anonymous"/>
  
</LoginModule>
 
</Security>
 
<Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="default"/>
 
<Workspace name="${wsp.name}">
  
<FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
   
<param name="path" value="${wsp.home}"/>
  
</FileSystem>
  
<PersistenceManager 
        
class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
   
<param name="url" value="jdbc:derby:${wsp.home}/db;create=true"/>
   
<param name="schemaObjectPrefix" value="${wsp.name}_"/>
  
</PersistenceManager>
  
<SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
   
<param name="path" value="${wsp.home}/index"/>
  
</SearchIndex>
 
</Workspace>
 
<Versioning rootPath="${rep.home}/version">
  
<FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
   
<param name="path" value="${rep.home}/version" />
  
</FileSystem>
  
<PersistenceManager 
        
class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
   
<param name="url" value="jdbc:derby:${rep.home}/version/db;create=true"/>
   
<param name="schemaObjectPrefix" value="version_"/>
  
</PersistenceManager>
  
</Versioning>
  
<SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
   
<param name="path" value="${rep.home}/repository/index"/>
  
</SearchIndex>
</Repository>

 
  在这个配|文仉Q?lt;Repository>元素是根元素Q它包含了下面这些元素:
  aQ?lt;FileSystem>: 该元素配|了内容仓库的全局数据存储位置Q这些全局数据包括已注册的命名I间Q定制的节点cd{等。  ?    JackRabbit 提供了几U选择Q一U是像上面例子里配置的存储在本地文g里,LocalFileSystem. 如果你想把它们存储在数据库里Q你可以使用 DbFileSystem.
  bQ?lt;Security>:内容仓库的安全配|,它有两个子元素:<AccessManager>?lt;LoginModule>?lt;AccessManager>配置的类用来判断用户有没有权限来对特定数据执行特定的操作?br />  cQ?lt;Workspaces>:q个元素的配|对所有的workspace都通用。它的rootPath 属性是所有workspace文g夹的根目录,在我们的例子里它是c:/temp/Blogging/WorkspaceQdefaultWorkspace 属性则包含了workspace的默认名?br />  dQ?lt;Workspace>:q个元素是所有workspace的默认配|模ѝ去每个workspace文g夹下你都会发C个workspace.xml文gQ这个文件和q个元素的配|一模一栗三个子元素Q?lt;FileSystem>Q和q个workspace相关数据的存储位|;<PersistenceManager> Q这个workspace内容节点存储{略Q?lt;SearchIndex>Q可选,全文索?br />  eQ?lt;Versioning>:配置一个版本相关的对象。其实JackRabbit也是把它作ؓ节点来处理的?br />
q两个参数可以通过两种方式讄Q一U是在仓库实例创建时直接传到Jackrabbit里去Q一U是间接的通过讄JNDI object factory?br />你可以设|org.apache.jackrabbit.repository.home q个pȝ属性的值来指定你的内容仓库ȝ录;也可以设|?br />org.apache.jackrabbit.repository.conf q个pȝ属性的值来指定你的内容仓库配置文grepository.xml。如果你不设定这两个
参数QJackrabbit会把当前目录作ؓ内容仓库ȝ录,同时Q它有一个默认的内容仓库配置文g?img src ="http://www.aygfsteel.com/RongHao/aggbug/95637.html" width = "1" height = "1" />

ronghao 2007-01-23 23:57 发表评论
]]>
webwork拦截与common-fileupload冲突http://www.aygfsteel.com/RongHao/archive/2006/11/23/83122.htmlronghaoronghaoThu, 23 Nov 2006 14:02:00 GMThttp://www.aygfsteel.com/RongHao/archive/2006/11/23/83122.htmlhttp://www.aygfsteel.com/RongHao/comments/83122.htmlhttp://www.aygfsteel.com/RongHao/archive/2006/11/23/83122.html#Feedback1http://www.aygfsteel.com/RongHao/comments/commentRss/83122.htmlhttp://www.aygfsteel.com/RongHao/services/trackbacks/83122.html两个servlet里用Ccommon-fileupload.jar.一切看h都很不错,可是是上传不了文g.debug发现common-fileupload得不到fileItem.很是郁闷,因ؓ提供的sample是可以正常跑?上了common-fileupload的官方网?才发现是有别的进E拦截request的缘?于是开始调?我靠,pȝ里的qo器真TM的多,最后是把webwork\webwork-cleanup拦截/*变ؓ*.actionq才正常.
 问题:我们真的需要这么多的filter?q些filterqo的范围认真考虑q吗,可以~小?

ronghao 2006-11-23 22:02 发表评论
]]>
ibatis DAO 事务探烦http://www.aygfsteel.com/RongHao/archive/2006/01/20/28817.htmlronghaoronghaoFri, 20 Jan 2006 09:50:00 GMThttp://www.aygfsteel.com/RongHao/archive/2006/01/20/28817.htmlhttp://www.aygfsteel.com/RongHao/comments/28817.htmlhttp://www.aygfsteel.com/RongHao/archive/2006/01/20/28817.html#Feedback6http://www.aygfsteel.com/RongHao/comments/commentRss/28817.htmlhttp://www.aygfsteel.com/RongHao/services/trackbacks/28817.html阅读全文

ronghao 2006-01-20 17:50 发表评论
]]>
Z么会重复的造轮子?Q?/title><link>http://www.aygfsteel.com/RongHao/archive/2005/12/28/25763.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Wed, 28 Dec 2005 10:19:00 GMT</pubDate><guid>http://www.aygfsteel.com/RongHao/archive/2005/12/28/25763.html</guid><wfw:comment>http://www.aygfsteel.com/RongHao/comments/25763.html</wfw:comment><comments>http://www.aygfsteel.com/RongHao/archive/2005/12/28/25763.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.aygfsteel.com/RongHao/comments/commentRss/25763.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/RongHao/services/trackbacks/25763.html</trackback:ping><description><![CDATA[<P> 目l于上线q行了,但是q是问题多多Q但q好都不是涉及到逻辑的大问题。这两天把数据备份这块重做了一下,原先是自己写的一个线E池Q功能其实就是每天对mysqlq行备䆾Q当初设计ؓ什么会把这个功能放到程序里实现Q?Q。这完全是重复的造轮子!开始是用Jrontab重构了下Q后来讨论后军_在程序里把这功能删除,改在Linux里写个备份脚本。每天的晚上12点进行备份,然后本机一份,ftp到另一台服务器一份。有D|间没操作Linux了,l果好多命o都忘了,寒!Z么会重复的造轮子?Q?/P><img src ="http://www.aygfsteel.com/RongHao/aggbug/25763.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/RongHao/" target="_blank">ronghao</a> 2005-12-28 18:19 <a href="http://www.aygfsteel.com/RongHao/archive/2005/12/28/25763.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对原有系l进行重?/title><link>http://www.aygfsteel.com/RongHao/archive/2005/11/15/19933.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Tue, 15 Nov 2005 10:04:00 GMT</pubDate><guid>http://www.aygfsteel.com/RongHao/archive/2005/11/15/19933.html</guid><wfw:comment>http://www.aygfsteel.com/RongHao/comments/19933.html</wfw:comment><comments>http://www.aygfsteel.com/RongHao/archive/2005/11/15/19933.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/RongHao/comments/commentRss/19933.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/RongHao/services/trackbacks/19933.html</trackback:ping><description><![CDATA[最q一直打对原有的一套业务管理系l进行重构。原因很单,原来的系l采用的是JSP+JAVABEAN+MYSQL的两层架构,在JSP中直接调用JAVABEANQƈ且包含了太多的业务逻辑Q在l护的时候很困难?BR>初步的打是采用jstl+struts+spring+hibernate?BR>struts仅仅用于表现层,它的Action中不可以涉及C务逻辑<BR>最q看了看jbpm的源代码Q但是还没有在具体的目中实c也军_先不在程序中包含工作?img src ="http://www.aygfsteel.com/RongHao/aggbug/19933.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/RongHao/" target="_blank">ronghao</a> 2005-11-15 18:04 <a href="http://www.aygfsteel.com/RongHao/archive/2005/11/15/19933.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Tomcat中配|运行jbpm自带的websale http://www.aygfsteel.com/RongHao/archive/2005/11/10/19192.htmlronghaoronghaoThu, 10 Nov 2005 09:31:00 GMThttp://www.aygfsteel.com/RongHao/archive/2005/11/10/19192.htmlhttp://www.aygfsteel.com/RongHao/comments/19192.htmlhttp://www.aygfsteel.com/RongHao/archive/2005/11/10/19192.html#Feedback5http://www.aygfsteel.com/RongHao/comments/commentRss/19192.htmlhttp://www.aygfsteel.com/RongHao/services/trackbacks/19192.html1. ?http://www.jboss.com/products/jbpm/downloads 下蝲 jbpm-3.0.zip

2. 解压~?jbpm-3.0.zip ?'temp' 目录

3. 使用 eclipse, ?'temp\jbpm-3.0' 作ؓ an existing project into workspace 导入

配置q接 MySQL

1. ?'jbpm-3.0\lib' 目录?创徏 'mysql' 目录

2. ?mysql数据库驱?(mysql-connector-java-3.1.7-bin.jar) 拯?'mysql' 目录

3. ?mysql 中创Z个数据库Q数据库名字

4. ?'jbpm-3.0\src\resources'目录下创?'mysql' 目录

5. 把两个配|文?(create.db.hibernate.properties, identity.db.xml) ?'hsqldb' 目录?拯?'mysql' 目录

6. 按下面所C编?'create.db.hibernate.properties' 文g: hibernate.dialect=org.hibernate.dialect.MySQLDialect

hibernate.connection.driver_class=com.mysql.jdbc.Driver

hibernate.connection.url=jdbc:mysql://localhost:3306/

hibernate.connection.username= hibernate.connection.password=

hibernate.show_sql=true hibernate.query.substitutions=true 1, false 0

hibernate.c3p0.min_size=1 hibernate.c3p0.max_size=3

7. 另一个文?'identity.db.xml'不做改动

8. ?'jbpm-3.0' 根目? ~辑ANT的脚?'build.deploy.xml' 扑ֈ target name="create.db", 删除 db.start, db.stop 在这个目标块中将所有的'hsqldb' 替换?'mysql'

9. q行ANT ant create.db -buildfile build.deploy.xml q行完毕后就会发现mysql中多出很多表Q这是jbpm保持状态用?

创徏 jbpm.war 使其在tomcat中运?/STRONG>

默认的打war包时Q掉了一些库文g

1. ?eclipse? ~辑ant脚本 'build.deploy.xml' 在目标块 target name="build.webapp" 中在

<copy todir="build/jbpm.war.dir/WEB-INF/lib"> 下将

<fileset dir="build" includes="jbpm-webapp-${jbpm.version}.jar" /> 替换?/P>

<fileset dir="build" includes="jbpm*.jar" />

 另外加入新的两行

<fileset dir="lib/hibernate" includes="*.jar" />
<fileset dir="lib/bsh" includes="*.jar" />

2.因ؓ Hibernate 不能它的SessionFactory与tomcat的jndi l定 , 我们直接在源码中修改

3. 打开源文?JbpmSessionFactory.java, ?getInstance() Ҏ? 删除下面代码

InitialContext initialContext = new InitialContext(); Object o = initialContext.lookup(jndiName);

下面这?

instance = (JbpmSessionFactory) PortableRemoteObject.narrow
(o, JbpmSessionFactory.class);

替换?instance = (JbpmSessionFactory) PortableRemoteObject.narrow
(new JbpmSessionFactory(createConfiguration()), JbpmSessionFactory.class);

4.?createConfiguration(String configResource) Ҏ? 注释掉这D代?

String hibernatePropertiesResource = JbpmConfiguration.getString("jbpm.hibernate.properties");

if (hibernatePropertiesResource!=null) { Properties hibernateProperties =
new Properties();

try { hibernateProperties.load( ClassLoaderUtil.getStream(hibernatePropertiesResource) ); }

catch (IOException e) {
      e.printStackTrace();
      throw new RuntimeException
   ("couldn't load the hibernate properties from resource      '"hibernatePropertiesResource"'", e);
}
log.debug("overriding hibernate properties with "+ hibernateProperties); configuration.setProperties(hibernateProperties);
}
同时加入下面的代?

configuration.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");

configuration.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");

configuration.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/";);

configuration.setProperty("hibernate.connection.username", "");

configuration.setProperty("hibernate.connection.password", "");

configuration.setProperty("hibernate.connection.pool_size", "15");

5. q行脚本命o ant build ant build.webapp -buildfile build.deploy.xml

6. jbpm.war ?'jbpm-3.0\build' 下拷贝到 'tomcat.home\webapps'

7. 启动 tomcat

8. 打开览?'http://localhost:8080/jbpm'



ronghao 2005-11-10 17:31 发表评论
]]>
վ֩ģ壺 | | | ض| | | | | ԰| | ̨| | | | | ض| | ͩ| | | | ӳ| Ӳ| | | | ߶| ƶ| | | | ͤ| | | | ޳| | | | | |