<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>蜗牛也是牛</title>
    <description></description>
    <link>http://snailness.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>十个笑话让你领悟人生</title>
        <author>snailness</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://snailness.javaeye.com">snailness</a>&nbsp;
          链接：<a href="http://snailness.javaeye.com/blog/224428" style="color:red;">http://snailness.javaeye.com/blog/224428</a>&nbsp;
          发表时间: 2008年08月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 父子二人看到一辆十分豪华的进口轿车。儿子不屑地对他的父亲说：&ldquo;坐这种车的人，肚子里一定没有学问！&rdquo;父亲则轻描淡写地回答：&ldquo;说这种话的人，口袋里一定没有钱！&rdquo; <br /><br />　　&mdash;&mdash;你对事情的看法，是不是也反映出你内心真正的态度？ <br /><br />　　晚饭后，母亲和女儿一块儿洗碗盘，父亲和儿子在客厅看电视。突然，厨房里传来打破盘子的响声，然后一片沉寂。儿子望着他父亲，说道：&ldquo;一定是妈妈打破的。&rdquo;&ldquo;你怎么知道？&rdquo;&ldquo;她没有骂人。&rdquo; <br /><br />　　&mdash;&mdash;我们习惯以不同的标准来看人看己，以致往往是责人以严，待己以宽。 <br /><br />　　有两个台湾观光团到日本伊豆半岛旅游，路况很坏，到处都是坑洞。一位导游连声说路面简直像麻子一样。而另一个导游却诗意盎然地对游客说：&ldquo;我们现在走的正是赫赫有名的伊豆迷人酒窝大道。&rdquo; <br /><br />　　&mdash;&mdash;虽是同样的情况，然而不同的意念，就会产生不同的态度。思想是何等奇妙的事，如何去想，决定权在你。 <br /><br />　　同样是小学三年级的学生，他们将来的志愿同是当小丑。中国老师斥之为：&ldquo;胸无大志，孺子不可教也！&rdquo;外国老师则会说：&ldquo;愿你把欢笑带给全世界！&rdquo; <br /><br />　　&mdash;&mdash;身为长辈的我们，不但要求多于鼓励，更以狭窄界定了成功的定义。 <br /><br />　　妻子正在厨房炒菜。丈夫在她旁边一直唠叨不停：&ldquo;慢些、小心！火太大了。赶快把鱼翻过来、油放太多了！&rdquo;妻子脱口而出：&ldquo;我懂得怎样炒菜。&rdquo;丈夫平静地答道：&ldquo;我只是要让你知道，我在开车时，你在旁边喋喋不休，我的感觉如何&hellip;&hellip;&rdquo; <br /><br />　　&mdash;&mdash;学会体谅他人并不困难，只要你愿意认真地站在对方的角度和立场看问题。 <br /><br />　　一辆载满乘客的公共汽车沿着下坡路快速前进着，有一个人在后面紧紧追赶着这辆车子。一个乘客从车窗中伸出头来对追车子的人说：&ldquo;老兄！算啦，你追不上的！&rdquo;&ldquo;我必须追上它，&rdquo;这人气喘吁吁地说：&ldquo;我是这辆车的司机！&rdquo; <br /><br />　　&mdash;&mdash;有些人必须非常认真努力，因为不这样的话，后果就十分悲惨了！然而也正因为必须全力以赴，潜在的本能和不为人知的特质终将充分展现出来。 <br /><br />　　甲：&ldquo;新搬来的邻居好可恶，昨天晚上三更半夜跑来猛按我家的门铃。&rdquo;乙：&ldquo;的确可恶！你有没有马上报警？&rdquo;甲：&ldquo;没有。我当他们是疯子，继续吹我的小喇叭。&rdquo; <br /><br />　　&mdash;&mdash;事出必有因，如果能先看到自己的不是，答案就会不一样。 <br /><br />　　张三在山间小路开车，正当他悠哉地欣赏美丽风景时，突然迎面开来的货车司机摇下窗户大喊一声：&ldquo;猪！&rdquo;张三越想越气，也摇下车窗大骂：&ldquo;你才是猪！&rdquo;刚骂完，他便迎头撞上一群过马路的猪。 <br /><br />　　&mdash;&mdash;不要错误地诠释别人的好意，那只会让自己吃亏，并且使别人受辱。 <br /><br />　　小男孩问爸爸：&ldquo;是不是做父亲的总比做儿子的知道得多？&rdquo;爸爸回答：&ldquo;当然啦！&rdquo;&ldquo;电灯是谁发明的？&rdquo;&ldquo;爱迪生。&rdquo;&ldquo;那爱迪生的爸爸怎么没有发明电灯？&rdquo; <br /><br />　　&mdash;&mdash;权威往往只是一个经不起考验的空壳子，尤其在现今这个多元开放的时代。 <br /><br />　　小明洗澡时不小心吞下一小块肥皂，他的妈妈慌慌张张地打电话给家庭医生求助。医生说：&ldquo;我现在还有几个病人在，可能要半小时后才能赶过去。&rdquo;小明妈妈说：&ldquo;在你来之前，我该做什么？&rdquo;医生说：&ldquo;给小明喝一杯白开水，然后用力跳一跳，你就可以让小明用嘴巴吹泡泡消磨时间了。&rdquo; <br /><br />　　&mdash;&mdash;事情既然已经发生了，何不坦然自在地面对。担心不如宽心，穷紧张不如穷开心</p>
          <br/>
          <span style="color:red;">
            <a href="http://snailness.javaeye.com/blog/224428#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>Tue, 05 Aug 2008 11:22:12 +0800</pubDate>
        <link>http://snailness.javaeye.com/blog/224428</link>
        <guid>http://snailness.javaeye.com/blog/224428</guid>
      </item>
      <item>
        <title>关于成熟</title>
        <author>snailness</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://snailness.javaeye.com">snailness</a>&nbsp;
          链接：<a href="http://snailness.javaeye.com/blog/221934" style="color:red;">http://snailness.javaeye.com/blog/221934</a>&nbsp;
          发表时间: 2008年07月31日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>成熟是一个很痛的词，它不一定会得到什么，却一定会失去什么......</p>
          <br/>
          <span style="color:red;">
            <a href="http://snailness.javaeye.com/blog/221934#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>Thu, 31 Jul 2008 00:19:07 +0800</pubDate>
        <link>http://snailness.javaeye.com/blog/221934</link>
        <guid>http://snailness.javaeye.com/blog/221934</guid>
      </item>
      <item>
        <title>应用优化自查</title>
        <author>snailness</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://snailness.javaeye.com">snailness</a>&nbsp;
          链接：<a href="http://snailness.javaeye.com/blog/220915" style="color:red;">http://snailness.javaeye.com/blog/220915</a>&nbsp;
          发表时间: 2008年07月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h2>应用优化自查</h2>
