<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title></title>
    <description></description>
    <link>http://thblovezhj.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>【转载】翻动100万级的数据 —— 只需几十毫秒 之揭秘篇</title>
        <author>thblovezhj</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://thblovezhj.javaeye.com">thblovezhj</a>&nbsp;
          链接：<a href="http://thblovezhj.javaeye.com/blog/172256" style="color:red;">http://thblovezhj.javaeye.com/blog/172256</a>&nbsp;
          发表时间: 2008年03月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          原文地址：<br /><br />http://blog.csdn.net/jyk/archive/2006/03/04/615146.aspx<br /><br />感谢大家的支持！！！<br />昨天发了一个邀请，邀请大家帮忙测试，效果还可以，下面小结一下：<br /><br />通过内部的计数器得知：访问次数是1071（其中有好多是自己点的:)），人数不是太理想，本来是想看看上万人同时访问的情况:)<br /><br />系统资源的占用情况<br /><br />内存 —— 很理想。SQL占用的内存最大也没有超过65M，一般是在35M左右；asp.net占用的内存最大也没有超过40M，一般是在25M左右。<br /><br />CPU：8%左右，由于访问次数不多，也不够集中，所以这个数值也说明不了什么。自己连续点了n次下一页，发现CPU的使用率飘高，达到了50%左右。<br />但是对于100万的记录，AMD XP2000+ 的CPU 几十毫秒的放映速度，因该是可以接受的，甚至是很理想的吧。<br />毕竟服务器的CPU要比我的快很多吧，而且记录也很难达到100万吧。<br /><br />结果还是很满意的，但是美中不足的是，我想看一下海量访问的情况下的效果，<br />希望大家再支持一下，多点几下，谢谢了。呵呵<br /><br />另外说明一下：前n页可以在60毫秒内完成，n应该是大于500的，小于多少嘛还没有测试。后n页就比较慢了，需要500毫秒左右。<br /><br />下面讨论一下翻页的技巧吧。<br />我没有用游标、临时表、not in、in 这些方法，并不是说他们的效率不高，而是我还没有测试过。我只用了 top ，查了两次表。<br />大家也可提供一些其他的方法，我来测试一下，看看在100万条的情况下的效果。（请不要给在存储过程里面组串的，看着实在是太费劲了）<br /><br /><br />讨论的前提是在海量数据的情况下，至少是在10万以上的。如果是很少的数据呢，那怎么翻都可以了。也差不了多少。<br /><br />1.设置合理的索引<br />首先要做的是设置合理的索引，这个好像经常被忽略，至少很少被谈起。<br /><br />注意：主键是索引的一种，而且是最快的一种。如果你都是把主键当作排序字段的话，那么你已经利用了索引。<br /><br />不设置合理的索引的话，会导致查询速度非常的慢，甚至会造成超时。<br /><br />这方面你可以做一个实验：找一个表，填进去10万条记录，假设有ID 、addedDate等字段，在查询分析器里面执行一下<br /><br />select top 10 * from table<br />应该立刻就能出现结果。<br /><br />然后再执行 select top 10 * from table order by ID（这时ID字段是主键）<br />也是立刻就出现了结果。<br /><br />然后再执行 select top 10 * from table order by addedDate （这时addedDate字段没有索引）<br />你会发现速度很慢。<br /><br />现在给addedDate 加一个非聚集索引，然后在执行上面的查询语句，速度也变得很快了。<br /><br />可见索引神奇的效果！<br /><br />这是翻动百万级记录最基本的设置，具体到我的那个论坛的翻页，我是设置了BoardID、 replyDate两个字段作为联合索引的。<br />因为是要在同一个讨论组李翻页，而且是按replyDate排序的。<br /><br /><br />2.只返回需要的记录<br />对于海量数据，都读出来做缓存，那是不可想象的（记录少的话，也要看利用率，一般都是很浪费的）。<br />所以呢如果一页显示20条的话名那就只都读出来20条，这样就很省内存和时间。<br /><br />注意：虽然ADO.NET里面有这个方法<br />SqlDataAdapter.Fill(DataSet1,startRecord,maxRecords,srcTable);<br />但是他还是要先从SQL里面把查询语句的查出来的所有记录都出来，然后在截取指定的记录数。这对于SQL来说是一样的，对于海量数据依然会很慢。<br /><br />论坛里的首页用的是select top 20 * from table where boardID = 5 order by replyDate desc<br />这样呢就只返回了20条记录，再加上索引的功劳，速度是非常快的。<br /><br /><br />3.尽量减少字段的长度<br />一个表可以建很多的字段，但是字段的总长度不能超过8060B，也就是说如果你建了一个char(8060)的字段，就不能在建其他的字段了。<br /><br />我在第一次的测试中（星期天的），把主题的所有信息都放在了一个表里面，包括了一个nvarchar(3600)的主题内容的字段，复制记录的时候发现非常的慢，<br />当达到9万的时候，就已经很慢的，勉强把记录数拷贝到了35万，加了索引，测试了一下，翻页速度还是可以的，前n也都是很快的，后n页就很慢了，<br />如果再加上查询那就非常之慢了。<br /><br />查看了一下数据文件吓了一跳 —— 他居然占用了1.4G的硬盘空间，怪不得拷贝和查询都慢的要死呢。<br /><br />于是修改了一下表结构，把那个nvarchar(3600)的主题内容的字段踢了出去，放在一个单独的表里面。<br />再重新拷贝记录就非常的快了，很快就把记录数从16表成了1048577。昨天的测试就是在这个条件下进行的。<br /><br />4.技巧<br />终于到了翻页算法的地方了，呵呵没有等急吧。<br />思路呢就是先找到一个标志，然后呢把大于（或小于）这个标志的前n条记录取出来。<br />什么？没看懂。没关系，我举个例子吧。<br /><br />假设是按ID倒序的，每一页显示10条记录，有100条记录，记录号正好是1到100（怎么这么巧？？为了说明方便嘛）<br /><br />那么第一页的记录就是100到91、第二页的记录就是90到81、第三页的记录就是80到71......<br /><br />我现在要翻到第三页，那么要找到第21行的记录的ID的值（也就是80），然后把小于等于80的记录用top 10 取出来就行了。<br /><br />查询语句<br /><br />declare @pageSize int --返回一页的记录数<br />declare @CurPage int --页号（第几页）1：第一页；2：第二页；......；-1最后一页。<br /><br />declare @Count int<br />declare @id int<br /><br />set @pageSize=10<br />set @CurPage =1<br /><br />if @CurPage = -1<br />begin<br />--最后一页<br />set rowcount @pageSize<br />select @id=ID from table order by ID <br />end<br /><br />--定位<br />if @CurPage > 0<br />begin<br />set @Count = @pageSize * (@CurPage -1) + 1<br />set rowcount @Count<br />select @id=ID from table order by ID desc<br />end<br /><br />--返回记录<br />set rowcount @pageSize<br />select * from table where ID &lt;=@id order by ID desc<br /><br />set rowcount 0<br /><br /><br />其中“定位”用了 select @id=ID from table order by ID desc<br />这种方法，感觉上是很省内存的，因为只记录了一个ID，<br /><br />然后用 select * from table where ID &lt;=@id order by ID desc<br />取得最终需要的记录<br /><br />set rowcount @pageSize 相当于 top @pageSize 。<br /><br /><br />优点：无论翻到哪一页，内存的占用情况都不变，多人访问内存也不会不变，很多人呢，还没有测试出来:)<br />缺点：单表、单排序字段。<br /><br /><br /><br />http://community.csdn.net/Expert/TopicView3.asp?id=4182510<br /><br />发了这个帖子，回复的人很多，感谢大家的支持。这里有个误会我不得不说明一下，免的误人子弟。<br /><br />在帖子里我并不是写了个算法就完事了，而是说了很多翻动海量数据要注意的地方，<br /><br />比如建立合理的索引，只返回需要的记录 ，尽量减少字段的长度 等注意到或没有注意到的地方。<br /><br />最后说的才是算法，可能是我的表达能力太差了吧，举的例子给大家带来了误会。<br /><br />翻页的语句 ( @pageSize * (@CurPage -1) + 1 )<br /><br />--定位<br />declare @id int <br />select top 41 @id=ID from table order by ID desc <br /><br />--显示数据<br />select top 20 * from table where ID &lt;=@id order by ID desc <br /><br />按照ID倒序排列（也就是按照int类型的字段排序）<br />一页显示20条记录，这是显示第三页的语句 <br />@pageSize * (@CurPage -1) + 1 = 20*(3-1) + 1 = 41 <br />正是因为ID是不连续的 所以才需要用第一个语句来定位，如果是连续的那还用第一条语句做什么呢？<br /><br />举各少量数据的例子：<br />假设有10条记录，ID是：1000，500，320，205，115，110，95，68，4，1。这回不写连续的了免的误会<br />一页显示两条记录，现在要显示第三页，那么第三页的id就是 115，110<br /><br />先看第一条语句<br />select top 5 @id=ID from table order by ID desc <br />不知道大家有没有看懂这句，这时print @id 得到的结果是 115。<br /><br />再看第二条语句<br />select top 2 * from table where ID &lt;=115 order by ID desc <br />这时的记录集就是 115，110，也就是我们所需要的记录了。<br /><br /><br />注意：不需要连续的ID，也不局限只能按ID排序，你可以换成ReplyDate(最后回复时间)字段， <br />当然了declare @id int 要改成 declare @id datetime<br /><br />这里的ID 是主键，唯一标识记录的字段，它本身就是一种索引，而且是效率最高的索引。<br /><br />A.唯一标识记录的字段的值怎么能随意改动呢，那不乱套了吗？<br /><br />B.主键是最快的索引，可能你还没有意识到（一开始我就不知道，学了SQL很久以后才知道的），如果你的算法用它作为排序字段，那么速度会很快，会比用其他字段（没有索引的字段）排序快很多。<br /><br />C.用ReplyDate(最后回复时间)来排序，那么就必须给他建立索引（在海量数据的情况下），否则会超时的。<br /><br /><br />D.建立索引后，再执行添加、修改、删除会对数据库带来灾难性的折磨？？<br />一开始我也是这么认为的，但是为了能够翻页，不得不加索引。<br />但是接下来的事实确打消了我的顾虑<br /><br />先来看添加。<br />100万条记录是怎么弄出来的？大家可以看到帖子里有很多标题一样的主题，对了是复制出来的。<br />我先加了16条记录，然后加上了索引。注意在insert into 之前就已经建立好了索引！<br /><br />接下来就是insert into table (...) select ... from table 影响的行数：<br />16、32、64、128、256、512、1024、2048、4096、8192、16384、32768、65536、<br />131072、262144、524288 很快记录就达到了100完了。<br />最后一次也只不过一两分钟（具体的时间忘记了，反正是很快了）。<br />同时，论坛也提供了发贴的功能，只是在批量添加记录的时候，把一些记录的最后回复时间弄成了2006年，<br />所以，你发的帖子不会显示在第一页。但是你可以看到，执行时间是很快的。<br /><br />可见添加的时候是不成问题的，索引是倒序排列的，所以影响的行数绝对没有你想象的那么多。<br /><br />再来看修改。<br />看了sp1234的回复，加了修改的功能，只是为了测试，所以呢可以修改标题、最后发表时间、分组ID。<br />为什么可以修改这几个字段呢？标题是普通字段，最后发表时间和分组ID是索引字段。<br />修改这几个字段需要的时间都是很快的，在最后回复时间的右面有 [改] [删] 字样，大家可以试一试。<br />同样，修改的时候，影响的行数也不是很多。<br /><br />最后看删除<br />不多说了，论坛提供了这个功能，试一下就知道了。另外，删除的时候，不用重新建立一遍索引吧？<br /><br /><br />在来说一下使用范围吧。<br />首先呢这只是一种方法，而不是一个通用的存储过程，也就是说要根据情况作适当的修改。<br />最佳使用环境：<br />单表，单排序字段，可以利用索引。<br />注意事项：<br />排序字段不必连续，最好使用int、datetime类型的字段，字符串型的字段没有试过，效果可能会略差。<br />表可以没有主键，但是对于海量数据的情况下，必须建立合理的索引。<br /><br />有一个比较致命的限制，大家好像都没有发现，那就是排序字段的重复性，<br />最好是没有重复的，但不是说绝对不能有重复的记录，有不要紧，只要不跨页就行，跨页的话就会挤掉若干条记录，<br />用时间字段来排序，发生重复的记录的可能性就很小了。<br /><br /><br />扩展性：<br />bingbingcha(不思不归,不孟不E,原来是头大灰狼) 的回复很精彩<br />-----------------<br />这样的技巧在SQL区都讨论过了..速度是很快的..但是满足不了需求的..实用性太差了..现在的企业需要用到分页的大部分都是多表查询..单表分页满足不了需求的..<br /><br />这个存储过程可以扩展..用临时表+楼主的方法..是个不错的选择..<br />-----------------<br /><br />对于多表关联查询，有两种方法，第一种就是bingbingcha说的 —— “用临时表+楼主的方法”，这是在海量数据的时候唯一可行的方法。<br />但是在小数据量的时候，这么些就有一点繁琐，而且不容易归纳到通用的写法里。<br /><br />先来看一下查询语句据的写法：<br />联合的<br />SELECT a.ReplyID, a.TopicID<br />FROM dbo.BBS_Reply a INNER JOIN<br />dbo.BBS_body b ON a.BodyID = b.bodyID<br />where a.ReplyID >10<br /><br />单表的<br /><br />SELECT ReplyID, TopicID<br />FROM dbo.BBS_Reply <br />where ReplyID >10<br /><br />有没有看到相同的地方：<br />select 显示的字段<br />from 表<br />where 条件<br /><br />那么单表查询和多表查询有什么区别呢？<br />至少有很多的多表（单字段排序）查询都是可用这种方式的。<br />注意：我并没有说所有的多表（单字段排序）查询都可以用，看具体情况了。<br /><br /><br /><br />这是一个效率最高（需要合理的索引的帮忙），比较通用的翻页方法。不知道这次我有没有讲明白。
          <br/>
          <span style="color:red;">
            <a href="http://thblovezhj.javaeye.com/blog/172256#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 15 Mar 2008 23:44:30 +0800</pubDate>
        <link>http://thblovezhj.javaeye.com/blog/172256</link>
        <guid>http://thblovezhj.javaeye.com/blog/172256</guid>
      </item>
      <item>
        <title>海量数据处理分析</title>
        <author>thblovezhj</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://thblovezhj.javaeye.com">thblovezhj</a>&nbsp;
          链接：<a href="http://thblovezhj.javaeye.com/blog/172255" style="color:red;">http://thblovezhj.javaeye.com/blog/172255</a>&nbsp;
          发表时间: 2008年03月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          笔者在实际工作中，有幸接触到海量的数据处理问题，对其进行处理是一项艰巨而复杂的任务。原因有以下几个方面：一、数据量过大，数据中什么情况都可能存在。如果说有10条数据，那么大不了每条去逐一检查，人为处理，如果有上百条数据，也可以考虑，如果数据上到千万级别，甚至过亿，那不是手工能解决的了，必须通过工具或者程序进行处理，尤其海量的数据中，什么情况都可能存在，例如，数据中某处格式出了问题，尤其在程序处理时，前面还能正常处理，突然到了某个地方问题出现了，程序终止了。二、软硬件要求高，系统资源占用率高。对海量的数据进行处理，除了好的方法，最重要的就是合理使用工具，合理分配系统资源。一般情况，如果处理的数据过TB级，小型机是要考虑的，普通的机子如果有好的方法可以考虑，不过也必须加大CPU和内存，就象面对着千军万马，光有勇气没有一兵一卒是很难取胜的。三、要求很高的处理方法和技巧。这也是本文的写作目的所在，好的处理方法是一位工程师长期工作经验的积累，也是个人的经验的总结。没有通用的处理方法，但有通用的原理和规则。那么处理海量数据有哪些经验和技巧呢，我把我所知道的罗列一下，以供大家参考：一、选用优秀的数据库工具现在的数据库工具厂家比较多，对海量数据的处理对所使用的数据库工具要求比较高，一般使用Oracle或者DB2，微软公司最近发布的SQL Server 2005性能也不错。另外在BI领域：数据库，数据仓库，多维数据库，数据挖掘等相关工具也要进行选择，象好的ETL工具和好的OLAP工具都十分必要，例如Informatic，Eassbase等。笔者在实际数据分析项目中，对每天6000万条的日志数据进行处理，使用SQL Server 2000需要花费6小时，而使用SQL Server 2005则只需要花费3小时。二、编写优良的程序代码处理数据离不开优秀的程序代码，尤其在进行复杂数据处理时，必须使用程序。好的程序代码对数据的处理至关重要，这不仅仅是数据处理准确度的问题，更是数据处理效率的问题。良好的程序代码应该包含好的算法，包含好的处理流程，包含好的效率，包含好的异常处理机制等。三、对海量数据进行分区操作对海量数据进行分区操作十分必要，例如针对按年份存取的数据，我们可以按年进行分区，不同的数据库有不同的分区方式，不过处理机制大体相同。例如SQL Server的数据库分区是将不同的数据存于不同的文件组下，而不同的文件组存于不同的磁盘分区下，这样将数据分散开，减小磁盘I/O，减小了系统负荷，而且还可以将日志，索引等放于不同的分区下。四、建立广泛的索引对海量的数据处理，对大表建立索引是必行的，建立索引要考虑到具体情况，例如针对大表的分组、排序等字段，都要建立相应索引，一般还可以建立复合索引，对经常插入的表则建立索引时要小心，笔者在处理数据时，曾经在一个ETL流程中，当插入表时，首先删除索引，然后插入完毕，建立索引，并实施聚合操作，聚合完成后，再次插入前还是删除索引，所以索引要用到好的时机，索引的填充因子和聚集、非聚集索引都要考虑。五、建立缓存机制当数据量增加时，一般的处理工具都要考虑到缓存问题。缓存大小设置的好差也关系到数据处理的成败，例如，笔者在处理2亿条数据聚合操作时，缓存设置为100000条/Buffer，这对于这个级别的数据量是可行的。六、加大虚拟内存如果系统资源有限，内存提示不足，则可以靠增加虚拟内存来解决。笔者在实际项目中曾经遇到针对18亿条的数据进行处理，内存为1GB，1个P4 2.4G的CPU，对这么大的数据量进行聚合操作是有问题的，提示内存不足，那么采用了加大虚拟内存的方法来解决，在6块磁盘分区上分别建立了6个4096M的磁盘分区，用于虚拟内存，这样虚拟的内存则增加为 4096*6 + 1024 = 25600 M，解决了数据处理中的内存不足问题。七、分批处理 海量数据处理难因为数据量大，那么解决海量数据处理难的问题其中一个技巧是减少数据量。可以对海量数据分批处理，然后处理后的数据再进行合并操作，这样逐个击破，有利于小数据量的处理，不至于面对大数据量带来的问题，不过这种方法也要因时因势进行，如果不允许拆分数据，还需要另想办法。不过一般的数据按天、按月、按年等存储的，都可以采用先分后合的方法，对数据进行分开处理。八、使用临时表和中间表数据量增加时，处理中要考虑提前汇总。这样做的目的是化整为零，大表变小表，分块处理完成后，再利用一定的规则进行合并，处理过程中的临时表的使用和中间结果的保存都非常重要，如果对于超海量的数据，大表处理不了，只能拆分为多个小表。如果处理过程中需要多步汇总操作，可按汇总步骤一步步来，不要一条语句完成，一口气吃掉一个胖子。九、优化查询SQL语句在对海量数据进行查询处理过程中，查询的SQL语句的性能对查询效率的影响是非常大的，编写高效优良的SQL脚本和存储过程是数据库工作人员的职责，也是检验数据库工作人员水平的一个标准，在对SQL语句的编写过程中，例如减少关联，少用或不用游标，设计好高效的数据库表结构等都十分必要。笔者在工作中试着对1亿行的数据使用游标，运行3个小时没有出结果，这是一定要改用程序处理了。十、使用文本格式进行处理对一般的数据处理可以使用数据库，如果对复杂的数据处理，必须借助程序，那么在程序操作数据库和程序操作文本之间选择，是一定要选择程序操作文本的，原因为：程序操作文本速度快；对文本进行处理不容易出错；文本的存储不受限制等。例如一般的海量的网络日志都是文本格式或者csv格式（文本格式），对它进行处理牵扯到数据清洗，是要利用程序进行处理的，而不建议导入数据库再做清洗。十一、       定制强大的清洗规则和出错处理机制海量数据中存在着不一致性，极有可能出现某处的瑕疵。例如，同样的数据中的时间字段，有的可能为非标准的时间，出现的原因可能为应用程序的错误，系统的错误等，这是在进行数据处理时，必须制定强大的数据清洗规则和出错处理机制。十二、       建立视图或者物化视图视图中的数据来源于基表，对海量数据的处理，可以将数据按一定的规则分散到各个基表中，查询或处理过程中可以基于视图进行，这样分散了磁盘I/O，正如10根绳子吊着一根柱子和一根吊着一根柱子的区别。十三、       避免使用32位机子（极端情况）目前的计算机很多都是32位的，那么编写的程序对内存的需要便受限制，而很多的海量数据处理是必须大量消耗内存的，这便要求更好性能的机子，其中对位数的限制也十分重要。十四、       考虑操作系统问题海量数据处理过程中，除了对数据库，处理程序等要求比较高以外，对操作系统的要求也放到了重要的位置，一般是必须使用服务器的，而且对系统的安全性和稳定性等要求也比较高。尤其对操作系统自身的缓存机制，临时空间的处理等问题都需要综合考虑。十五、       使用数据仓库和多维数据库存储数据量加大是一定要考虑OLAP的，传统的报表可能5、6个小时出来结果，而基于Cube的查询可能只需要几分钟，因此处理海量数据的利器是OLAP多维分析，即建立数据仓库，建立多维数据集，基于多维数据集进行报表展现和数据挖掘等。十六、       使用采样数据，进行数据挖掘基于海量数据的数据挖掘正在逐步兴起，面对着超海量的数据，一般的挖掘软件或算法往往采用数据抽样的方式进行处理，这样的误差不会很高，大大提高了处理效率和处理的成功率。一般采样时要注意数据的完整性和，防止过大的偏差。笔者曾经对1亿2千万行的表数据进行采样，抽取出400万行，经测试软件测试处理的误差为千分之五，客户可以接受。还有一些方法，需要在不同的情况和场合下运用，例如使用代理键等操作，这样的好处是加快了聚合时间，因为对数值型的聚合比对字符型的聚合快得多。类似的情况需要针对不同的需求进行处理。海量数据是发展趋势，对数据分析和挖掘也越来越重要，从海量数据中提取有用信息重要而紧迫，这便要求处理要准确，精度要高，而且处理时间要短，得到有价值信息要快，所以，对海量数据的研究很有前途，也很值得进行广泛深入的研究。
          <br/>
          <span style="color:red;">
            <a href="http://thblovezhj.javaeye.com/blog/172255#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 15 Mar 2008 23:38:29 +0800</pubDate>
        <link>http://thblovezhj.javaeye.com/blog/172255</link>
        <guid>http://thblovezhj.javaeye.com/blog/172255</guid>
      </item>
      <item>
        <title>电脑设置定时自动关机</title>
        <author>thblovezhj</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://thblovezhj.javaeye.com">thblovezhj</a>&nbsp;
          链接：<a href="http://thblovezhj.javaeye.com/blog/172193" style="color:red;">http://thblovezhj.javaeye.com/blog/172193</a>&nbsp;
          发表时间: 2008年03月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          1、控制面板－－电源设置！ <br />2、Windows XP的关机是由Shutdown.exe程序来控制的，位于Windows\\System32文件夹中。如果想让Windows 2000也实现同样的效果，可以把Shutdown.exe复制到系统目录下。 <br />比如你的电脑要在22:00关机，可以选择“开始→运行”，输入“at 22:00 Shutdown -s”，这样，到了22点电脑就会出现“系统关机”对话框，默认有30秒钟的倒计时并提示你保存工作。如果你想以倒计时的方式关机，可以输入“Shutdown.exe -s -t 3600”，这里表示60分钟后自动关机，“3600”代表60分钟。 <br />设置好自动关机后，如果想取消的话，可以在运行中输入“shutdown -a”。另外输入“shutdown -i”，则可以打开设置自动关机对话框，对自动关机进行设置。 <br />Shutdown.exe的参数，每个都具有特定的用途，执行每一个都会产生不同的效果，比如“-s”就表示关闭本地计算机，“-a”表示取消关机操作，下面列出了更多参数，大家可以在Shutdown.exe中按需使用。 <br />-f：强行关闭应用程序 <br />-m \\\\计算机名：控制远程计算机 <br />-i：显示图形用户界面，但必须是Shutdown的第一个选项 <br />-l：注销当前用户 <br />-r：关机并重启 <br />-t 时间：设置关机倒计时 <br />-c \"消息内容\"：输入关机对话框中的消息内容（不能超127个字符）
          <br/>
          <span style="color:red;">
            <a href="http://thblovezhj.javaeye.com/blog/172193#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 15 Mar 2008 17:18:00 +0800</pubDate>
        <link>http://thblovezhj.javaeye.com/blog/172193</link>
        <guid>http://thblovezhj.javaeye.com/blog/172193</guid>
      </item>
      <item>
        <title>Log4J简介</title>
        <author>thblovezhj</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://thblovezhj.javaeye.com">thblovezhj</a>&nbsp;
          链接：<a href="http://thblovezhj.javaeye.com/blog/172187" style="color:red;">http://thblovezhj.javaeye.com/blog/172187</a>&nbsp;
          发表时间: 2008年03月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          第1章.     Log4j 的优点<br /><br />Log4j是Apache的一个开放源代码项目，通过使用Log4j，我们可以控制日志信息输送的；我们也可以控制每一条日志的输出格式；通过定义每一条日志信息的级别，我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是，这些可以通过一个配置文件来灵活地进行配置，而不需要修改应用的代码。 <br />log4j的好处在于： <br />1)        通过修改配置文件，就可以决定log信息的目的地——控制台、文件、GUI组件、甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等 <br />2)        通过修改配置文件，可以定义每一条日志信息的级别，从而控制是否输出。在系统开发阶段可以打印详细的log信息以跟踪系统运行情况,而在系统稳定后可以关闭log输出,从而在能跟踪系统运行情况的同时,又减少了垃圾代码（System.out.println(......)等)。 <br />3)        使用log4j，需要整个系统有一个统一的log机制，有利于系统的规划。 <br /><br />第2章.     配置文件<br /><br />Log4j由三个重要的组件构成：日志信息的优先级，日志信息的输出目的地，日志信息的输出格式。日志信息的优先级从高到低有FATAL、ERROR、WARN、INFO、DEBUG，分别用来指定这条日志信息的重要程度；日志信息的输出目的地指定了日志将打印到控制台还是文件中；而输出格式则控制了日志信息的显示内容。 <br />2.1.   日志信息的优先级<br /><br />分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。 <br />Log4j建议只使用四个级别，优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别，您可以控制到应用程序中相应级别的日志信息的开关。 <br />假如在一个级别为q的Logger中发生一个级别为p的日志请求，如果p>=q,那么请求将被启用。这是Log4j的核心原则。 <br />比如在这里定义了INFO级别，则应用程序中所有DEBUG级别的日志信息将不被打印出来； <br /><br />2.2.   输出源的使用<br /><br />有选择的能用或者禁用日志请求仅仅是Log4j的一部分功能。Log4j允许日志请求被输出到多个输出源。用Log4j的话说，一个输出源被称做一个Appender。 <br />Appender包括console（控制台）, files（文件）, GUI components（图形的组件）, remote socket servers（socket 服务）, JMS（java信息服务）, NT Event Loggers（NT的事件日志）, and remote UNIX Syslog daemons（远程UNIX的后台日志服务）。它也可以做到异步记录。 <br />一个logger可以设置超过一个的appender。 <br />用addAppender 方法添加一个appender到一个给定的logger。对于一个给定的logger它每个生效的日志请求都被转发到该logger所有的appender上和该logger的父辈logger的appender上。 <br />2.2.1.  ConsoleAppender<br /><br />如果使用ConsoleAppender，那么log信息将写到Console。效果等同于直接把信息打印到System.out上了。 <br />2.2.2.  FileAppender<br /><br />使用FileAppender，那么log信息将写到指定的文件中。这应该是比较经常使用到的情况。 <br />相应地，在配置文件中应该指定log输出的文件名。如下配置指定了log文件名为dglog.txt <br />log4j.appender.A2.File=dglog.txt <br />注意将A2替换为具体配置中Appender的别名。 <br />2.2.3.  DailyRollingAppender<br /><br />使用FileAppender可以将log信息输出到文件中，但是如果文件太大了读起来就不方便了。这时就可以使用DailyRollingAppender。DailyRollingAppender可以把Log信息输出到按照日期来区分的文件中。配置文件就会每天产生一个log文件，每个log文件只记录当天的log信息： <br />log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender <br />log4j.appender.A2.file=dglog <br />log4j.appender.A2.DatePattern='.'yyyy-MM-dd <br />log4j.appender.A2.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A2.layout.ConversionPattern= %5r %-5p %c{2} - %m%n <br />2.2.4.  org.apache.log4j.RollingFileAppender<br /><br />文件大小到达指定尺寸的时候产生一个新的文件。 <br />log4j.appender.R=org.apache.log4j.RollingFileAppender <br />log4j.appender.R.File= ../logs/dglog.log <br /># Control the maximum log file size <br />log4j.appender.R.MaxFileSize=100KB <br /># Archive log files (one backup file here) <br />log4j.appender.R.MaxBackupIndex=1 <br />log4j.appender.R.layout=org.apache.log4j.PatternLayout <br />log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n <br />这个配置文件指定了输出源R，是一个轮转日志文件。最大的文件是100KB，当一个日志文件达到最大尺寸时，Log4J会自动把example.log重命名为dglog.log.1，然后重建一个新的dglog.log文件，依次轮转。 <br /><br />2.2.5.  org.apache.log4j.WriterAppender<br /><br />将日志信息以流格式发送到任意指定的地方。 <br /><br />2.3.  Layout的配置<br /><br />Layout指定了log信息输出的样式。 <br />2.3.1.  布局样式<br /><br />org.apache.log4j.HTMLLayout（以HTML表格形式布局）， <br />org.apache.log4j.PatternLayout（可以灵活地指定布局模式）， <br />org.apache.log4j.SimpleLayout（包含日志信息的级别和信息字符串）， <br />org.apache.log4j.TTCCLayout（包含日志产生的时间、线程、类别等等信息） <br />2.3.2.  格式<br /><br />%m 输出代码中指定的消息 <br />%p 输出优先级，即DEBUG，INFO，WARN，ERROR，FATAL <br />%r 输出自应用启动到输出该log信息耗费的毫秒数 <br />%c 输出所属的类目，通常就是所在类的全名 <br />%t 输出产生该日志事件的线程名 <br />%n 输出一个回车换行符，Windows平台为"rn"，Unix平台为"n" <br />%d 输出日志时间点的日期或时间，默认格式为ISO8601，也可以在其后指定格式，比如：%d{yyy MMM dd HH:mm:ss,SSS}，输出类似：2002年10月18日 22：10：28，921 <br />%l 输出日志事件的发生位置，包括类目名、发生的线程，以及在代码中的行数。举例：Testlog4.main(Test Log4.java:10) <br /><br />2.3.3.  例子<br /><br />例子1：显示日期和log信息 <br />log4j.appender.A2.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %m%n <br />打印的信息是： <br />2002-11-12 11:49:42,866 SELECT * FROM Role WHERE 1=1 order by createDate desc <br /><br />例子2：显示日期，log发生地方和log信息 <br />log4j.appender.A2.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %l "#" %m%n <br />2002-11-12 11:51:46,313 cn.net.unet.weboa.system.dao.RoleDAO.select(RoleDAO.java:409) "#" <br />SELECT * FROM Role WHERE 1=1 order by createDate desc <br />  <br />例子3：显示log级别,时间,调用方法,log信息 <br />log4j.appender.A2.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A2.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} <br />method:%l%n%m%n <br />log信息: <br />[DEBUG] 2002-11-12 12:00:57,376 <br />method:cn.net.unet.weboa.system.dao.RoleDAO.select(RoleDAO.java:409) <br />SELECT * FROM Role WHERE 1=1 order by createDate desc <br /><br />2.4.   配置文件的例子:<br /><br />log4j.rootLogger=DEBUG <br />#将DAO层log记录到DAOLog,allLog中 <br />log4j.logger.DAO=DEBUG,A2,A4 <br />#将逻辑层log记录到BusinessLog,allLog中 <br />log4j.logger.Businesslog=DEBUG,A3,A4 <br /><br />#A1--打印到屏幕上 <br />log4j.appender.A1=org.apache.log4j.ConsoleAppender <br />log4j.appender.A1.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A1.layout.ConversionPattern=%-5p [%t] %37c %3x - %m%n <br /><br />#A2--打印到文件DAOLog中--专门为DAO层服务 <br />log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender <br />log4j.appender.A2.file=DAOLog <br />log4j.appender.A2.DatePattern='.'yyyy-MM-dd <br />log4j.appender.A2.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A2.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} <br />method:%l%n%m%n <br /><br />#A3--打印到文件BusinessLog中--专门记录逻辑处理层服务log信息 <br />log4j.appender.A3=org.apache.log4j.DailyRollingFileAppender <br />log4j.appender.A3.file=BusinessLog <br />log4j.appender.A3.DatePattern='.'yyyy-MM-dd <br />log4j.appender.A3.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A3.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} <br />method:%l%n%m%n <br /><br />#A4--打印到文件alllog中--记录所有log信息 <br />log4j.appender.A4=org.apache.log4j.DailyRollingFileAppender <br />log4j.appender.A4.file=alllog <br />log4j.appender.A4.DatePattern='.'yyyy-MM-dd <br />log4j.appender.A4.layout=org.apache.log4j.PatternLayout <br />log4j.appender.A4.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} <br />method:%l%n%m%n <br /><br /><br />第3章.     API使用<br /><br />log4j使用步骤有3个： <br />3.1.   初始化<br />3.1.1.  Tomcat下的初始化<br /><br />默认的Log4j initialization典型的应用是在web-server 环境下。在tomcat3.x和tomcat4.x下，你应该将配置文件Log4j.properties放在你的web应用程序的WEB-INF/classes 目录下。 <br />Log4j将发现属性文件，并且以此初始化。这是使它工作的最容易的方法。 <br />你也可以选择在运行tomcat前设置系统属性Log4j.configuration 。对于tomcat 3.x，TOMCAT_OPTS 系统变量是用来设置命令行的选项。对于tomcat4.0，用系统环境变量CATALINA_OPTS 代替了TOMCAT_OPTS。 <br />UNIX 命令行 <br />export TOMCAT_OPTS="-DLog4j.configuration=foobar.txt" <br />告诉Log4j用文件foobar.txt作为默认的配置文件。这个文件应该放在WEB-INF/classes 目录下。这个文件将被PropertyConfigurator所读。每个web-application将用不同的默认配置文件，因为每个文件是和它的web-application 相关的。 <br />1. export TOMCAT_OPTS="-DLog4j.debug -DLog4j.configuration=foobar.xml" export TOMCAT_OPTS="-DLog4j.debug -DLog4j.configuration=foobar.xml" <br />告诉Log4j输出Log4j-internal的调试信息，并且用foobar.xml作为默认的配置文件。这个文件应该放在你的web-application的WEB-INF/classes 目录下。因为有.xml的扩展名，它将被DOMConfigurator所读。每个web-application将用不同的默认配置文件。因为每个文件都和它所在的web-application 相关的。 <br />2. set TOMCAT_OPTS=-DLog4j.configuration=foobar.lcf <br />-DLog4j.configuratorClass=com.foo.BarConfigurator <br />告诉Log4j用文件foobar.lcf作为默认的配置文件。这个文件应该放在你的web-application的WEB-INF/classes 目录下。因为定义了Log4j.configuratorClass 系统属性，文件将用自定义的com.foo.barconfigurator类来解析。每个web-application将用不同的默认配置文件。因为每个文件都和它所在的web-application 相关的。 <br />3. set TOMCAT_OPTS=-DLog4j.configuration=file:/c:/foobar.lcf set TOMCAT_OPTS=-DLog4j.configuration=file:/c:/foobar.lcf <br />告诉Log4j用文件foobar.lcf作为默认的配置文件。这个配置文件用URL file:/c:/foobar.lcf定义了全路径名。这样同样的配置文件将被所有的web-application所用。 <br />不同的web-application将通过它们自己的类装载器来装载Log4j。这样，每个Log4j的环境将独立的运作，而没有任何的相互同步。例如：在多个web-application中定义了完全相同的输出源的FileAppenders将尝试写同样的文件。结果好象是缺乏安全性的。你必须确保每个不同的web-application的Log4j配置没有用到同样的系统资源。 <br />3.1.2.  Servlet 的初始化<br /><br />用一个特别的servlet来做Log4j的初始化也是可以的。如下是一个例子： <br />public class Log4jInit extends HttpServlet { <br />public void init() { <br />String prefix = getServletContext().getRealPath("/"); <br />String file = getInitParameter("Log4j-init-file"); <br />if(file != null) { <br />PropertyConfigurator.configure(prefix+file); <br />} <br />} <br />public void doGet(HttpServletRequest req, HttpServletResponse res) { <br />} <br />} <br /><br />在web.xml中定义随后的servlet为你的web-application。 <br />&lt;servlet> <br />&lt;servlet-name>Log4j-init&lt;/servlet-name> <br />&lt;servlet-class>xx.xx.Log4jInit&lt;/servlet-class> <br />&lt;init-param> <br />&lt;param-name>Log4j-init-file&lt;/param-name> <br />&lt;param-value>WEB-INF/classes/Log4j.properties&lt;/param-value> <br />&lt;/init-param> <br />&lt;load-on-startup>1&lt;/load-on-startup> <br />&lt;/servlet> <br />写一个初始化的servlet是最有弹性的初始化Log4j的方法。代码中没有任何限制，你可以在servlet的init方法中定义它。 <br />3.2.   根据配置文件初始化log4j<br /><br />log4j可以使用3中配置器来初始化：BasicConfigurator,DOMConfigurator,PropertyConfigurator <br />其语法为： <br />BasicConfigurator.configure ()： 自动快速地使用缺省Log4j环境。 <br />PropertyConfigurator.configure ( String configFilename) ：读取使用Java的特性文件编写的配置文件。 <br />DOMConfigurator.configure ( String filename ) ：读取XML形式的配置文件。 <br />这里用的是PropertyConfigurator。使用PropertyConfigurator适用于所有的系统。如下的语句： <br />PropertyConfigurator.configure("log4j.properties"); <br />就以log4j.properties为配置文件初始化好了log4j环境。 <br />注意一点：这个语句只需要在系统启动的时候执行一次。例如，在ActionServlet的init()方法中调用一次。 <br />public class ActionServlet extends HttpServlet{ <br />... <br />/** <br />* Initialize global variables <br />*/ <br />public void init() throws ServletException { <br />// 初始化Action资源 <br />try{ <br />initLog4j(); <br />... <br />}catch(IOException e){ <br />throw new ServletException("Load ActionRes is Error"); <br />} <br />} <br />... <br />protected void initLog4j(){ <br />PropertyConfigurator.configure("log4j.properties"); <br />} <br />... <br />}//end class ActionServlet <br /><br />3.3.   在需要使用log4j的地方获取Logger实例<br /><br />使用Log4j，首先就是获取日志记录器，这个记录器将负责控制日志信息。其语法为： <br />public static Logger getLogger( String name)， <br />通过指定的名字获得记录器，如果必要的话，则为这个名字创建一个新的记录器。Name一般取本类的名字，比如： <br />static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () ) ; <br />     Log4j使得通过软件组件命名logger很容易。我们可以通过Logger的静态的初始化方法在每一个类里定义一个logger，令logger的名字等于类名的全局名，而实现logger的命名。这是一个实效的简单的定义一个logger的方法。因为日志输出带有产生日志的类的名字，这个命名策略使得我们更容易定位到一个日志信息的来源。虽然普通，但却是命名logger的常用策略之一。 <br />Log4j没有限制定义logger的可能。开发员可以自由的按照它们的意愿定义logger的名称。 <br />然而，以类的所在位置来命名Logger好象是目前已知的最好方法。 <br /><br />3.4.   使用Logger对象的debug,info,fatal...方法<br /><br />log.debug("it is the debug info"); <br /><br />第4章.     优化<br /><br />一个经常引用的依靠于logging的参数是可以计算的花费。这是一个合理的概念，一个适度的应用程序可能产生成千上万个日志请求。许多努力花在测量和调试logging的优化上。Log4j要求快速和弹性：速度最重要，弹性是其次。 <br />4.1.   日志为禁用时，日志的优化。<br /><br />当日志被彻底的关闭，一个日志请求的花费等于一个方法的调用加上整数的比较时间。在233mhz的Pentium II 机器上这个花费通常在5-50纳秒之间。 <br />然而，方法调用包括参数构建的隐藏花费。 <br />例如，对于logger cat，logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); <br />引起了构建信息参数的花费，例如，转化整数i和entry[i]到一个string，并且连接中间字符串，不管信息是否被输出。这个参数的构建花费可能是很高，它主要决定于被调用的参数的大小。 <br />避免参数构建的花费应如下， <br /><br />if(logger.isDebugEnabled()) <br />{ <br />        logger.debug("result is" + result ); <br />} <br /><br />如果logger的debug被关闭这将不会招致参数构建的花费。另一方面，如果logger是debug的话，它将产生两次判断 logger是否能用的花费。一次是在debugenabled，一次是debug。这是无关紧要的，因为判断日志的能用 只占日志实际花费时间的约1%。 <br />在Log4j里，日志请求在Logger 类的实例里。Logger 是一个类，而不是一个接口。这大量的减少了在方法调用上的弹性化的花费。 <br />当然用户采用预处理或编译时间技术去编译出所有的日志声明。这将导致完美的执行成效。然而因为二进制应用程序不包括任何的日志声明的结果，日志不可能对那个二进制程序开启。以我的观点，以这种较大的代价来换取较小的性能优化是不值得的。 <br /><br />4.2.   当日志状态为启用时，日志的优化。<br /><br />这是本质上的优化logger的层次。当日志状态为开，Log4j依然需要比较请求的级别与logger的级别。然而， logger可能没有被安排一个级别；它们将从它们的father继承。这样，在继承之前，logger可能需要搜索它的ancestor。 <br />这里有一个认真的努力使层次的搜索尽可能的快。例如，子logger仅仅连接到它的存在的father logger。 <br />在先前展示的BasicConfigurator 例子中，名为com.foo.bar 的logger是连接到跟根logger，因此绕过 了不存在的logger com和com.foo。这将显著的改善执行的速度，特别是解析logger的层结构时。 <br />典型的层次结构的解析的花费是logger彻底关闭时的三倍。 <br /><br />4.3.   日志信息的输出时，日志的优化。<br /><br />这是主要花费在日志输出的格式化和发送它到它的输出源上。这里我们再一次的付出努力以使格式化执行的尽可能快。同appender一样。实际上典型的花费大约是100-300毫秒。 <br />详情看org.apache.log4.performance.Logging。 <br />虽然Log4j有许多特点，但是它的第一个设计目标还是速度。一些Log4j的组件已经被重写过很多次以改善性能。不过，投稿者经常提出了新的优化。你应该满意的知道，以SimpleLayout的配置执行测试已经展示了Log4j的输出同System.out.println一样快。
          <br/>
          <span style="color:red;">
            <a href="http://thblovezhj.javaeye.com/blog/172187#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 15 Mar 2008 16:57:58 +0800</pubDate>
        <link>http://thblovezhj.javaeye.com/blog/172187</link>
        <guid>http://thblovezhj.javaeye.com/blog/172187</guid>
      </item>
      <item>
        <title>OSCache使用指南</title>
        <author>thblovezhj</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://thblovezhj.javaeye.com">thblovezhj</a>&nbsp;
          链接：<a href="http://thblovezhj.javaeye.com/blog/172186" style="color:red;">http://thblovezhj.javaeye.com/blog/172186</a>&nbsp;
          发表时间: 2008年03月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          OSCache是当前运用最广的缓存方案，JBoss,Hibernate,Spring等都对其有支持，<br />下面简单介绍一下OSCache的配置和使用过程。<br /><br />1.安装过程<br />从http://www.opensymphony.com/oscache/download.html下载合适的OSCache版本，<br />我下载的是oscache-2.0.2-full版本。<br />解压缩下载的文件到指定目录<br /><br />从解压缩目录取得oscache.jar 文件放到 /WEB-INF/lib 或相应类库目录 目录中，<br />jar文件名可能含有版本号和该版本的发布日期信息等，如oscache-2.0.2-22Jan04.jar<br /><br />如果你的jdk版本为1.3.x,建议在lib中加入Apache Common Lib 的commons-collections.jar包。<br />如jdk是1.4以上则不必<br /><br />从src或etc目录取得oscache.properties 文件，放入src根目录或发布环境的/WEB-INF/classes 目录<br />如你需要建立磁盘缓存，须修改oscache.properties 中的cache.path信息 (去掉前面的#注释)。<br />win类路径类似为c:\\app\\cache<br />unix类路径类似为/opt/myapp/cache<br /><br />拷贝OSCache标签库文件oscache.tld到/WEB-INF/classes目录。<br /><br />现在你的应用目录类似如下：<br />$WEB_APPLICATION\WEB-INF\lib\oscache.jar<br />$WEB_APPLICATION\WEB-INF\classes\oscache.properties<br />$WEB_APPLICATION\WEB-INF\classes\oscache.tld<br /><br /><br />将下列代码加入web.xml文件中<br />&lt;taglib><br />&lt;taglib-uri>oscache&lt;/taglib-uri><br />&lt;taglib-location>/WEB-INF/classes/oscache.tld&lt;/taglib-location><br />&lt;/taglib> <br /><br />为了便于调试日志输出，须加入commons-logging.jar和log4j-1.2.8.jar到当前类库路径中<br /><br />在src目录加入下面两个日志输出配置文件：<br />log4j.properties 文件内容为：<br />log4j.rootLogger=DEBUG,stdout,file<br /><br />log4j.appender.stdout=org.apache.log4j.ConsoleAppender<br />log4j.appender.stdout.layout=org.apache.log4j.PatternLayout<br />log4j.appender.stdout.layout.ConversionPattern=[start]%d{yyyy/MM/dd/ HH:mm:ss}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n<br /><br /><br /><br />log4j.appender.file=org.apache.log4j.RollingFileAppender<br />log4j.appender.file.File=oscache.log<br />log4j.appender.file.MaxFileSize=100KB<br />log4j.appender.file.MaxBackupIndex=5<br />log4j.appender.file.layout=org.apache.log4j.PatternLayout<br />log4j.appender.file.layout.ConversionPattern=[start]%d{yyyy/MM/dd/ HH:mm:ss}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n<br /><br /><br />log4j.logger.org.apache.commons=ERROR<br />log4j.logger.com.opensymphony.oscache.base=INFO<br /><br /><br />commons-logging.properties 文件内容为<br /><br />org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JCategoryLog<br /><br />2.oscache.properties 文件配置向导 <br /><br />cache.memory<br />值为true 或 false ，默认为在内存中作缓存，<br />如设置为false，那cache只能缓存到数据库或硬盘中，那cache还有什么意义：）<br /><br />cache.capacity<br />缓存元素个数<br /><br />cache.persistence.class<br />持久化缓存类，如此类打开，则必须设置cache.path信息<br /><br />cache.cluster 相关<br />为集群设置信息。<br />如<br />cache.cluster.multicast.ip为广播IP地址<br />cache.cluster.properties为集群属性<br /><br /><br />3.OSCache的基本用法<br /><br />cache1.jsp 内容如下<br /><br />&lt;%@ page import="java.util.*" %><br />&lt;%@ taglib uri="oscache" prefix="cache" %><br /><br />&lt;html><br />&lt;body><br /><br />没有缓存的日期: &lt;%= new Date() %>&lt;p><br />&lt;!--自动刷新--><br />&lt;cache:cache time="30"><br />每30秒刷新缓存一次的日期: &lt;%= new Date() %> <br />&lt;/cache:cache><br />&lt;!--手动刷新--><br />&lt;cache:cache key="testcache"><br />手动刷新缓存的日期: &lt;%= new Date() %> &lt;p><br />&lt;/cache:cache><br />&lt;a href="cache2.jsp">手动刷新&lt;/a><br /><br />&lt;/body><br />&lt;/html><br /><br />cache2.jsp 执行手动刷新页面如下<br />&lt;%@ taglib uri="oscache" prefix="cache" %><br /><br />&lt;html><br />&lt;body><br /><br />缓存已刷新...&lt;p><br /><br />&lt;cache:flush key="testcache" scope="application"/><br /><br />&lt;a href="cache1.jsp">返回&lt;/a><br /><br />&lt;/body><br />&lt;/html><br /><br /><br />你也可以通过下面语句定义Cache的有效范围,如不定义scope,scope默认为Applcation<br />&lt;cache:cache time="30" scope="session"><br />...<br />&lt;/cache:cache><br /><br />4. 缓存过滤器 CacheFilter <br /><br />你可以在web.xml中定义缓存过滤器，定义特定资源的缓存。<br />&lt;filter><br />&lt;filter-name>CacheFilter&lt;/filter-name><br />&lt;filter-class>com.opensymphony.oscache.web.filter.CacheFilter&lt;/filter-class><br />&lt;init-param><br />&lt;param-name>time&lt;/param-name><br />&lt;param-value>60&lt;/param-value><br />&lt;/init-param><br />&lt;init-param><br />&lt;param-name>scope&lt;/param-name><br />&lt;param-value>session&lt;/param-value><br />&lt;/init-param><br />&lt;/filter><br />&lt;filter-mapping><br />&lt;filter-name>CacheFilter&lt;/filter-name><br />&lt;url-pattern>*.jsp&lt;/url-pattern><br />&lt;/filter-mapping><br />上面定义将缓存所有.jsp页面，缓存刷新时间为60秒，缓存作用域为Session<br /><br />注意，CacheFilter只捕获Http头为200的页面请求，即只对无错误请求作缓存，<br />而不对其他请求（如500,404,400）作缓存处理
          <br/>
          <span style="color:red;">
            <a href="http://thblovezhj.javaeye.com/blog/172186#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 15 Mar 2008 16:41:58 +0800</pubDate>
        <link>http://thblovezhj.javaeye.com/blog/172186</link>
        <guid>http://thblovezhj.javaeye.com/blog/172186</guid>
      </item>
  </channel>
</rss>