<div class="t_msgfont" id="postmessage_41937"><br /><span style="color: #0000ff;"><span class="t_tag" id="tag_0.6506950774048305"><span class="t_tag" onclick="tagshow(event)">数据</span>库</span>相关</span><br />&nbsp;&nbsp;&nbsp;使用了 P6SPY/SQL Moniter 吗? <br />&nbsp; &nbsp;&nbsp; &nbsp; 好<span class="t_tag" onclick="tagshow(event)">工具</span>不用白不用。<br />&nbsp; &nbsp;一个操作内有重复执行的<span class="t_tag" onclick="tagshow(event)">SQL</span>吗? <br />&nbsp; &nbsp;&nbsp; &nbsp; 考虑 cache 吧。<br />&nbsp; &nbsp;有执行特别慢的SQL吗？<br />&nbsp; &nbsp;&nbsp; &nbsp; 拎出来，先试试自己建立<span class="t_tag" onclick="tagshow(event)">索引</span>吧。<br />&nbsp; &nbsp;&nbsp; &nbsp; 考虑一下，是否有不必要的逻辑存在。<br />&nbsp; &nbsp;有多次与数据库<span class="t_tag" onclick="tagshow(event)">交互</span>的逻辑处理吗? <br />&nbsp; &nbsp;&nbsp; &nbsp; 可以尝试考虑 procedure<br />&nbsp; &nbsp;一个<span class="t_tag" onclick="tagshow(event)">页面</span>上有很多统计数字吗? <br />&nbsp; &nbsp;&nbsp; &nbsp; 实时性不高，可以考虑晚上定时刷新做cache，需和用户沟通新的统计时机<span class="t_tag" onclick="tagshow(event)">问题</span><br />&nbsp; &nbsp;&nbsp; &nbsp; 实时性高，考虑用 AJAX ,不影响页面整个的展现和显示<br /><span style="color: #0000ff;">页面相关</span><br />&nbsp; &nbsp;一个<span class="t_tag" onclick="tagshow(event)">网页</span>的内容太多了<br />&nbsp; &nbsp;&nbsp; &nbsp; 图片太多？优化吧<br />&nbsp; &nbsp;&nbsp; &nbsp; js 太多，按逻辑理顺。除掉不需要引用的</div>
          <br/>
          <span style="color:red;">
            <a href="http://snailness.javaeye.com/blog/220915#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>Tue, 29 Jul 2008 09:53:09 +0800</pubDate>
        <link>http://snailness.javaeye.com/blog/220915</link>
        <guid>http://snailness.javaeye.com/blog/220915</guid>
      </item>
      <item>
        <title>SQL 在什么情况下使用全表扫描</title>
        <author>snailness</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://snailness.javaeye.com">snailness</a>&nbsp;
          链接：<a href="http://snailness.javaeye.com/blog/211420" style="color:red;">http://snailness.javaeye.com/blog/211420</a>&nbsp;
          发表时间: 2008年07月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>　　1：对返回的行无任何限定条件，即没有where 字句。</p>
<p>　　2：对数据表与任何索引主列相对应的行限定条件，例如：在City-State-Zip列创建了三列复合索引，那么仅对State有列限定条件不能使用这个索引，因为State不是索引的主列。</p>
<p>　　3：对索引的主列有限定条件，但是条件在表达式里使用，例如：在City上有索引，但是若使用表达式，如：</p>
<p>　　以下是引用片段：</p>
<p>　　where upper(city)='TokYo' 或</p>
<p>　　City || 'X' like 'TOKYO%'，</p>
<p>　　那么不会使用索引。</p>
<p>　　4：对索引的主列有限定条件，但是条件或者是Null或者是不相等。例如：在City上有索引，但是若使用表达式，如:</p>
<p>　　以下是引用片段：</p>
<p>　　where City is null，where City is</p>
<p>　　not null，Where city!='TOKYO'.</p>
<p>　　5: 对索引的主列有限定条件，但是条件使用like操作以及值以&lsquo;%&rsquo;开始或者值是一个赋值变量。例如：</p>
<p>　　以下是引用片段：</p>
<p>　　where City like '%YOK%'</p>
<p>　　where City like: City_bind_Variable xl_rao</p>
          <br/>
          <span style="color:red;">
            <a href="http://snailness.javaeye.com/blog/211420#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>Fri, 04 Jul 2008 11:17:54 +0800</pubDate>
        <link>http://snailness.javaeye.com/blog/211420</link>
        <guid>http://snailness.javaeye.com/blog/211420</guid>
      </item>
      <item>
        <title>数据库之事务和锁</title>
        <author>snailness</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://snailness.javaeye.com">snailness</a>&nbsp;
          链接：<a href="http://snailness.javaeye.com/blog/210604" style="color:red;">http://snailness.javaeye.com/blog/210604</a>&nbsp;
          发表时间: 2008年07月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 关系型数据库有四个显著的特征，即安全性、完整性、并发性和监测性。数据库的安全性就是要保证数据库中数据的安全，防止未授权用户随意修改数据库中
的数据，确保数据的安全。在大多数数据库管理系统中，主要是通过许可来保证数据库的安全性。完整性是数据库的一个重要特征，也是保证数据库中的数据切实有
效、防止错误、实现商业规则的一种重要机制。在数据库中，区别所保存的数据是无用的垃圾还是有价值的信息，主要是依据数据库的完整性是否健全。在SQL
Server
7.0中，数据的完整性是通过一系列逻辑来保障的，这些逻辑分为三个方面，即实体完整性、域完整性和参考完整性。对任何系统都可以这样说，没有监测，就没
有优化。这句话用在数据库管理系统方面，也是切合实际的。只有通过对数据库进行全面的性能监测，也才能发现影响系统性能的因素和瓶颈，才能针对瓶颈因素，
采取切合实际策略，解决问题，提高系统的性能。并发性也是一个非常重要的概念，它是用来解决多个用户对同一数据进行操作时的问题。特别是对于网络数据库来
说，这个特点更加突出。提高数据库的处理速度，单单依靠提高计算机的物理速度是不够的，还必须充分考虑数据库的并发性问题，提高数据库并发性的效率。那么
如何保证并发性呢？在这个面向下一世纪的数据库产品SQL Server 7.0中，通过使用事务和锁机制，解决了数据库的并发性问题。
</p>
<p><a name="2"></a>
<strong>概念和特点</strong>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 事务和锁是两个紧密联系的概念。事务就是一个单元的工作，包括一系列的操作这些操作要么全部成功，要么全部失败。事务确保多个数据的修改作为一个单
元来处理。例如，在银行业务中，有一条记帐原则，即有借有贷，借贷相等。那么为了保证这种原则，就得有确保借和贷的登记要么同时成功，要么同时失败。如果
出现只记录了借，或者只记录了贷，那么就违反了记帐原则，就会出现记错帐的情况。SQL
Server通过支持事务机制管理多个事务，保证事务的一致性。事务使用锁，防止其他用户修改另外一个还没有完成的事务中的数据。对于多用户系统来说，锁
机制是必须的。在SQL Server 7.0中，使用事务日志来保证修改的完整性和可恢复性。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; SQL Server有多种锁，允许事务锁定不同的资源。锁就是保护指定的资源，不被其他事务操作。为了最小化锁的成本，SQL
Server自动地以与任务相应等级的锁来锁定资源对象。锁定比较小的对象，例如锁定行，虽然可以提高并发性，但是却有较高的开支，因为如果锁定许多行，
那么需要占有更多的锁。锁定比较大的对象，例如锁定表，会大大降低并发性，因为锁定整个表就限制了其他事务访问该表的其他部分，但是成本开支比较低，因为
只需维护比较少的锁。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 事务和锁具有以下特点:</p>
<ul>
<li>事务是一个单元的工作，要么全做，要么全不做 </li>
<li>事务保证操作的一致性和可恢复性 </li>
<li>每一条Transact-SQL语句都可以是一个事务 </li>
<li>实际使用的事务是用户定义的事务，它包括一系列操作或者语句 </li>
<li>在多服务器环境中，使用用户定义的分布式事务，保证操作的一致性 </li>
<li>锁是保证并发控制的手段 </li>
<li>可以锁定的资源包括行、页、簇、表和数据库 </li>
<li>锁的类型主要包括共享锁和排它锁 </li>
<li>特殊类型的锁包括意图锁、修改锁和模式锁 </li>
<li>共享锁允许其他事务继续使用锁定的资源 </li>
<li>排它锁只允许一个事务访问数据 </li>
<li>系统本身可以处理死锁 </li>
<li>用户可以根据实际情况定制锁的一些特征 </li>
</ul>
<p><a name="3"></a>
<strong>事务</strong>
</p>
<p>事务的定义</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
事务是指一个单元的工作，这些工作要么全做，要么全部不做。作为一个逻辑单元，必须具备四个属性：自动性、一致性、独立性和持久性。自动性是指事务必须是
一个自动的单元工作，要么执行全部数据的修改，要么全部数据的修改都不执行。一致性是指当事务完成时，必须使所有数据都具有一致的状态。在关系型数据库
中，所有的规则必须应用到事务的修改上，以便维护所有数据的完整性。所有的内部数据结构，例如树状的索引与数据之间的链接，在事务结束之后，必须保证正
确。独立性是指并行事务的修改必须与其他并行事务的修改相互独立。一个事务看到的数据要么是另外一个事务修改这些事务之前的状态，要么是第二个事务已经修
改完成的数据，但是这个事务不能看到正在修改的数据。这种特征也称为串行性。持久性是指当一个事务完成之后，它的影响永久性的产生在系统中，也就是这种修
改写到了数据库中。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 事务机制保证一组数据的修改要么全部执行，要么全部不执行。SQL
Server使用事务保证数据的一致性和确保在系统失败时的可恢复性。事务是一个可以恢复的单元的工作，由一条或者多条Transact-SQL语句组
成，可以影响到表中的一行或者多行数据。事务打开以后，直到事务成功完成之后提交为止，或者到事务执行失败全部取消或者滚回去为止。</p>
<p>事务的工作原理图</p>
<p>事务确保数据的一致性和可恢复性。事务的工作原理如图1所示。</p>
<p><img src="http://www.microsoft.com/china/msdn/archives/technic/develop/database/images/0522c-1.gif" height="315" alt="" width="231" />
</p>
<p>图1&nbsp;&nbsp;&nbsp; 事务的工作原理图</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
事务开始之后，事务所有的操作都陆续写到事务日志中。写到日志中的操作，一般有两种：一种是针对数据的操作，一种是针对任务的操作。针对数据的操作，例如
插入、删除和修改，这是典型的事务操作，这些操作的对象是大量的数据。有些操作是针对任务的，例如创建索引，这些任务操作在事务日志中记录一个标志，用于
表示执行了这种操作。当取消这种事务时，系统自动执行这种操作的反操作，保证系统的一致性。系统自动生成一个检查点机制，这个检查点周期地发生。检查点的
周期是系统根据用户定义的时间间隔和系统活动的频度由系统自动计算出来的时间间隔。检查点周期地检查事务日志，如果在事务日志中，事务全部完成，那么检查
点将事务日志中的事务提交到数据库中，并且在事务日志中做一个检查点提交标记。如果在事务日志中，事务没有完成，那么检查点将事务日志中的事务不提交到数
据库中，并且在事务日志中做一个检查点未提交标记。事务的恢复以及检查点保护系统的完整和可恢复，可以使用如图2所示的示例说明。</p>
<p><img src="http://www.microsoft.com/china/msdn/archives/technic/develop/database/images/0522c-2.gif" height="279" alt="" width="495" />
 </p>
<p>图2&nbsp;&nbsp;&nbsp; 事务恢复和检查点示例</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
在这个示例图中，有五个事务：事务1、事务2、事务3、事务4和事务5。方框表示事务的开始和完成提交。水平方向表示时间。检查点表示在某一时间点发生检
查点机制，系统失败表示在某一时间点由于断电、系统软件失败等原因而发生的系统失败。事务1的完成发生在检查点发生之间，所以事务1被提交到数据库中。事
务2和事务4的完成发生在系统失败之前，所以这两个事务可以被系统向前滚动提交到数据库中。事务3和事务5由于系统失败而没有完成，所以这两个事务被取
消。</p>
<p><a name="4"></a>
<strong>使用事务的考虑</strong>
</p>
<p>在使用事
务时，原则上应该使事务尽可能得短并且要避免事务嵌套。事务应该尽可能得短，这是因为比较长的事务增加了事务占用数据的时间，使其它必须等待访问该事务锁
定数据的事务，延长了等待访问数据的时间。在使用事务时，为了使事务尽可能得短，应该采取一些相应的方法。为了最小化时间，在使用一些Transact-
SQL语句时，一定要非常小心。例如，当使用循环语句WHILE时，一定要事先确认循环的长度和占用的时间，使这种循环在完成相应的功能之前，一定要确保
循环尽可能得短。在开始事务之前，一定要了解需要用户交互式操作才能得到的信息。这样，在事务的进行过程中，就可以避免进行一些耗费时间的交互式操作，缩
短事务进程的时间。在一个用户定义的事务中，应该尽可能地使用一些数据操纵语言，例如INSERT、UPDATE和DELETE语句，因为这些语句主要是
操纵数据库中的数据。而对于一些数据定义语言，应该尽可能地少用或者不用，因为这些数据定义语言的操作既占用比较长的时间，又占用比较多的资源，并且这些
数据定义语言的操作通常不涉及到数据，所以应该在事务中尽可能地少用或者不用这些操作。另外，在使用数据操纵语言时，要注意，一定要在这些语句中使用条件
判断语句，使得这些数据操纵语言涉及到尽可能少的记录，从而缩短事务的处理时间。</p>
<p>在嵌套事务时，也要注意一些问题。虽然说，在事务中间嵌套事务是可能的，并不影响SQL Server处理事务的性能。但是，实际上，使用嵌套事务，除了把事务搞得更加复杂之外，并没有这么明显的好处。因此，不建议使用嵌套事务。</p>
<p><a name="5"></a>
<strong>事务的类型</strong>
</p>
<p>根
据系统的设置，可以把事务分成两种类型。一种是系统提供的事务，另一种是用户定义的事务。系统提供的事务是指在执行某些语句时，一条语句就是一个事务。这
时要明确，一条语句的对象既可能是表中的一行数据，也可能是表中的多行数据，甚至是表中的全部数据。因此，只有一条语句构成的事务也可能包含了多行数据的
处理。例如执行下面这条数据操纵语句：</p>
<p>UPDATE&nbsp;&nbsp; authors</p>
<p>SET state = &lsquo;CA&rsquo;</p>
<p>这是一条语句，这条语句本身就构成了一个事务。这条语句由于没有使用条件限制，那么这条语句就是修改表中的全部数据。所以这个事务的对象，就是修改表中的全部数据。如果authors表中有1000行数据，那么这1000行数据的修改要么全部成功，要么全部失败。</p>
<p>另
外一种事务，是用户明确定义的事务。在实际应用中，大多数的事务处理就是采用了用户定义的事务来处理。在开发应用程序时，可以使用BEGIN
TRANSACTION语句来定义明确的用户定义的事务。在使用用户定义的事务时，一定要注意两点：一是事务必须有明确的结束语句来结束。如果不使用明确
的结束语句来结束，那么系统可能把从事务开始到用户关闭连接之间的全部操作都作为一个事务来对待。事务的明确结束可以使用这样两个语句中的一
个：COMMIT语句和ROLLBACK语句。COMMIT语句是提交语句，将全部完成的语句明确地提交到数据库中。ROLLBACK语句是取消语句，该
语句将事务的操作全部取消，即表示事务操作失败。</p>
<p>还有一种特殊的用户定义的事务，这就是分布式事务。前面提到的事务都是在一个
服务器上的操作，其保证的数据完整性和一致性是指一个服务器上的完整性和一致性。但是，如果一个比较复杂的环境，可能有多台服务器，那么要保证在多服务器
环境中事务的完整性和一致性，就必须定义一个分布式事务。在这个分布式事务中，所有的操作都可以涉及对多个服务器的操作，当这些操作都成功时，那么所有这
些操作都提交到相应服务器的数据库中，如果这些操作中有一条操作失败，那么这个分布式事务中的全部操作都被取消。</p>
<p><a name="6"></a>
<strong>锁和锁的作用</strong>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
锁就是防止其他事务访问指定的资源的手段。锁是实现并发控制的主要方法，是多个用户能够同时操纵同一个数据库中的数据而不发生数据不一致现象的重要保障。
一般来说，锁可以防止脏读、不可重复读和幻觉读。脏读就是指当一个事务正在访问数据，并且对数据进行了修改，而这种修改还没有提交到数据库中，这时，另外
一个事务也访问这个数据，然后使用了这个数据。因为这个数据是还没有提交的数据，那么另外一个事务读到的这个数据是脏数据，依据脏数据所做的操作可能是不
正确的。不可重复读是指在一个事务内，多次读同一数据。在这个事务还没有结束时，另外一个事务也访问该同一数据。那么，在第一个事务中的两次读数据之间，
由于第二个事务的修改，那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的，因此称为是不可重复读。幻觉
读是指当事务不是独立执行时发生的一种现象，例如第一个事务对一个表中的数据进行了修改，这种修改涉及到表中的全部数据行。同时，第二个事务也修改这个表
中的数据，这种修改是向表中插入一行新数据。那么，以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行，就好象发生了幻觉一样。</p>
<p><a name="7"></a>
<strong>空间管理</strong>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
锁是防止其他事务访问指定的资源控制、实现并发控制的一种主要手段。为了提高系统的性能，加快事务的处理速度，缩短事务的等待时间，应该使锁定的资源最小
化。为了控制锁定的资源，应该首先了解系统的空间管理。在SQL
Server系统中，最小的空间管理单位是页，一个页有8K。所有的数据、日志、索引都存放在页上。另外，使用页有一个限制，这就是表中的一行数据必须在
同一个页上，不能跨页。页上面的空间管理单位是簇，一个簇是8个连续的页。表和索引的最小占用单位是簇。数据库是由一个或者多个表或者索引组成，即是由多
个簇组成。SQL Server系统的空间管理结构示意图如图3所示。</p>
<p><img src="http://www.microsoft.com/china/msdn/archives/technic/develop/database/images/0522c-3.gif" height="242" alt="" width="411" />
</p>
<p>&nbsp;</p>
<p>图3&nbsp;&nbsp; SQL Server空间管理</p>
<p><a name="8"></a>
<strong>可以锁定的资源</strong>
</p>
<p>为
了优化系统的并发性，应该根据事务的大小和系统活动的程度，锁定不同的资源。也就是说，既可以锁定比较大的资源，也可以锁定比较小的资源。在SQL
Server系统中，已经比较完善地实现了这些要求。在SQL Server
7.0中，可以锁定的资源有多种，这些可以锁定的资源分别是行、页、簇、表和数据库，他们对应的锁分别是行级锁、页级锁、簇级锁、表级锁和数据库级锁。在
如图4所示的结构中，数据行存放在页上，页存放在簇上，一个表有若干个簇组成，而若干个表组成了数据库。在这些可以锁定的资源中，最基本的资源是行、页和
表，而簇和数据库是特殊的可以锁定的资源。</p>
<p><img src="http://www.microsoft.com/china/msdn/archives/technic/develop/database/images/0522c-4.gif" height="197" alt="" width="304" />
</p>
<p>&nbsp;</p>
<p>图4&nbsp;&nbsp; 表、页、行的结构图</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
行是可以锁定的最小空间。在SQL Server
7.0中，实现了行级锁。行级锁就是指事务在操纵数据的过程中，锁定一行或者若干行数据，其他事务不能同时处理这些行的数据。行级锁占用的数据资源最少，
所以在事务的处理过程中，允许其他事务继续操纵同一个表或者同一个页的其他数据，大大降低了其他事务等待处理的时间，提高了系统的并发性。页级锁是一种最
优锁，因为行级锁不可能出现数据既被占用又没有使用的浪费现象。在图5中，椭圆形表示行级锁占用的数据，而椭圆形之外的其他数据仍然可以由其他事务使用。
行级锁是SQL Server 7.0的重要特征，它的引入引起了数据存储引擎的改变。</p>
<p><img src="http://www.microsoft.com/china/msdn/archives/technic/develop/database/images/0522c-5.gif" height="200" alt="" width="319" />
</p>
<p>&nbsp;</p>
<p>图5&nbsp;&nbsp; 行级锁</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
页级锁是指在事务的操纵过程中，无论事务处理数据的多少，每一次都锁定一页，在这个页上的数据不能被其他事务操纵。在SQL Server
7.0以前，使用的是页级锁。页级锁锁定的资源比行级锁锁定的数据资源多。在页级锁中，即使是一个事务只操纵页上的一行数据，那么该页上的其他数据行也不
能被其他事务使用。因此，当使用页级锁时，会出现数据的浪费现象，也就是说，在同一个页上会出现数据被占用却没有使用的现象。在这种现象中，数据的浪费最
多不超过一个页上的数据行。在图6中，圆形区表示一个页级锁，在这个圆形区内，只有一个事务可以可以使用圆形区中的数据，其他事务只能使用圆形区以外的数
据。</p>
<p><img src="http://www.microsoft.com/china/msdn/archives/technic/develop/database/images/0522c-6.gif" height="201" alt="" width="319" />
</p>
<p>&nbsp;</p>
<p>图6&nbsp;&nbsp; 页级锁</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
簇级锁是一种特殊类型的锁，只能用在一些特殊的情况下。簇级锁就是指事务占用一个簇，这个簇不能同时被其他事务占用。例如在创建数据库和创建表时，系统分
配物理空间时使用这种类型的锁。系统是按照簇分配空间的。当系统分配空间时，使用簇级锁，防止其他事务同时使用同一个簇。当系统完成分配空间之后，就不再
使用这种类型的簇级锁。特别是，当涉及到对数据操作的事务时，不使用簇级锁。簇级锁的结构如图7所示。椭圆形区域表示簇级锁占用的数据，其他事务只能使用
该簇以外的其他簇。</p>
<p><img src="http://www.microsoft.com/china/msdn/archives/technic/develop/database/images/0522c-7.gif" height="207" alt="" width="457" />
</p>
<p>图7&nbsp;&nbsp; 簇级锁</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
表级锁也是一个非常重要的锁。表级锁是指事务在操纵某一个表的数据时，锁定了这个数据所在的整个表，其他事务不能访问该表中的其他数据。当事务处理的数据
量比较大时，一般使用表级锁。表级锁的特点是使用比较少的系统资源，但是却占用比较多的数据资源。与行级锁和页级锁相比，表级锁占用的系统资源例如内存比
较少，但是占用的数据资源却是最大。在表级锁时，有可能出现数据的大量浪费现象，因为表级锁锁定整个表，那么其他的事务都不能操纵表中的其他数据。这样，
会延长其他事务等待处理的时间，降低系统的并发性能。表级锁的结构示意图如图8所示，椭圆形表示表级锁。</p>
<p><img src="http://www.microsoft.com/china/msdn/archives/technic/develop/database/images/0522c-8.gif" height="240" alt="" width="457" />
</p>
<p>图8&nbsp;&nbsp; 表级锁 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
数据库级锁是指锁定整个数据库，防止任何用户或者事务对锁定的数据库进行访问。数据库级锁是一种非常特殊的锁，它只是用于数据库的恢复操作过程中。这种等
级的锁是一种最高等级的锁，因为它控制整个数据库的操作。只要对数据库进行恢复操作，那么就需要设置数据库为单用户模式，这样系统就能防止其他用户对该数
据库进行各种操作。数据库级锁的结构示意图如图9所示。严格地说，数据库级锁不是一种锁，而是一种类似锁的一种单用户模式机制。但是，这种单用户模式机制
非常类似锁机制，因此也可以把这种单用户模式称为数据库级锁。</p>
<p>&nbsp;</p>
<p><img src="http://www.microsoft.com/china/msdn/archives/technic/develop/database/images/0522c-9.gif" height="198" alt="" width="433" />
</p>
<p>图9&nbsp;&nbsp; 数据库级锁</p>
<p><a name="9"></a>
<strong>锁的类型和其兼容性</strong>
</p>
<p>锁定资源的方式有两种基本形式，一种形式是读操作要求的共享锁，另一种形式是写操作要求的排它锁。除了这两种基本类型的所，还有一些特殊情况的锁，例如意图锁、修改锁和模式锁。在这些各种类型的锁中，有些类型的锁之间是可以兼容的，有些类型的锁之间是不兼容的。</p>
<p>共
享锁允许并行事务读取同一种资源，这时的事务不能修改访问的数据。当使用共享锁锁定资源时，不允许修改数据的事务访问数据。当读取数据的事务读完数据之
后，立即释放所占用的资源。一般地，当使用SELECT语句访问数据时，系统自动对所访问的数据使用共享锁锁定。对于那些修改数据的事务，例如使用
INSERT、UPDATE和DELETE语句，系统自动在所修改的事务上放置排它锁。排它锁就是在同一时间内只允许一个事务访问一种资源，其他事务都不
能在有排它锁的资源上访问。在有排它锁的资源上，不能放置共享锁，也就是说不允许可以产生共享锁的事务访问这些资源。只有当产生排它锁的事务结束之后，排
它锁锁定的资源才能被其他事务使用。</p>
<p>除了上面的基本锁以外，根据不同的情况，SQL Server还可以使用一些其他类型的锁。这些特殊类型的锁包括意图锁、修改锁和模式锁。</p>
<p>系
统使用意图锁来最小化锁之间的冲突。意图锁建立一个锁机制的分层结构，这种结构依据锁定的资源范围从低到高依次是行级锁层、页级锁层和表级锁层。意图锁表
示系统希望在层次低的资源上获得共享锁或者排它锁。例如，放置在表级上的意图锁表示一个事务可以在表中的页或者行上放置共享锁。在表级上设置共享锁防止以
后另外一个修改该表中页的事务在包含了该页的表上放置排它锁。意图锁可以提高性能，这是因为系统只需要在表级上检查意图锁，确定一个事务能否在哪个表上安
全地获取一个锁，而不需要检查表上的每一个行锁或者页锁，确定一个事务是否可以锁定整个表。意图锁有三种类型，即意图共享锁、意图排它锁和使用意图排它的
共享锁。意图共享锁表示读低层次资源的事务的意图，把共享锁放在这些单个的资源上。意图排它锁表示修改低层次的事务的意图，把排它锁放在这些单个资源上。
意图排它锁包括意图共享锁，它是意图共享锁的超集。使用意图排它的共享锁表示允许并行读取顶层资源的事务的意图，并且修改一些低层次的资源，把意图排它锁
放在这些单个资源上。例如，表上的一个使用意图排它的共享锁把共享锁放在表上，允许并行读取，并且把意图排它锁放在将要修改的页上，把排它锁放在修改的行
上。每一个表一次只能有一个使用意图排它的共享锁因为表级共享锁阻止对表的任何修改。使用意图排它的共享锁是共享锁和意图排它锁的组合。</p>
<p>当系统将要修改一个页时，使用修改锁。在系统修改该页之前，系统自动地把这个修改页锁上升到排它页锁，防止锁之间发生冲突。当第一次读取页时，在修改操作的开始阶段，获得修改锁。修改锁与共享锁是兼容的。如果该页被修改了，那么修改锁上升到排它锁。</p>
<p>模式锁保证当表或者索引被另外一个会话参考时，不能被删除或者修改其结构模式。SQL Server系统提供了两种类型的模式锁：模式稳定锁和模式修改锁。模式稳定锁确保锁定的资源不能被删除，模式修改锁确保其他会话不能参考正在修改的资源。</p>
<p>有些锁之间是兼容的，例如共享锁和修改锁之间。有些锁之间是不兼容的，例如排它锁和共享锁之间。下面的表1列出了SQL Server系统提供的各种锁之间的兼容性。</p>
<p>表1&nbsp;&nbsp; SQL Server系统提供的各种锁之间的兼容性</p>
<table class="90v" cellspacing="0" border="1" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="180">
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 锁名称</p>
</td>
<td valign="top" width="60">
<p>IS</p>
</td>
<td valign="top" width="60">
<p>S</p>
</td>
<td valign="top" width="60">
<p>U</p>
</td>
<td valign="top" width="60">
<p>IX</p>
</td>
<td valign="top" width="60">
<p>SIX</p>
</td>
<td valign="top" width="60">
<p>X</p>
</td>
</tr>
<tr>
<td valign="top" width="180">
<p>意图共享锁（IS）</p>
</td>
<td valign="top" width="60">
<p>兼容</p>
</td>
<td valign="top" width="60">
<p>兼容</p>
</td>
<td valign="top" width="60">
<p>兼容</p>
</td>
<td valign="top" width="60">
<p>兼容</p>
</td>
<td valign="top" width="60">
<p>兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
</tr>
<tr>
<td valign="top" width="180">
<p>共享锁（S）</p>
</td>
<td valign="top" width="60">
<p>兼容</p>
</td>
<td valign="top" width="60">
<p>兼容</p>
</td>
<td valign="top" width="60">
<p>兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
</tr>
<tr>
<td valign="top" width="180">
<p>修改锁（U）</p>
</td>
<td valign="top" width="60">
<p>兼容</p>
</td>
<td valign="top" width="60">
<p>兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
</tr>
<tr>
<td valign="top" width="180">
<p>意图排它锁（IX）</p>
</td>
<td valign="top" width="60">
<p>兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
</tr>
<tr>
<td valign="top" width="180">
<p>意图排它的共享锁（SIX）</p>
</td>
<td valign="top" width="60">
<p>兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
</tr>
<tr>
<td valign="top" width="180">
<p>排它锁（X）</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
<td valign="top" width="60">
<p>不兼容</p>
</td>
</tr>
</tbody>
</table>
<p>另外，除了表1中列出的锁之间的兼容性之外，对于模式锁来说，模式修改锁对于全部锁都是不兼容的，而模式稳定锁对于除了模式修改锁之外的全部锁都是兼容的。</p>
<p><a name="10"></a>
<strong>死锁问题</strong>
</p>
<p>死锁是一个很重要的话题。在事务和锁的使用过程中，死锁是一个不可避免的现象。在两种情况下，可以发生死锁。第一种情况是，当两个事务分别锁定了两
个单独的对象，这时每一个事务都要求在另外一个事务锁定的对象上获得一个锁，因此每一个事务都必须等待另外一个事务释放占有的锁，这时，就发生了死锁。这
种死锁是最典型的死锁形式。在同一时间内有两个事务A和B，事务A有两个操作：锁定表part和请求访问表supplier；事务B也有两个操作：锁定表
supplier和请求访问表part。结果，事务A和事务B之间发生了死锁，其示意进程如图10所示。</p>
<p>&nbsp;</p>
<p><img src="http://www.microsoft.com/china/msdn/archives/technic/develop/database/images/0522c-10.gif" height="180" alt="" width="400" />
</p>
<p>图10&nbsp;&nbsp;&nbsp; 死锁示意图</p>
<p>死锁的第二种情况是，当在一个数据库中时，有若干个长时间运行的事务执行并行的操作，当查询分析器处理一种非常复杂的查询例如连接查询时，那么由于不能控制处理的顺序，有可能发生死锁现象。</p>
<p>当发生死锁现象时，系统可以自动检测到，然后通过自动取消其中一个事务来结束死锁。在发生死锁的两个事务中，根据事务处理时间的长短作为规则来确定
他们的优先级。处理时间长的事务具有较高的优先级，处理时间较短的事务具有较低的优先级。在发生冲突时，保留优先级高的事务，取消优先级低的事务。</p>
<p><a name="11"></a>
<strong>会话级锁和表级锁</strong>
</p>
<p>一般地，锁是由系统自动提供的。但是，在有些情况下，用户也可以定制锁。也就是说，用户可以对会话级锁和表级锁进行定制。</p>
<p>会话级锁的定制包括两个方面，事务孤立等级和锁超时限制。事务孤立等级保护指定的事务，该事务孤立等级允许对一个会话中的全部事务设置孤立等级。当
设置孤立等级时，就为会话中的全部语句指定了默认的锁定行为。在指定事务孤立等级时，使用到下面一些选项。READ
COMMITTED选项指导系统在读取数据时，使用共享锁。在这种选项下，不能体会到脏读，即不能看到正在修改的数据。但是，在事务结束之前，可以改变数
据，所以可以产生不可重复读数据或者幻觉数据。READ
UNCOMMITTED选项指导系统既不使用共享锁，也不使用排它锁。在这种选项下，可以看到正在修改的数据，体会到脏读。这个选项是限制程度最低的设
置。REPEATABLE
READ选项指导系统在查询使用的全部数据上放置锁，防止其他用户修改数据，但是幻觉读可以发生。SERIALIZABLE选项指导系统在数据上放置锁，
直到事务完成以后，用户才可以修改或者插入数据。这个选项是限制程度最高的设置。另外，事务等待访问的时间也可以定制，这需要设置锁超时限制。当设置了锁
超时时间以后，如果事务等待的时间超过了锁超时时间，那么该事务被自动取消。</p>
<p>定制表级锁就是指通过为表指定一个或者多个选项，设置表级锁的行为。实际上，定制表级锁，就是使用一种优化隐藏的方式。优化隐藏就是指在FROM子
句后面，附加上有关的内容选项，提高系统识辨操作的能力。定制表级锁有许多选项。ROWLOCK选项指导系统使用行级锁而不是页级锁或者表级锁，这是系统
的默认选项。PAGLOCK选项指导系统使用页级锁。TABLOCK选项指导系统使用表级锁而不是使用锁定对象更细的行级锁或者页级锁，并且使用共享锁，
因此允许其他事务读取表中的数据，但是不能修改表中的数据。TABLOCKX选项指导系统使用排它锁，防止其他事务读取或者修改表中的任何数据。
NOLOCK选项指导系统不使用锁，既不使用共享锁，也不使用排它锁。在这种情况下，可以体会到脏读。HOLDLOCK选项指导系统占有共享锁直到该事务
的结束，而不是当有其他锁请求时立即释放。UPDLOCK选项指导事务在读取表中的数据时，使用修改的页级锁代替共享锁。这个锁一直占用到该语句或者事务
的结束为止。</p>
<p><a name="12"></a>
<strong>结论</strong>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
网络技术是信息技术发展的趋势。多用户、多事务、可伸缩、复制、数据仓库等等都是为了适应网络技术的数据库发展方向。事务作为一个重要的数据库技术的基本
概念，在保护数据库的可恢复性和多用户、多事务方面具有基础性的作用。一个事务就是一个单元的工作，该事务可能包括一条语句，也可能包括一百条语句，而这
些语句的所有操作，要么都完成，要么都取消。在数据库备份和恢复过程中，事务也具有重要作用，可以利用日志进行事务日志备份、增量备份，而不必每一次都执
行耗费时间、精力和备份介质的完全备份。锁是实现多用户、多事务等并发处理方式的手段。锁的类型和资源有多种。锁是由系统自动提供的，用户也可以进行一些
定制。在SQL Server 7.0中，一个明显的特征是使用了行级锁。使用行级锁引起了数据存储引擎、事务管理方式等方面的变化</p>
          <br/>
          <span style="color:red;">
            <a href="http://snailness.javaeye.com/blog/210604#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>Wed, 02 Jul 2008 14:31:28 +0800</pubDate>
        <link>http://snailness.javaeye.com/blog/210604</link>
        <guid>http://snailness.javaeye.com/blog/210604</guid>
      </item>
      <item>
        <title>转：ThreadLocal</title>
        <author>snailness</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://snailness.javaeye.com">snailness</a>&nbsp;
          链接：<a href="http://snailness.javaeye.com/blog/184232" style="color:red;">http://snailness.javaeye.com/blog/184232</a>&nbsp;
          发表时间: 2008年04月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          早在Java 1.2推出之时，Java平台中就引入了一个新的支持：java.lang.ThreadLocal，给我们在编写多线程程序时提供了一种新的选择。使用这个工具类可以很简洁地编写出优美的多线程程序，虽然ThreadLocal非常有用，但是似乎现在了解它、使用它的朋友还不多。<br /><br />　　ThreadLocal是什么<br /><br />　　ThreadLocal是什么呢？其实ThreadLocal并非是一个线程的本地实现版本，它并不是一个Thread，而是thread local variable（线程局部变量）。也许把它命名为ThreadLocalVar更加合适。线程局部变量（ThreadLocal）其实的功用非常简单，就是为每一个使用该变量的线程都提供一个变量值的副本，是每一个线程都可以独立地改变自己的副本，而不会和其它线程的副本冲突。从线程的角度看，就好像每一个线程都完全拥有该变量。线程局部变量并不是Java的新发明，在其它的一些语言编译器实现（如IBM XL FORTRAN）中，它在语言的层次提供了直接的支持。因为Java中没有提供在语言层次的直接支持，而是提供了一个ThreadLocal的类来提供支持，所以，在Java中编写线程局部变量的代码相对比较笨拙，这也许是线程局部变量没有在Java中得到很好的普及的一个原因吧。<br /><br />　　ThreadLocal的设计<br /><br />　　首先看看ThreadLocal的接口：<br /><br />　　Object get() ; // 返回当前线程的线程局部变量副本 protected Object initialValue(); // 返回该线程局部变量的当前线程的初始值void set(Object value); // 设置当前线程的线程局部变量副本的值<br /><br />　　 ThreadLocal有3个方法，其中值得注意的是initialValue()，该方法是一个protected的方法，显然是为了子类重写而特意实现的。该方法返回当前线程在该线程局部变量的初始值，这个方法是一个延迟调用方法，在一个线程第1次调用get()或者set(Object)时才执行，并且仅执行1次。ThreadLocal中的确实实现直接返回一个null：<br /><br /><br /><br /><br /><br />protected Object initialValue() { return null; }<br /><br />　　ThreadLocal是如何做到为每一个线程维护变量的副本的呢？其实实现的思路很简单，在ThreadLocal类中有一个Map，用于存储每一个线程的变量的副本。比如下面的示例实现：<br /><br /><br /><br /><br /><br />public class ThreadLocal<br />{<br />　private Map values = Collections.synchronizedMap(new HashMap());<br />　public Object get()<br />　{<br />　　Thread curThread = Thread.currentThread();<br />　　Object o = values.get(curThread);<br />　　if (o == null && !values.containsKey(curThread))<br />　　{<br />　　　o = initialValue();<br />　　　values.put(curThread, o);<br />　　}<br />　　return o;<br />　}<br /><br />　public void set(Object newValue)<br />　{<br />　　values.put(Thread.currentThread(), newValue);<br />　}<br /><br />　public Object initialValue()<br />　{<br />　　return null;<br />　}<br />}<br /><br />　　当然，这并不是一个工业强度的实现，但JDK中的ThreadLocal的实现总体思路也类似于此。<br /><br />　　ThreadLocal的使用<br /><br />　　如果希望线程局部变量初始化其它值，那么需要自己实现ThreadLocal的子类并重写该方法，通常使用一个内部匿名类对ThreadLocal进行子类化，比如下面的例子，SerialNum类为每一个类分配一个序号：<br /><br /><br /><br /><br /><br />public class SerialNum<br />{<br />　// The next serial number to be assigned<br /><br />　private static int nextSerialNum = 0;<br />　private static ThreadLocal serialNum = new ThreadLocal()<br />　{<br />　　protected synchronized Object initialValue()<br />　　{<br />　　　return new Integer(nextSerialNum++);<br />　　}<br />　};<br /><br />　public static int get()<br />　{<br />　　return ((Integer) (serialNum.get())).intValue();<br />　}<br />}<br /><br />　　SerialNum类的使用将非常地简单，因为get()方法是static的，所以在需要获取当前线程的序号时，简单地调用：<br /><br /><br /><br />int serial = SerialNum.get();<br /><br />　　即可。<br /><br />　　在线程是活动的并且ThreadLocal对象是可访问的时，该线程就持有一个到该线程局部变量副本的隐含引用，当该线程运行结束后，该线程拥有的所以线程局部变量的副本都将失效，并等待垃圾收集器收集。<br /><br />　　ThreadLocal与其它同步机制的比较<br /><br />　　ThreadLocal和其它同步机制相比有什么优势呢？ThreadLocal和其它所有的同步机制都是为了解决多线程中的对同一变量的访问冲突，在普通的同步机制中，是通过对象加锁来实现多个线程对同一变量的安全访问的。这时该变量是多个线程共享的，使用这种同步机制需要很细致地分析在什么时候对变量进行读写，什么时候需要锁定某个对象，什么时候释放该对象的锁等等很多。所有这些都是因为多个线程共享了资源造成的。ThreadLocal就从另一个角度来解决多线程的并发访问，ThreadLocal会为每一个线程维护一个和该线程绑定的变量的副本，从而隔离了多个线程的数据，每一个线程都拥有自己的变量副本，从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象，在编写多线程代码时，可以把不安全的整个变量封装进 ThreadLocal，或者把该对象的特定于线程的状态封装进ThreadLocal。<br /><br />　　由于ThreadLocal中可以持有任何类型的对象，所以使用ThreadLocal get当前线程的值是需要进行强制类型转换。但随着新的Java版本（1.5）将模版的引入，新的支持模版参数的ThreadLocal&lt; T>类将从中受益。也可以减少强制类型转换，并将一些错误检查提前到了编译期，将一定程度地简化ThreadLocal的使用。<br /><br />　　总结<br /><br />　　当然ThreadLocal并不能替代同步机制，两者面向的问题领域不同。同步机制是为了同步多个线程对相同资源的并发访问，是为了多个线程之间进行通信的有效方式；而ThreadLocal是隔离多个线程的数据共享，从根本上就不在多个线程之间共享资源（变量），这样当然不需要对多个线程进行同步了。所以，如果你需要进行多个线程之间进行通信，则使用同步机制；如果需要隔离多个线程之间的共享冲突，可以使用ThreadLocal，这将极大地简化你的程序，使程序更加易读、简洁。
          <br/>
          <span style="color:red;">
            <a href="http://snailness.javaeye.com/blog/184232#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>Fri, 18 Apr 2008 22:58:59 +0800</pubDate>
        <link>http://snailness.javaeye.com/blog/184232</link>
        <guid>http://snailness.javaeye.com/blog/184232</guid>
      </item>
      <item>
        <title>windows2003 server安装sybase11.92</title>
        <author>snailness</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://snailness.javaeye.com">snailness</a>&nbsp;
          链接：<a href="http://snailness.javaeye.com/blog/180714" style="color:red;">http://snailness.javaeye.com/blog/180714</a>&nbsp;
          发表时间: 2008年04月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          windows2003 server安装sybase11.92<br />   安装完成后，启动服务，是无法从windows下的服务启动，需要从命令行下启动.比如安装目录的％sybase％\install里的 RUN_XXX.bat.直接启动RUN_xxx.bat就可以了.<br />   sybase  11.92从快捷方式启动 serverconfig建服务会有问题，类似的好像还有sybase12.5.0,需从bin目录下面直接启动syconfig.exe建服务，要不会报错，建不了服务.<br />   安装sybase11.92的过程中需选择安装的组件，选择安装全部的组件的情况下其中Sybase Central无法使用，要报错.
          <br/>
          <span style="color:red;">
            <a href="http://snailness.javaeye.com/blog/180714#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>Wed, 09 Apr 2008 10:19:40 +0800</pubDate>
        <link>http://snailness.javaeye.com/blog/180714</link>
        <guid>http://snailness.javaeye.com/blog/180714</guid>
      </item>
      <item>
        <title>Sybase 11.9.2 的jdbc 连接问题</title>
        <author>snailness</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://snailness.javaeye.com">snailness</a>&nbsp;
          链接：<a href="http://snailness.javaeye.com/blog/180712" style="color:red;">http://snailness.javaeye.com/blog/180712</a>&nbsp;
          发表时间: 2008年04月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Sybase 11.9.2 的jdbc 连接问题 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 今天搭测试环境, Sybase 11.9.2的数据库. <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 程序用的是Jdbc连接数数库,建好库后一连就出现这个问题: <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;java.sql.SQLException:JZOSJA:没有发现元数据存取器信息。请按jConnect文档中所述安装所需的表.&quot; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 原来是因为Sybase 11.9.2太老了,默认是不支持JDBC的. <br /><br />解决办法: <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 找一个高版本的sybase 的jConnect-5_5\sp 目录下有个sql_server.sql文件, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 把它放在Sybase 11.9.2端ispl下执行一次就可以了. <p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://snailness.javaeye.com/blog/180712#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>Wed, 09 Apr 2008 10:14:14 +0800</pubDate>
        <link>http://snailness.javaeye.com/blog/180712</link>
        <guid>http://snailness.javaeye.com/blog/180712</guid>
      </item>
      <item>
        <title>扩展JAAS </title>
        <author>snailness</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://snailness.javaeye.com">snailness</a>&nbsp;
          链接：<a href="http://snailness.javaeye.com/blog/178941" style="color:red;">http://snailness.javaeye.com/blog/178941</a>&nbsp;
          发表时间: 2008年04月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;用户认证和访问控制是大多数java应用的重要安全尺度，特别是J2EE应用。Java认证和权限服务(即JAAS)，J2SE1.4和1.5的核心API，描绘表达了新的安全标准。其提供了一个可插拔的(pluggable)和富有弹性的(flexible)框架(framework)允许开发者混合不同的安全机制和丰富的已经存在各种安全方面的资源。 <br />　　伴随着即将来临的J2SE1.5版本的发布，它包含了许多诸如加密技术、XML安全性、公钥机制（PKI）、Kerberos （是一个网络附加系统/协议，可以允许用户通过一个安全伺服器的服务来验证 自己。象远端登陆，远端拷贝，系统间的相互档拷贝和另外高风险任务的服务将被变 得相当安全和可控制。）和结盟认证（the federating identity）的增强！，JAAS将会在J2EE实现中扮演一个更加重要的角色。 <br />　　<strong>认证</strong> <br />　　认证就是校验一个用户拥有使用已经被企业用户注册机构证明了的身份鉴定的权限的处理过程。JAAS的认证机制建立于一整套可插拔的模块（参看图1）基础上。JAAS允许不同的验证模型在运行时可被插拔。客户应用总是通过登陆上下文对象和JAAS交互。 <br />　　认证处理过程典型的要经过下面的步骤： <br />　　1、 生成一个LoginContext对象。这个LoginContext寻找配置文件以决定使用那个LoginModule。同样，可选择的，有可能传递一个CallbackHandler给LoginContext. <br />　　2、 通过调用LoginContext的login方法执行认证，它会加载预定义的LoginModule去检验是否用户可以被认证。 <br />　　3、 如果用户被认证，那么用规则和标识和其所属项进行关联。 <br />　　4、 或者在登陆失败的情况下跑出一个LoginException <br />　　5、 使用LoginContext的logout方法进行注销登陆 <br />在JAAS中，登陆是一个两阶段(two-phase)的处理过程。第一阶段是&ldquo;登陆（login）&rdquo;阶段（就像上面2所描述的）。这个阶段唯一的任务是认证。只要处理过程成功通过这个阶段，认证处理过程就进入了&ldquo;提交(commit)&rdquo;阶段（如上步骤3），这一阶段LoginModule的commit方法被调用去关联所属子项相关的规则和标识。 <br />　　在JAAS中一个所属子项表示一个认证实体，比如一个人或者一台设备。它包含了一整套法则和安全相关的属性诸如密码和加密密钥。在JAAS体系结构中，所属子项和其所附属的相关权限，扮演了重要的角色在认证过程当中。所有的认证模块当中，LoginModule是事实上的认证机制的借口。虽然LoginModule决没有得到直接调用客户应用的机会，但是他经由一个可插拔的模块提供了一个认证的具体类型，其实现了认证的算法并且决定实际的认证过程是怎样被执行的。 <br />　　SUN提供了几个默认的LoginModule 实现，在sun.com.security.auth.module包里有诸如JndiLoginModule,Krb2LoginModule,UnixLoginModule和NTLoginModule等几个LoginModule实现。因为JAAS登录结构体系是可扩展的，所以你只要在配置文件中指定使用哪个LoginModule模块就可以几乎全部插入任何LoginModule模块。 <br />　　如下即为一个配置文件的例子： <br />　　MySample { <br />　　com.sample.module.MyLoginModule required debug=true; <br />　　}; <br />　　 <br />　　这里MySample是登录上下文环境(login context)的名字，当你生成一个新的LoginContext开始认证过程时它会被传入LoginContex的构造函数中。依据配置块提示，那个文本块提醒JAAS有关LoginModule在登录过程中应该被用来执行认证。另外，对于LoginModule，任何关于他的选项也可以在这里被指定。在执行登录这一步骤的过程中，CallbackHandler类被LoginModule类用来跟用户通信已便于取得认证信息。CallbackHandler类处理三种类型的回调（Callback）：NameCallback,提示用户输入一个用户名；PasswordCallcack,提示输入密码；TextOutputCallback,报告错误、警告或则发送给用户一些其他信息。 <br />授权是决定是否认证的用户可以执行一些动作的工作，例如访问一处资源。因为JAAS建立于已经存在的Java安全模型的基础上，故这个过程时基于策略的。策略配置文件实质上包含了一系列的入口，诸如&ldquo;Keystore&rdquo;和/或&ldquo;grant&rdquo;. <br />　　grant入口包含了所有的权限，他是通过认证的代码或则法则被授予可以进行安全敏感的操作，例如，访问一个具体的Web页面或则本地的文件。JAAS支持基于法则的策略入口，赋权入口基本格式如下： <br />　　grant Codebase &ldquo;codebase_URL&rdquo; Signedby &ldquo;signer_name,&rdquo; <br />　　Principal principal_class_name &ldquo;principal_name&rdquo;, <br />　　Principal principal_class_name &ldquo;principal_name&rdquo;, <br />　　&hellip; { <br />　　permission permission_class_name &ldquo;target_name&rdquo;, &ldquo;action&rdquo;, <br />　　permission permission_class_name &ldquo;target_name&rdquo;, &ldquo;action&rdquo;, <br />　　&hellip; <br />　　} <br />　　 <br />　　上面格式中&ldquo;动作（action）&rdquo;可能是必需的或则可能被忽略依赖于权限类型。在JAAS体系结构中，策略对象表达了一个Java应用环境的系统安全策略和在任何时间事实上只有一个策略对象。依据Java2 SDK文档，默认的策略实现是sun.security.provider.PolicyFile,其中策略被指定在一个或多个策略配置文件里。 <br />　　只要用户被认证，授权经由Subject.doAs方法发生，或者从Subject类的静态方法doAsPrivileged，doAS方法用当前的AccessControlContext动态和子项并且同时调用run方法去执行动作，他导致安全验证。权限验证过程通过下面的步骤在图2: <br />　　就像LoginModule,策略也是可插拔的模型。你可以挂上其它的策略实现通过在java.security的属性文件中改变&ldquo;policy.provider=sun.security.provider.PolicyFile&rdquo; <br />　　到一个你项使用的策略类。 <br />　　<strong>Extend JAAS</strong> <br />　　JAAS建立于已经存在的Java安全模型的顶端，其基于&ldquo;CodeSource&rdquo;和平面文本格式策略文件实现。这可能对企业应用是不够用的，你可能想使用可定制的安全仓库。对于JAAS的其它实现,诸如LDAP(轻型目录访问协议)，数据库或者其他文件系统，它可以通过编写你自己的可定制模块被完成，感谢JAAS的可插拔的特性。然而，这需要对模块和JAAS中的处理过程有完善的理解，同时你必须做许多编码去覆写相关的类，并且处理好配置和策略两种文件。 <br />　　理想情况下，我们愿意能够扩展JAAS以一个更加容易的方式以便于无论何时一个可定制的安全知识库或者不同的访问控制机制改变或者必须去增加时，你能够只开发和插入这些不同的小模块（即，适配器）去适应这些新的变化和需求，并且在最好的情况下，不必去理解和熟悉JAAS处理过程的细节，同样，我们也愿意能够去做这些变化仅仅通过改变一个配置文件。另一个目标是我们的JAAS扩展组件能够被使用在不同的J2EE应用中&mdash;独立的或者Web上的。图3描述了JAAS扩展组件的设计意图。我们的JAAS扩展组在实现可定制的LoginModule和策略模块时充分件利用了JAAS插拔式的体系结构。这些模块中，我们委派数据请求到适配器。这些适配器的每个对于诸如数据取回的简单任务是隔离的，所以你可以快速地使用不同的安全知识或者算法开发不同的适配器而不是尝试去实现不同的LoginModule或者策略模块，它们更加复杂并且需要更多的努力。 <br />　　你可以从www.sys-con.com/java/sourcec.cfm.下在完整的源玛。 <br />　　<strong>实现的AuthLoginModule类</strong> <br />　　AuthLoginModule类是我们定制的LoginModule实现，LoginModule类是在JAAS中是一个可插拔组件并且服务于两个目的： <br />　　1、鉴定认证用户 <br />　　2、如果认证成公，则用相关的负责人信息或者证书更新主题。 <br />　　 <br />　　LoginModule有5个方法去实现功能，让我们关注一下login()方法。这个方法被调用以认证主题并且主要作两件事情： <br />　　1、包含用户名和密码，典型地，LoginModule要调用CallbackHandler类的handle方法去得到用户名和密码 <br />　　2、通过和数据源中的比较校验密码。LoginModule从Callbacks取回用户名和密码。(其默认期望用户接口的某种排序)，这一点对于一个简单的演示程序或者就在命令行，可是他对于一个J2EE应用来说不太实用，例如，对于大多数的Web应用，用户名和密码将比较典型的从一个form中读出。在这种情况下，使用JAAS认证会比较困难。考虑我们不直接使用LoginModule,解决方案是实现一个可定制的CallbackHandler类，他会接收用户名和密码然后递交它们给LoginModule，所以他没有必要提示用户输入信息 <br />　　 <br />　　以下示例説明用户信息如何从JSP或者Servlet中传递： <br />　　String userName = request.getParameter (&ldquo;user&rdquo;); <br />　　String password = request.getParameter(&ldquo;password&rdquo;); <br />　　LoginContext context = new LoginContext (&ldquo;MySample&rdquo;, <br />　　new AuthCallbackHandler (userName, password)); <br />　　一旦拥有了用户名和密码在手，AuthLoginModule类，我们的LoginModule类的定制实现，会经由LoginSourceAdapterFactory实例化LoginSourceAdapter并同时委派实际的认证过程到资源适配器。适配器只不过是一个简单的类，其从一个具体的数据适配器（比如数据库或者LDAP,或者一些别的系统）领取用户信息。在&ldquo;提交&rdquo;阶段，AuthLoginModule类从LoginSourceAdapter类取回相关的信息并且把他们和主题相关联。 <br />　　 <br />　　LoginSourceAdapter类 <br />　　LoginSourceAdapter类是一个认证目的的资源适配器的接口，它有4个需要实现的方法： <br />　　1、void initialize(Hashtable parameters):initialized方法被调用来以相关的参数初始化适配器。此方法在对象生成后立即被调用并且优先于任何对其他方法的调用。 <br />　　2、boolean authenticate(String username,char[] password):此认证方法被调用来认证用户。 <br />　　3. String[] getGroupNames (String userName):getGroupNames方法被调用来在认证成功后得到相关的主要信息。 <br />　　4. void terminate ():这个方法在LoginModule类的logout方法被执行后调用，它给适配器做一些清理工作的机会。 <br /><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://snailness.javaeye.com/blog/178941#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>Wed, 02 Apr 2008 18:07:37 +0800</pubDate>
        <link>http://snailness.javaeye.com/blog/178941</link>
        <guid>http://snailness.javaeye.com/blog/178941</guid>
      </item>
      <item>
        <title>sybase数据库无效问题</title>
        <author>snailness</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://snailness.javaeye.com">snailness</a>&nbsp;
          链接：<a href="http://snailness.javaeye.com/blog/177778" style="color:red;">http://snailness.javaeye.com/blog/177778</a>&nbsp;
          发表时间: 2008年03月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最近在公司做一个项目的时候因为设计到跟其他部门的产品结合,产品负责人要求对所有用到的表建立视图,操作统一对视图进行操作。 <br />&nbsp;&nbsp;&nbsp;&nbsp; 有一展现列表设计三表联查，三个表数据量分别为100w，10w，10w。按说数据量不是很大，数据库查询却需要1秒左右的时间，数据库该优化的也优化了，索引该建的也建了。 <br />&nbsp;&nbsp;&nbsp;&nbsp; 看了看执行计划既然是全表扫描，让人莫名其妙。最后同事跟踪了一下，原来是由于数据库的元数据统计信息是旧的或者说不正确。重新统计元数据统计信息： <br />&nbsp;&nbsp;&nbsp;&nbsp; update all statistics K_RW..B_FTRW <br />&nbsp;&nbsp;&nbsp;&nbsp; go <br />后正常。&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;什么原因引起的呢？还是不慎了解 <p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://snailness.javaeye.com/blog/177778#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>Sun, 30 Mar 2008 14:39:02 +0800</pubDate>
        <link>http://snailness.javaeye.com/blog/177778</link>
        <guid>http://snailness.javaeye.com/blog/177778</guid>
      </item>
  </channel>
</rss>