<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
    <channel>
        <title>To Trac Xinbin&apos;s Life</title>
        <link>http://www.trac.net.cn/</link>
        <description>Hello World!</description>
        <language>en</language>
        <copyright>Copyright 2008</copyright>
        <lastBuildDate>Tue, 25 Nov 2008 22:38:55 +0800</lastBuildDate>
        <generator>http://www.sixapart.com/movabletype/</generator>
        <docs>http://www.rssboard.org/rss-specification</docs>
        
        <item>
            <title>tags vs keywords?</title>
            <description><![CDATA[<p>Only Test, hhee</p>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></description>
            <link>http://www.trac.net.cn/2008/11/tags-vs-keywords.html</link>
            <guid>http://www.trac.net.cn/2008/11/tags-vs-keywords.html</guid>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">tag</category>
            
            <pubDate>Tue, 25 Nov 2008 22:38:55 +0800</pubDate>
        </item>
        
        <item>
            <title>今日怪事连连，啥兆头？</title>
            <description><![CDATA[<p>一大早起床玩电脑，突然发现右下角有了一个蓝色五星, 把鼠标放上去一看，原来是传说中的微软OFFICE正版验证。没法，谁让我计算机上软件安得这么全呢？删掉吧，反正不用，因为有OpenOffice。</p>
<p>office卸载后，蓝色五星仍在，不会吧？难道只能破解？看看他说什么，点击菜单上的"office正版验证细节"，转到了微软网站，提示以下信息：</p>
<p>未检测到 Office 产品<br />问题： 此计算机上未找到适合于验证的 Office 产品。 这可能是由于下列原因之一导致的：</p>
<p>解决方案： 从零售商或您附近的软件经销商处为您的新计算机购买正版 Microsoft Office。 了解有关如何购买 Microsoft Office 的更多信息。</p>
<p>有截图为证：</p>
<p>
<p>&nbsp;</p>
<p><img class="mt-image-none" height="768" alt="shot.JPG" src="http://www.trac.net.cn/2008/10/22/shot.JPG" width="1280" /></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 微软可真是搞笑，不用你的office，也是你正版验证失败的条件吗？</p>
<p>&nbsp;</p>
<p>怪事之二：</p>
<p>因为手误，打错了域名了，转到了网通伟大的纠错页面。页面似乎比之前更乱，一看logo，竟然是联通的。啥时候学校的出口变成联通的了？把页面拽到最后，署名是"中国网络通信集团公司"。</p>
<p>呵呵，原来如此。</p></p>]]></description>
            <link>http://www.trac.net.cn/2008/10/post.html</link>
            <guid>http://www.trac.net.cn/2008/10/post.html</guid>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">域名纠错</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">微软正版验证</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">网通</category>
            
            <pubDate>Wed, 22 Oct 2008 08:29:07 +0800</pubDate>
        </item>
        
        <item>
            <title>世上最便宜的饭店</title>
            <description><![CDATA[<p>物价疯长，饭店里的菜也疯长，但一个地方除外，这就是我将要告诉大家的，世上最便宜的饭店（注意了，不是史上最便宜的）。</p>
<p>下面是几张图：</p>
<p>最低价的菜单：</p>
<p>&nbsp;</p>
<p>
<p>&nbsp;</p>
<p></p>
<p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a href="http://www.trac.net.cn/2008/09/10/07092008034.jpg"><img class="mt-image-none" height="768" alt="07092008034.jpg" src="http://www.trac.net.cn/assets_c/2008/09/07092008034-thumb-1024x768.jpg" width="1024" /></a></span>令人惊讶的三菜，量足，而且只6元钱：</p>
<p>&nbsp;</p>
<p>
<p><a href="http://www.trac.net.cn/2008/09/10/07092008036.jpg"><img class="mt-image-none" height="450" alt="07092008036.jpg" src="http://www.trac.net.cn/2008/09/10/07092008036-thumb-600x450.jpg" width="600" /></a></p>
<p>高雅的环境，超大屏幕液晶电视，而且是有线，不是常规饭店配备的：</p>
<p></p>
<p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a href="http://www.trac.net.cn/2008/09/10/07092008035.jpg"><img class="mt-image-none" height="450" alt="07092008035.jpg" src="http://www.trac.net.cn/2008/09/10/07092008035-thumb-600x450.jpg" width="600" /></a></span>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></description>
            <link>http://www.trac.net.cn/2008/09/the-cheapest-restaurant.html</link>
            <guid>http://www.trac.net.cn/2008/09/the-cheapest-restaurant.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">生活琐事</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">最便宜的饭店</category>
            
            <pubDate>Wed, 10 Sep 2008 12:48:13 +0800</pubDate>
        </item>
        
        <item>
            <title>生活搜索的核心竞争力</title>
            <description><![CDATA[<p>"精准营销，生活搜索从某种程度上来说他的核心竞争力就在这里，生活搜索和通用搜索最大的不同就在于此。"7月26日，在聚城沙龙生活搜索主题研讨上，爱帮网市场总监李翔表示。 </p>
<p>"同一个商家在阿里巴巴和慧聪留下的手机号码是不一样的，为什么，因为这样他能很清楚的知道，从阿里巴巴和慧聪分别给他带来的用户是多少。现在商家对广告的诉求是精确话的，他会以量来评估这个广告给他带来的价值。"李翔举例道："而在城市消费领域，同样是餐馆，中关村的是一个小型的餐馆他需要覆盖的是中关村这个地方，他只需要中关村这些人知道了解。但是一家大型餐馆的话，他就需要整个北京的人都知道，都光顾，他们营销的成本、手段、受众都是有区别的。生活搜索在精确性方面，具有地域性的优势。" </p>
<p>与会的百度战略合作孙泽锋也表示："目前中小企业有将近3000多万家，购买百度的竞价排名是很少很少的一部分客户，现在还有一个2000万--3000万的长尾，他们买不起百度的竞价排名，他们需要生活搜索给他一个特定的区域进行投放，费用更低和地点更精准。" </p>
<p>"换一种思维来想，生活搜索类似于精准营销，潜力是非常大的。"孙泽锋补充到："还有很大一块，就是品牌厂家也希望能通过生活搜索和本地搜索来投放广告，花更少的钱，做更精准的。如果生活搜索能更精准的人群定位，地点还有信息化的东西，广告产品出来了，广告厂商也会很乐意接受。" </p>
<p>如何实现精准营销 </p>
<p>爱帮网目前开始了一个新的尝试，通过COOKIE的记录去定义用户的生活轨迹，预计10月份的时候爱帮会推出一个叫生活史的产品。这个产品就是通过这些生活数据分析来记录每个人的行为。 </p>
<p>"生活搜索接触到的是人很琐碎的事，比如一个用户今天中午想吃的菜和明天中午想吃的菜是不一样的。今天和明天想去的餐馆也是不一样的。目前我们想到的是生活搜索应该有一些个性化的东西，个性化的推送，针对用户会有一些个性化的处理方式。"李翔说。 </p>
<p>百度则在考虑和中国电信，中国网通在IP定位上精准化，比如一个小区的IP是否可以定位，那么网站提供给用户的信息可以完全是用户周边的生活信息的汇集，而不是一个大范围北京的，是基于它周围10公里，5公里之内的信息。 </p>
<p>"其实从２０００年开始，百度就已经很关注精准营销这个概念了！我们对用户行为会有一些分析，可以定位到用户吃喝玩乐，衣食住行的喜好，这样就能很容易的去推送一些内容，结合地域性的ＩＰ段推送他周边的和他息息相关的生活信息"孙泽锋说："百度在基于这个层面的产品和技术上都有考虑，但是以网页形式还是像GOOGLE和爱帮专门做一个频道出来，这个还没有考虑。" <br /></p>]]></description>
            <link>http://www.trac.net.cn/2008/08/post-5.html</link>
            <guid>http://www.trac.net.cn/2008/08/post-5.html</guid>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">垂直搜索</category>
            
            <pubDate>Wed, 20 Aug 2008 19:08:20 +0800</pubDate>
        </item>
        
        <item>
            <title>Disable Cache in Squid 2.5</title>
            <description><![CDATA[<p>&nbsp;Add/modify squid.conf :</p>
<p>#no local caching<br />maximum_object_size 0 KB<br />minimum_object_size 0 KB</p>
<p># specify uncachable requests<br />acl all src 0.0.0.0/0.0.0.0<br />no_cache deny all</p>
<p>or<br /># caches nothing based on time<br />acl Working time 08:00-16:00<br />no_cache deny Working</p>
<p><br /># avoid having a cache directory<br />cache_dir null /tmp <br />or<br />cache_dir null /null</p>
<p>&nbsp;</p>]]></description>
            <link>http://www.trac.net.cn/2008/08/disable-cache-in-squid-25.html</link>
            <guid>http://www.trac.net.cn/2008/08/disable-cache-in-squid-25.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Linux</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">服务器</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">squid</category>
            
            <pubDate>Fri, 01 Aug 2008 19:02:08 +0800</pubDate>
        </item>
        
        <item>
            <title>windows 上 openvpn 客户端的安装</title>
            <description><![CDATA[openvpn 是跨平台的，官方也提供 windows的版本。但是很遗憾，不是图形化界面，这让同学们交流很是不便，现在向大家推荐一个
<h1 align="left">OpenVPN GUI for Windows.</h1>
<p align="left">&nbsp;</p>
<p align="left">官方网站是 <a href="http://www.openvpn.se/">http://www.openvpn.se/</a>, 此软件包含openvpn的所有功能，而且额外增加了图形化界面。</p>
<p align="left">1. 下载与安装</p>
<p align="left">&nbsp;&nbsp;&nbsp; 点此下载：<a href="http://www.openvpn.se/files/install_packages/openvpn-2.0.9-gui-1.0.3-install.exe">http://www.openvpn.se/files/install_packages/openvpn-2.0.9-gui-1.0.3-install.exe</a></p>
<p align="left">&nbsp;&nbsp;&nbsp; 安装就不多说了</p>
<p align="left">2.&nbsp;配置客户端</p>
<p align="left">&nbsp;&nbsp;&nbsp; openvpn支持静态密码连接，我就不介绍了。这里说的是实用SSL证书连接。</p>
<p align="left">&nbsp;&nbsp; 安装目录 C:\Program Files\OpenVPN\下有一个配置文件模板的文件夹：sample-config ，里面有openv server/client的配置文件实例。因为本文主要讲解如何安装客户端，所以直接把 client.ovpn 复制到 config 目录下作为客户端的配置文件。</p>
<p align="left">&nbsp;&nbsp;&nbsp; 然后把管理员提供的证书（ca.crt, client.crt, client.key）复制到config 目录下；</p>
<p align="left">&nbsp;&nbsp; 修改 client.opvn ，主要是 证书的路径和文件名，以及openvpn服务器的相关配置，根据经验，主要参数如下：</p>
<p align="left"><br />;dev tap<br />dev tun</p>
<p align="left">proto tcp<br />;proto udp</p>
<p align="left">;remote my-server-2 1194</p>
<p align="left">ca ca.crt<br />cert xxx.crt<br />key xxx.key<br /></p>
<p align="left">&nbsp;</p>]]></description>
            <link>http://www.trac.net.cn/2008/07/windows-openvpn.html</link>
            <guid>http://www.trac.net.cn/2008/07/windows-openvpn.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Linux</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">服务器</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">openvpn client</category>
            
            <pubDate>Wed, 30 Jul 2008 12:58:29 +0800</pubDate>
        </item>
        
        <item>
            <title>允许OPENVPN客户端之间互相访问</title>
            <description><![CDATA[<p>默认情况下，openvpn 出于安全考虑是禁止客户端之间互相访问的。其实修改这个配置很简单，只需要把配置文件（我的路径是 /etc/openvpn/server.conf）以下内容取消注释即可：</p>
<p>&nbsp; ;client-to-client</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></description>
            <link>http://www.trac.net.cn/2008/07/openvpn.html</link>
            <guid>http://www.trac.net.cn/2008/07/openvpn.html</guid>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">openvpn</category>
            
            <pubDate>Wed, 30 Jul 2008 05:46:21 +0800</pubDate>
        </item>
        
        <item>
            <title>SQLite的原子提交原理(转贴)</title>
            <description><![CDATA[<div class="Section1" style="LAYOUT-GRID:  15.6pt none">
<p class="MsoNormal" style="TEXT-ALIGN: center" align="center"><a name="_Toc189374154"><b><span lang="EN-US" style="FONT-SIZE: 24pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span></b></a><b><span style="FONT-SIZE: 24pt; FONT-FAMILY: 宋体">的原子提交原理</span></b></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">摘要：</span></p>
<p class="MsoNormal"><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399">&nbsp;</span></p>
<p class="MsoNormal"><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">本文源自：</span><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399"><a href="http://www.sqlite.org/atomiccommit.html"><span style="COLOR: #333399">http://www.sqlite.org/atomiccommit.html</span></a></span><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">，</span><i><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Verdana sans-serif'">2007/11/28</span></i><i><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">的版本</span></i></p>
<p class="MsoNormal"><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">本人正在做一个项目，在项目中定义了自己的文件格式，为了做到停电或程序崩溃不损坏这些文件原有的数据，故针对操作的原子性做一些思考，后来看到</span><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399">sqlite</span><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">的这篇文章，与自己的实现方式作了一些对比。故顺手在研究此文章的时候将大意译成了中文。毕竟只是一时顺手之作，应该存在不少的误读与错误，请多多包涵，此文章的原始地址在</span><span style="FONT-SIZE: 9pt; COLOR: #333399"> <span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html"><font color="#800080">http://chensheng.net/p/sqlite/auto_commit_zh_cn.html</font></a></span></span><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">，本文可以转载，但请保留出处，以便他人能够方便找到我在修改此文可能的错误之后重新发布的版本。如果发现错误请发</span><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399">mail</span><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">给我</span><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399">erehw#163.com</span><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">。</span></p>
<p class="MsoNormal"><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399">&nbsp;</span></p>
<p class="MsoNormal"><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">本文描述了</span><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399">sqlite</span><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">为保证数据库文件不被损坏而采取的种种手段，对于一些小型应用值得借鉴。其实在我看来，我自己实现这种方式似乎都有些不必要，也可以直接利用</span><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399">sqlite</span><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">或者</span><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399">berkeley db</span><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">即可。</span></p>
<p class="MsoNormal"><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399">&nbsp;</span></p>
<p class="MsoNormal"><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399">2008-1-29</span><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">于杭州，时日江南一片暴雪，众多机场车站都处于凝滞状态。感谢众多在此次雪灾之中作出贡献的人们。</span></p>
<p class="MsoNormal"><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: center" align="center"><span style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">目录</span></p>
<p class="MsoToc1"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374154"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">SQLite</span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">的原子提交原理</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">1</span></a></span></span></p>
<p class="MsoToc2"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374155"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">1.0 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">简介</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">2</span></a></span></span></p>
<p class="MsoToc2"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374156"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">2.0 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">硬件设定</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">2</span></a></span></span></p>
<p class="MsoToc2"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374157"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">3.0 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">单个文件提交</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">4</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374158"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">3.1 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">实始状态</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">4</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374159"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">3.2 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">申请一个共享锁</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">5</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374160"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">3.3 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">从数据库里面读取信息</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">5</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374161"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">3.4 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">申请一个</span></span></b><b><span style="FONT-FAMILY: 'Verdana sans-serif'">Reserved Lock</span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">. </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">6</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374162"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">3.5 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">生成一个回滚日志文件</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">6</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374163"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">3.6 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">修改用户进程中的数据页</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">7</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374164"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">3.7 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">刷新回滚日志文件到存储设备中</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">7</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374165"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">3.8 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">获得一个独享锁</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">7</span></a></span></span></p>
<p class="MsoToc2"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374166"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">3.9 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">将变更写入到数据库文件中</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">8</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374167"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">3.10 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">刷新变更到存储</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">8</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374168"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">3.11 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">删除回滚日志文件</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">9</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374169"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">3.12 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">释放锁</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">9</span></a></span></span></p>
<p class="MsoToc2"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374170"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">4.0 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">回滚</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">10</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374171"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">4.1</span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">出事了，出事了</span></span></b><b><span style="FONT-FAMILY: 'Verdana sans-serif'">!!!</span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none"> </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">10</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374172"><b><span style="FONT-FAMILY: 'Verdana sans-serif'"><font color="#45735f">4.2 Hot Rollback Journals</font></span></b><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none"> </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">11</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374173"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">4.3 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">取得数据库的一个独享锁</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">11</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374174"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">4.4 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">回滚没有完成的变更</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">12</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374175"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">4.5 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">删除</span></span></b><b><span style="FONT-FAMILY: 'Verdana sans-serif'">hot</span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">日志文件</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">13</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374176"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">4.6 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">如果一切正常，没有什么未完成的写操作</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">13</span></a></span></span></p>
<p class="MsoToc2"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374177"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">5.0 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">多文件提交</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">14</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374178"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">5.1 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">每个数据库文件单独拥有日志文件</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">14</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374179"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">5.2 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">主日志文件</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">15</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374180"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">5.3 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">更新回滚日志文件头</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">16</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374181"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">5.4 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">修改数据库文件</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">16</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374182"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">5.5 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">删除主日志文件</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">17</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374183"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">5.6 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">清除回滚日志</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">17</span></a></span></span></p>
<p class="MsoToc2"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374184"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">6.0</span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">原子操作的一些实现细节</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">18</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374185"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">6.1 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">总是记录整个扇区</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">18</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374186"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">6.2 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">写日志文件时垃圾的处理</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">19</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374187"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">6.3 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">提交前缓存溢出</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">19</span></a></span></span></p>
<p class="MsoToc2"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374188"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">7.0 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">优化</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">20</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374189"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">7.1 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">在事务间保存缓存</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">20</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374190"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">7.2 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">独享访问模式</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">21</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374191"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">7.3 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">不必将空闲页写进日志</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">21</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374192"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">7.4 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">单页更新及扇区原子写</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">22</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374193"><b><span style="FONT-FAMILY: 'Verdana sans-serif'"><font color="#45735f">7.5 Filesystems With Safe Append Semantics</font></span></b><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none"> </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">22</span></a></span></span></p>
<p class="MsoToc2"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374194"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">8.0 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">原子提交行为测试</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">23</span></a></span></span></p>
<p class="MsoToc2"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374195"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">9.0 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">会导致完蛋的事情</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">23</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374196"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">9.1 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">缺乏文件锁实现</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">23</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374197"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">9.2 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">不完整的磁盘刷新</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">24</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374198"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">9.3 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">文件部分地删除</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">24</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374199"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">9.4 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">写<span lang="EN-US">入到文件中的垃圾</span></span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">24</span></a></span></span></p>
<p class="MsoToc3"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374200"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">9.5 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">删除掉或更名了</span></span></b><b><span style="FONT-FAMILY: 'Verdana sans-serif'">"hot</span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">"日志文件</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">24</span></a></span></span></p>
<p class="MsoToc2"><span class="MsoHyperlink"><span lang="EN-US"><a href="http://chensheng.net/p/sqlite/auto_commit_zh_cn.html#_Toc189374201"><font color="#45735f"><b><span style="FONT-FAMILY: 'Verdana sans-serif'">10.0 </span></b><b><span lang="EN-US" style="FONT-FAMILY: 宋体"><span lang="EN-US">总结及未来的路</span></span></b></font><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">... </span><span style="DISPLAY: none; COLOR: windowtext; TEXT-DECORATION: none">25</span></a></span></span></p>
<p class="MsoNormal"><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399">&nbsp;</span></p>
<p class="MsoNormal"><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #333399">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374155"><b><span lang="EN-US" style="FONT-SIZE: 18pt; FONT-FAMILY: 'Verdana sans-serif'">1.0 </span></b></a><b><span style="FONT-SIZE: 18pt; FONT-FAMILY: 宋体">简介</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"原子提交"是</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">这种支持事务的数据库的一个重要特性。原子提交意味着某个事务中数据库的变化会完整完成或者根本不完成。原子提交意味着不同的写入分别写入到数据库的不同部分就似同时发生在同一个时间点一样。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">实际上硬件会连续的写到海量存储器中，只是写一个扇区所用的时间非常少。所以，同时或瞬间写入到数据文件的不同部分成为可能。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">的原子提交逻辑会使得一个事务中的变化就象同时发生的一样。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">事务的原子是</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">的重要特性，即使事务由于操作系统出错或掉电发生中断也能保持其原子性。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">本文描述了</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">实现原子操作的技术。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374156"><b><span lang="EN-US" style="FONT-SIZE: 18pt; FONT-FAMILY: 'Verdana sans-serif'">2.0 </span></b></a><b><span style="FONT-SIZE: 18pt; FONT-FAMILY: 宋体">硬件设定</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">在这</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体-方正超大字符集">往篇文章中，我们把海量存储特指定为"硬盘"，即使它可能是<span lang="EN-US">flash memory.</span></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">我们假定硬盘是以扇区为单位进行整块写入的。我们不能单独修改硬盘的小于扇区的部分。如果需要修改硬盘小于扇区的部分，你也必须整个读入此部分所在扇区，对此扇区进行修改，然后将整个扇区写回硬盘。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">在传统的</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">Spinning disk</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">中</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">,</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">扇区是最小的传输单元</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">---</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">无论是读还是写。然而，对于</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flash memory</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">，每次读的最小数目通常都远小于最小写操作数目。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite </span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">只关心写操作的最小数目，因此在本文中，当我们说"扇区"的时候，就是指单次写入的最少字节总数。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite 3.3.14</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">以前的版本，我们假定任何情况下，一个扇区是</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">512</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">字节。这是一个编译时设定的值，而且从没针对更大数进行测试过。当磁盘驱动器内部使用的是以</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">512</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">字节为单位的扇区时，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">512</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">字节的假定显得非常合理。然而，现在的磁盘都已经发展到</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">4k</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">每扇区了。同样，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'"> flash memory </span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">的扇区大小通常都大于</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">512</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">字节。因此，从</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.3.14</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">版本开始，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">有一个函数去获取文件系统的扇区真实大小。在当前的实现中</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">(3.5.0)</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">，这个函数仍然简单的返回</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">512--</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">因为在</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">win32</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">及</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">unix</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">环境下，没有标准方法去取得扇区的真实大小。但这个方法在人们需要针对他们应用进行调整的时候是非常有意义的。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">并<b><span style="COLOR: red">不</span></b>假定扇区写操作是原子的。然而，我们假定扇区写操作是线性的。所谓"线性"是指，当开始扇区写操作时，硬件从前一个扇区的结束点开始，然后一字节一字节的写入，直到此扇区的结束点。这个写操作可能是从尾向头写，也可能是从头向尾写。如果在一个扇区写入操作时发生掉电故障，这个扇区可能会一部分已经修改完成，还有一部分还没来得及进行修改。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">的关键设定是这样的：如果一个扇区的任何部分发生修改，那么不是它开始的部分发了变化，就是它结束部分发生了变化。所以硬件从来都不会从一个扇区的中间部分开始写入。我们不知道这个假定是否总是真实的，但无论如何，看起来还是蛮合理的。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">上段中，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">并没有假定扇区写操作是原子的。在</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite3.5.0</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">版本中，新增了一个</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">VFS</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">（虚拟文件系统）接口。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">通过</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">VFS</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">与实际的文件系统进行交互。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">已经为</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">windows</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">及</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">unix</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">编写了一个缺省的</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">VFS</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">实现。并且可以让用户在运行时实现一个自定义的</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">VFS</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">实现。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">VFS</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">接口有一个方法叫：</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'"> xDeviceCharacteristics.</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">此方法读取实际的文件系统各种特性。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">xDeviceCharacteristics</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">方法可以指明扇区写操作是原子的，如果确实指定扇区写是原子的，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">是不会放过这等好处的。但在</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">windows</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">及</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">unix</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">中，缺省</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'"> xDeviceCharacteristics</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">的实现并没有指明扇区写是原子的，所以这些优化通常会忽略掉了。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">假定操作系统会对写进行缓冲，因此写入请求返回时，有可能数据还没有真实的写入到存储中。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite </span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">同时还假定这种写操作会被操作系统记录。因此，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'"> SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">需要在关键点做</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">"flush" </span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">或</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'"> "fsync" </span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">函数调用。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">假定</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">或</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">fsync</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">在数据没有真实的写入到硬盘之前是不会返回的。不幸的是，我们知道在一些</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">windows</span><span style="FONT-FAMILY: 宋体">及</span><span lang="EN-US">unix</span><span style="FONT-FAMILY: 宋体">版本中，缺少</span><span lang="EN-US">flush</span><span style="FONT-FAMILY: 宋体">或</span><span lang="EN-US">fsync</span><span style="FONT-FAMILY: 宋体">的真正实现。这使得</span><span lang="EN-US">SQLite</span><span style="FONT-FAMILY: 宋体">在写入一个提交发生掉电故障后数据文件得到损坏。然而，这不要紧，</span><span lang="EN-US">SQLite</span><span style="FONT-FAMILY: 宋体">能够做一些测试或补救。</span><span lang="EN-US">SQLite</span><span style="FONT-FAMILY: 宋体">假定操作系统会是广告中那样漂亮运行。如果这些都不是问题，那么剩下的只期望你家的电源不要间歇性的休息。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">假定文件增长方式是指新分配的文件空间，刚分配的时候是随机内容，后来才被填入实际的数据。换而言之，文件先变大，然后再填充其内容。这是一悲观假定，因而</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">不得不做一些额外的操作来防止因断电发生的破坏数据文件</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">--</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">发生在文件大小已经增大，而文件内容还没完全填入之间的掉电。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">VFS</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">的</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">xDeviceCharacteristics </span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">可以指明文件系统是否总是先写入数据然后才更变文件大小的。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">(</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">这就是那个：</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLITE_IOCAP_SAFE_APPEND </span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">属性，如果你想查看代码的话</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">) </span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">当</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">xDeviceCharacteristics </span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">方法指示了文件内容先写入然后才改变文件大小的话，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">会减少一些相当的数据保护及错误处理过程，这将大大减少一个提交磁盘</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">IO</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">操作。然而在当前的版本，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">windows</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">及</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">unix</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">的</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">VFS</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">实现并没有这样假定。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">假定文件删除从用户进程角度来讲是原子的。也就说当</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">要求删除一个文件，也在这删除的过程中间，断电了，一旦电源恢复，只有下列二种情况之一分发生：文件仍然存在，所有内容都没有发生变化；或者文件已经被删除掉了。如果电源恢复之后，文件只发生了部分删除，或者部分内容发生了变化或清除，或者文件只是清空，那么数据库还有用才怪呢。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">假定发现或修改由于宇宙射线，热噪声，量子波动，设备驱动</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">bug</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">等等其他可能所引发的错误，都由操作系统或硬件来完成。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">并不为此类问题增加任何数据冗余处理。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">假定在写入之后去读取所获得的数据，是与写入的数据完全一致的！</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374157"></a><a name="section_3_0"></a><b><span lang="EN-US" style="FONT-SIZE: 18pt; FONT-FAMILY: 'Verdana sans-serif'">3.0 </span></b><b><span style="FONT-SIZE: 18pt; FONT-FAMILY: 宋体">单个文件提交</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">我们着手观察</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">在针对一个数据库文件时，为保证一个原子提交所采取的步骤。关于在多个数据库文件之间为防止电源故障损坏数据库及保证提交的原子性所采用的技术及具体的文件格式在下一节进行讨论。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374158"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">3.1 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">实始状态</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">当一个数据库第一次打开时计算机的状态示意图如右图所示。图中最右边（</span><span lang="EN-US">"Disk"</span><span style="FONT-FAMILY: 宋体">标注）表示保存在存储设备中的内容。</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">每个方框代表一个扇区。蓝色的块表示这个扇区保存了原始资料。图中中间区域是操作系统的磁盘缓冲区。在我们的案例开始的时候，这些缓存是还没有被使用</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">--</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">因此这些方框是空白的。图中左边区域显示</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">用户进程的内存。因为这个数据库联接刚刚打开，所以还没有任何数据记录被读入，所以这些内存也是空的。</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'"> </span><span lang="EN-US"><img height="270" src="http://chensheng.net/p/sqlite/sqlite_images/image001.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374159"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">3.2 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">申请一个共享锁</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">在可以写数据库之前，它必须先读这个数据库，看它是否已经存在了。即使只是只是增加添加新的数据，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLit</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">仍然必须从</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">sqlite_master</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">表中读取数据库格式，这样才知道如何分析</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">INSERT</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">语句，知道在哪儿保存新的信息。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-FAMILY: 宋体">为了从数据库文件读取，第一步是获得一个数据库文件的共享锁。一个"共享"锁允许多个数据库联接在同一时刻从这个数据库文件中读取信息。</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"共享"锁将不允许其他联接针对此数据库进行写操作。这是必然的，如果一个联接在向数据库写入数据的同时，我们去读到信息，也可能读到的一部分数据是修改之前的，而另一部分数据是修改之后的。这将使得另外联接的修改操作看起来是非原子的。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">请注意共享锁只是针对操作系统的磁盘缓存，并非磁盘本身。通常文件锁只是操作系统内核的一些标识（详情要根据具体的操作系统）。因此，锁会立即消失一旦操作系统崩溃或者停电。当然创建该锁的进程消失，该锁也会随之而去。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="section_3_3"></a><span lang="EN-US"><img height="270" src="http://chensheng.net/p/sqlite/sqlite_images/image002.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374160"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">3.3 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">从数据库里面读取信息</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">当共享锁取得之后，我们就可以开始从数据库文件中读取信息了。在当前环节，我们已经假定了系统缓存是空的，所以信息必须首先从读硬盘读取到系统缓存中去，然后从系统缓存中传递到用户空间。针对之后的读取，部分或者全部数据都可能可以从操作系统缓存中取得，所以只需要传递到用户空间即可。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">一般的，数据库文件只有部分被读取。这个例子中，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">8</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">页中只有</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">页被读取。一个典型应用中，一个数据库文件拥有成千上万页，一个查询通常读取到的页码数量只占总数一个很小的百分比。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="270" src="http://chensheng.net/p/sqlite/sqlite_images/image003.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374161"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">3.4 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">申请一个</span></b><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">Reserved Lock</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">在修改一个数据库之前，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">首先得拥有一个针对数据库文件的"</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">Reserved</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"</span> <span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">锁。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">Reserved</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">锁类似于共享锁，它们都允许其他数据库联接读取信息。单个</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">Reserved </span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">锁能够与其他进程的多个共享锁一起协作。然后一个数据库文件同时只能存在一个</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">Reserved </span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">。因此只能有一个进程在某一时刻尝试去写一个数据库文件。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">Reserved </span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">锁的存在是宣告一个进程将打算去更新数据库文件，但还没有开始。因为还没有开始修改，因此其他进程可以读取数据，其他进程不应该去尝试修改该数据库。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="section_3_5"></a><span lang="EN-US"><img height="270" src="http://chensheng.net/p/sqlite/sqlite_images/image004.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374162"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">3.5 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">生成一个回滚日志文件</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">在修改数据库文件之前，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">会生成一个单独的回滚日志文件，并在其中写进将会被修改的页的原始数据。回滚日志文件意味它将包含了所有可以将数据库文件恢复到原始状态的数据。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">回滚日志文件有一个小的头部（图中绿色标记部分）记录了数据库文件的原始大小。因此，如果一旦即使数据库文件变大，我们还是会知道它原始大小。数据库文件中被修改的页码及他们的内容都被写进了回滚日志文件中。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">当一个新文件刚被创建，大部分的桌面操作系统（</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">windows,linux,macOSX</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">）实际并不会马上写入数据到硬盘。此文件还只是存在于操作系统磁盘缓存中。这个文件还不会立即写到存储设备中，一般都会有一些延迟，或者到操作系统相当空闲的时候。用户的对于文件生成感觉是要远远快（先）于其真实的发生磁盘</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">I/O</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">操作。右图中我们用图例说明了这一点，当新的回滚日志文件创建之后，它还只是出现在操作系统磁盘缓存之中，还没真实在写入到硬盘之上。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="section_3_6"></a><span lang="EN-US"><img height="351" src="http://chensheng.net/p/sqlite/sqlite_images/image005.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374163"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">3.6 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">修改用户进程中的数据页</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">当原始的数据已经被保存到回滚日志文件中之后，用户内存的数据就可以被修改了。任何一个数据库联接都有其他私有用户内存空间，所以用户内存空间发生的变化只有当前数据库联接才可见。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">其他数据库联接仍然可以读取那些存在于操作系统磁盘缓存中还没有被修改的数据。所以即使一个联接忙于某些修改，其他进程还可以读取原始数据到它们各自的空间中去</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="section_3_7"></a><span lang="EN-US"><img height="351" src="http://chensheng.net/p/sqlite/sqlite_images/image006.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374164"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">3.7 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">刷新回滚日志文件到存储设备中</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">接下来的步骤是将回滚日志文件刷新到硬盘中去。接下来我们会看到，这是一个紧要步骤用来保证我们可以从突然掉电中救回数据。这个步骤将要花费大量的时间</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">--</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">因为通常写入到硬盘是一个耗时操作。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">.</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">这个步骤通常要比简单的直接刷新这个回滚文件到硬盘要复杂一些。在大部分的操作系统中，二个单独的</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">是必须的。第一个</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">处理日志文件的内容部分。接下来，将日志文件的页码总数写入到日志文件头部，然后将日志头部</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flsuh</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">到硬盘中。至少为什么我们要做一个头部修改及做一个额外的</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">操作的原因我们会在后面的章节解释。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="section_3_8"></a><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="351" src="http://chensheng.net/p/sqlite/sqlite_images/image007.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374165"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">3.8 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">获得一个独享锁</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">在修改数据库文件本身之前，我们必须取得一个针对此数据库文件的独享锁。取得此锁的过程是分二步走的。首先</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">取得一个"临界"锁，然后将此锁提升成一个独享锁。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">一个临界锁允许其他所有已经取得一个共享锁的进程从数据库文件中继续读取数据。但是它会阻止新的共享锁的生成。也就说，临界锁将会防止因大量连续的读操作而无法获得写入的机会。这些读取者可能有一打，也可能上百，甚至于上千。任何一个读取者在开始读取之前都要申请一个共享锁，然后开始读取它需要的数据，然后释放共享锁。然而存在这样一种可能：如果有太多的进程来读取同一个数据文件，在老的进程释放它的共享锁之前总是会有新的进程申请共享锁，因此不会存在某一时刻这个数据库文件上没有共享锁的存在，也因此写入者不会拥有取得一个独享锁的机会。临界锁的概念可以使现有的读取者完成他们的读取，同时阻止新的读取者读取，最后所有的读取者都读完之后，这个临界锁就可以被提升为独享锁了。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">.</span><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="section_3_9"></a><span lang="EN-US"><img height="351" src="http://chensheng.net/p/sqlite/sqlite_images/image008.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374166"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">3.9 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">将变更写入到数据库文件中</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">一旦独享锁在手，我们知道再也没有其他进程在读取此数据库文件了，此时修改此文件是安全的了。通常，这些变更只会发生在操作系统磁盘缓存中，并不会全部写入到磁盘中去。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="section_3_10"></a><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="351" src="http://chensheng.net/p/sqlite/sqlite_images/image009.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374167"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">3.10 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">刷新变更到存储</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">一个附加的</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">操作是必要的，这样才可以保证针对此文件的变化真正的写入到永久存储器中。这也是一个重要的步骤，将可以保证数据在掉电之后也将是完整无损的。然而，因为写入到磁盘所固有的慢，这个步骤同上面</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.7</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">节将日志文件</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">到磁盘中一样，占据了</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLIite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">事务提交操作的绝大部分时间。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="section_3_11"></a><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="351" src="http://chensheng.net/p/sqlite/sqlite_images/image010.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374168"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">3.11 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">删除回滚日志文件</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">当数据变更已经安全的写入到硬盘之后，回滚日志文件就没有必要再存在了，因此立即删除之。如果在删除之前又掉电了或者系统崩溃了，恢复进程（在后面将会提到）会将日志文件的内容写回到数据库文件中</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">--</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">即使这个数据库没有发生变化。如果删除之后系统崩溃或者又停电了，看起来好象所有变化都已经写入到磁盘。因此，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">判断数据库文件是否完成了变更是依赖于回滚日志文件是否存在。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">删除一个文件实际上不是一个原子操作，但从用户进程的角度来看，它是一个原子操作。一个进程总是可以向操作系统询问某个文件存在否，而它得到的答案只有"</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">YES</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"和"</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">NO</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"二种。在一个事务提交的中间，系统崩溃或又停了，之后，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">会向操作系统咨询回滚日志文件存在与否，如果存在，则这个事务是没有完成，被中断了，需要对数据库文件进行回滚。如果日志文件不存在，意味着事务已经提交</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">ok</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">了。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">.</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">事务存在的可能性依赖于是否有回滚日志文件。删除一个文件对于一个用户进程来说是原子性的。因此，整个事务看起来也是一个原子操作。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">.</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="section_3_12"></a><span lang="EN-US"><img height="351" src="http://chensheng.net/p/sqlite/sqlite_images/image011.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374169"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">3.12 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">释放锁</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">事务提交最后一个步骤是释放独享锁，其他进程就又可以立即访问数据库文件了。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">右图中，我们指明了当锁被释放的时候用户空间所拥有的信息已经被清空了</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">.</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">对于老版本的</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">你可这么认为。但最新的</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">会保存些用户空间的缓存不会被清空</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">--</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">万一下一个事务开始的时候，这些数据刚好可以用上呢。重新利用这些内存要比再次从操作系统磁盘缓存或者硬盘中读取要来得轻松与快捷得多，何乐而不为呢？在再次使用这些数据之前，我们必须先取得一个共享锁，同时我们还不得不去检查一下，保证还没有其他进程在我们拥有共享锁之前对数据库文件进行了修改。数据库文件的第一页中有一个计数器，数据库文件每做一次修改，这个计数器就会增长一下。我们可以通过检查这个计数器就可得知是否有其他进程修改过数据库文件。如果数据库文件已经被修改过了，那么用户内存空间的缓存就不得不清空，并重新读入。大多数情况下，这种情况不大会发生，因此用户空间的内存缓存将是有效的，这对于性能提高来说作用是显著的。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="270" src="http://chensheng.net/p/sqlite/sqlite_images/image012.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374170"><b><span lang="EN-US" style="FONT-SIZE: 18pt; FONT-FAMILY: 'Verdana sans-serif'">4.0 </span></b></a><b><span style="FONT-SIZE: 18pt; FONT-FAMILY: 宋体">回滚</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">原子提交被设定是瞬间发生的。但上面的描述已经指出了其实这个过程是要花费不少时间的。如果在上面的提交过程中，计算机的电源被拉掉的情况下，为了保证变更是瞬间发生的事情，我们将"回滚"这些变化，将数据库文件恢复到事务开始之前的状态。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374171"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">4.1</span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">出事了，出事了</span></b><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">!!!</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">假设掉电发生在上面</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.10</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">步骤中。电源恢复之后，当前的状态可能如右图所示。我们打算修改数据库文件中的三页但只有一页被成功写入，其他一页只部分写入，还有一页根本就没有写入。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">这时，回滚日志文件是完整的。这是关键因素。上面</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.7</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">步骤做</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">操作的理由是将任何变更写入到数据库文件之前要绝对保证回滚日志文件已经安全、完整的写入到了永久存储中。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="section_4_2"></a><span lang="EN-US"><img height="351" src="http://chensheng.net/p/sqlite/sqlite_images/image013.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374172"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">4.2 Hot Rollback Journals</span></b></a></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">上面</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.2</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">节已经描述了，所有</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">进程尝试访问数据库文件之前，都得必须取得一个共享锁。但现在却被告知有一个回滚日志文件存在。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">会进行检查看这个日志文件是否是一个"</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">hot journal</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">A hot journal</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">是指需要被用来进行处理以使数据库回复到健壮的初始状态的。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">hot journal</span><span style="FONT-FAMILY: 宋体">的存在意味着早先的进程在一个事务中间发生了系统崩溃或掉电故障。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="FONT-FAMILY: 宋体">回滚日志是一个</span><span lang="EN-US">"hot"</span><span style="FONT-FAMILY: 宋体">的先天条件</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">回滚日志文件存在</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">回滚日志非空</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">这时数据库文件没有独享锁</span></p>
<p class="MsoNormal" style="MARGIN-LEFT: 21pt; TEXT-INDENT: -21pt; TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-FAMILY: Wingdings">l<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">回滚日志文件头部没有包括主日志文件的名字（</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">5.5</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">节）或者包含了主日志文件名称而且主日志文件存在</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="351" src="http://chensheng.net/p/sqlite/sqlite_images/image014.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">hot</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"日志文件存在指明先前的进程尝试去提交一个事务，但由于种种原因在完成提交以前，事务被中止了。同时指明了数据库文件的状态是需要通过回滚来修复的，修复之后才可以被正常使用。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374173"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">4.3 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">取得数据库的一个独享锁</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">为了处理"</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">hot</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"日志文件首先是要取得一个数据库的独享锁。这将防止</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">2</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">个或多个进程在同一时刻来尝试回滚同一个"</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">hot</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"日志文件。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="section_4_4"></a><span lang="EN-US"><img height="351" src="http://chensheng.net/p/sqlite/sqlite_images/image015.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374174"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">4.4 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">回滚没有完成的变更</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">一旦进程获得一个独享锁，它就被允许更新数据库文件。然后从日志文件中读取原始的内容，并写回到数据库文件中。是否还记得在这个被中止的事务的开始的时候，数据库文件原始大小已经被写进了日志文件的头部。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">使用这些信息来截断数据库文件，让文件恢复到原始大小</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">--</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">如果这个没有完成的事务使得数据库变大了。最后，数据库文件大小及内容肯定与这个被中断事务开始之前是一样的了。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="351" src="http://chensheng.net/p/sqlite/sqlite_images/image016.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374175"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">4.5 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">删除</span></b><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">hot</span></b><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">日志文件</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">当日志文件中的所有数据都被放回至数据库文件之后（并且做了</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">），此日志文件就可以被删除了。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="351" src="http://chensheng.net/p/sqlite/sqlite_images/image017.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374176"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">4.6 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">如果一切正常，没有什么未完成的写操作</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">恢复过程最后的步骤就是将独享锁降格成共享锁。一旦到了这里，数据库已经回得被中断事务开始的时状态。既然这个恢复操作已经完成，自动，自然而又透明，似乎被中断的事务从没有发生过一样！</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: Wingdings">J</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="270" src="http://chensheng.net/p/sqlite/sqlite_images/image018.gif" width="295" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374177"><b><span lang="EN-US" style="FONT-SIZE: 18pt; FONT-FAMILY: 'Verdana sans-serif'">5.0 </span></b></a><b><span style="FONT-SIZE: 18pt; FONT-FAMILY: 宋体">多文件提交</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">允许单个数据库联接通过使用</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'"><a href="http://sqlite.org/lang_attach.html"><font color="#45735f">ATTACH DATABASE</font></a></span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">命令同时与</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">2</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">个或多个数据库文件交互。在一个事务中，多个数据库文件被修改，所有文件的更新是原子性的。换而言之，要么所有文件被修改好了，要么什么也没有发生。针对多个文件的原子提交是要比仅针对单个文件的处理复杂一些。本节描述</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">是如何完成这有魔术色彩的工作的。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374178"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">5.1 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">每个数据库文件单独拥有日志文件</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">当一个事务涉及到多个数据库文件时，每个数据库文件都会有其相应的独立的回滚日志文件，并且每个数据库都是分别加锁的。下图显示了某个事务中修改了三个不同的数据库文件。这种情况与</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.6</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">步骤处理单个文件的事务还是有一些类似的。每个数据库文件有一个独享锁。针对每个数据库，要被修改页的原始内容被写入它们相应的回滚日志文件，但日志文件的内容还没有被</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">到硬盘中。这时针对数据库的变更还没有发生，虽然有可能用户空间的数据已经发生了变化。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">简单的说，下图已经简化了它们之前的状态。蓝色仍然指明是原始内容，而粉红是新的内容。但日志文件及数据库单独的页我们没有指示出来，同时我们也没有指明信息在操作系统磁盘缓存与硬盘中信息的差异。所有这些因素在一个多文件提交的场合下仍然起作用。这些因素会占据图中许多位置，但并没有增加新的信息，因此它们在此图中被省略掉了</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体-方正超大字符集">。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="267" src="http://chensheng.net/p/sqlite/sqlite_images/image019.gif" width="204" border="0" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374179"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">5.2 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">主日志文件</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">多文件提交的下一步是生成"主日志"文件。主日志文件的名称是与原始的数据库文件名</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'"> <span lang="EN-US">(</span></span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">数据库指的是用</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">sqlite3_open</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">的，而不是</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'"><a href="http://sqlite.org/lang_attach.html"><font color="#45735f">ATTACHed</font></a></span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">等辅助数据库</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">)</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">，再加上文本</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">"<b>-mj</b><i>HHHHHHHH</i>"</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">。附加的</span><i><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">HHHHHHHH</span></i><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">是一个随机</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">32</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">位</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">16</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">进数。每一个新的主日志文件会有一个变化的随机数</span><i><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">HHHHHHHH</span></i><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">后缀。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">（<i>注意：前面计算主日志文件名的算法是与</i></span><i><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite3.5.0</span></i><i><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">是一致的，但这不是</span></i><i><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span></i><i><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">规范的一部分，或许在新版本中发生变化</span></i><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">）</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">不同于回滚日志文件，主日志文件并不包含任何数据库文件的页的原始内容。主日志文件包含了此事务所涉及的数据库的回滚日志文件的全路径。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">当主日志文件已经创建完成之后，它会被立即</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">到硬盘，这个操作早于任何其他操作。在</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">unix</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">下面，这个主日志文件所在目录也被同步到了硬盘，保证掉电以后主日志文件显示在此目录中。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="267" src="http://chensheng.net/p/sqlite/sqlite_images/image020.gif" width="368" border="0" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374180"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">5.3 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">更新回滚日志文件头</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">接下来在每一个回滚日志文件的头部需要记录主日志文件的全路径。当一个回滚日志文件被创建时，用来存储主日志文件名的空间已经被保留在每一个日志文件的开始部分。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">在主日志文件名写入到日志名头部之前与之后都要进行一次</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">Flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">日志文件内容到硬盘。做二回</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">很重要。幸运的是第二次的</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">相对而言代价不是那么昂贵，因为一般的日志文件只有一页发生变化（第一页）</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">这一步与</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.7</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">节的单个文件事务提交场景类似。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="267" src="http://chensheng.net/p/sqlite/sqlite_images/image021.gif" width="368" border="0" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374181"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">5.4 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">修改数据库文件</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">一旦所有的回滚日志文件已经</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">到了硬盘中，就已经很安全的进行数据库文件更新了。我们在修改数据库文件之前必须得到所有数据库的独享锁。当所有的修改都完成的时候，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flsuh</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">数据库文件到硬盘是非常重要的。这将防止因系统崩溃或掉电而导致数据库损坏。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">这个步骤与单个文件提交过程中</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.8,3.9</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">及</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.10</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">步骤是一致的。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="section_5_5"></a><span lang="EN-US"><img height="267" src="http://chensheng.net/p/sqlite/sqlite_images/image022.gif" width="368" border="0" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374182"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">5.5 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">删除主日志文件</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">接下来的步骤是删除主日志文件。对于多文件事务提交，这是一个要点。这个步骤与上面</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.11</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">中单个文件的事务提交场景是相呼应的。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">这时，如果发生系统崩溃或者又停电了，当系统重新运行的时候，即使回滚日志文件存在，这个事务不会被回滚。不同点在于回滚日志文件中主日志文件路径。当系统重启的时候，如果回滚日志文件没有主日志文件名</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">(</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">针对于单文件提交</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">)</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">或者主日志文件仍然存在的时候，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">才会将这些日志文件视为"</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">hot</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"，并将回滚日志文件的内容放回到数据库文件中去。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="267" src="http://chensheng.net/p/sqlite/sqlite_images/image023.gif" width="368" border="0" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">&nbsp;</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374183"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">5.6 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">清除回滚日志</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">多文件事务提交的最后一步是删除单独的回滚日志文件，释放数据库文件的独享锁，其他进程就可以看到数据库的变化；这与上面</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.12</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">是相一致的。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">这时事务已经提交完成了。所以删除日志的时间点并不是很紧急。当前的实现是删除某个回滚日志文件，并释放相应的数据库锁，然后处理另一个日志文件。以后有可能改为删除所有日志文件之后才释放所有的锁。日志文件删除只要是在其相对应的锁释放之前就没有任何问题。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><img height="262" src="http://chensheng.net/p/sqlite/sqlite_images/image024.gif" width="209" border="0" /></span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374184"><b><span lang="EN-US" style="FONT-SIZE: 18pt; FONT-FAMILY: 'Verdana sans-serif'">6.0</span></b></a><b><span style="FONT-SIZE: 18pt; FONT-FAMILY: 宋体">原子操作的一些实现细节</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.0</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">节大致描述了</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">中原子提交是如何工作的。但它略过了许多重要的细节。下面的这些部分将尝试补充说明这些地方。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374185"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">6.1 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">总是记录整个扇区</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">当数据库文件的原始代码被写入到日志文件时（参见</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.5</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">节），</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">总是写入完整的扇区，即使数据文件页大小是小于一个扇区。由于历史上的原因，</span><span lang="EN-US">SQLite</span><span style="FONT-FAMILY: 宋体">的扇区大小原先是固定为</span><span lang="EN-US">512</span><span style="FONT-FAMILY: 宋体">字节，此外由于最小的页大小是</span><span lang="EN-US">512</span><span style="FONT-FAMILY: 宋体">字节，因此这从来都不是一个问题。自</span><span lang="EN-US">SQLite3.3.14</span><span style="FONT-FAMILY: 宋体">版本以来，</span><span lang="EN-US">SQLite</span><span style="FONT-FAMILY: 宋体">便有可能使用最小扇区大于</span><span lang="EN-US">512</span><span style="FONT-FAMILY: 宋体">字节的海量存储设备。所以，自从</span><span lang="EN-US">3.3.14</span><span style="FONT-FAMILY: 宋体">版本开始，只要一个扇区中的任何一页被写进到回滚日志文件中，那么同一扇区中的所有节都会写入到日志文件中去。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">将扇区中的所有页都写入日志文件中去是很重要的，它将可以防止因为在写一个扇区时发生掉电故障而导致数据库损坏。假充页</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">1</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">2</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">4</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">都是保存扇区</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">1</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">中，页</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">2</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">被修改了。为了将这种变更写回到页</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">2</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">中，实际的硬件设备将也会同时重写页</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">1</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">及</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">4</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">的内容</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">--</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">这是因为硬件必须以扇区为单元作写操作。如果一个写操作正在进行的时候，由于电源的原因，发生了中断，这样，页</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">1</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">4</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">中会有</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">1</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">页或者多页数据是不完整，不正确的。因此为了防止这种损坏，数据库文件的同一扇区中的所有页都必须写入到日志文件中去。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374186"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">6.2 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">写日志文件时垃圾的处理</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">当向一个日志文件追加数据时</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">,QLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">总是悲观的假定文件会首先变大，变大的部分会填之一些无效的垃圾数据，在此之后正确的数据才会取代这些垃圾。换而言之，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">假定文件先改变大小，然后内容才会写进来。如果在文件大小增大之后，在内容还没有写完之前发生掉电故障，那么这些日志文件就会留下一些垃圾数据在其中。下次当电源恢复，另一个</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">进程就会看到这些保存了垃圾数据的日志文件，并同时会把这些垃圾数据回滚到数据库文件中去，然后整个数据库就玩完了。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">使用了二种方式来预防这种问题。首先，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">会记录日志文件中的页数量。这个数量被初始化成</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">0</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">。所以在尝试回滚一个不完整（可能不正确的）回滚日志文件时，处理回滚的进程会看到日志只包含</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">0</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">个页面，那么它就会不对数据库作任何改变。提交之后，日志文件会被</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">到硬盘中用来确保所有的内容都同步到硬盘，同时没有任何垃圾内容保留在文件中。同时，只有在此之后日志文件头部的页总数值才会置成真实有效的数据（原先数值是</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">0</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">）。日志文件的头部总是与任何数据页处于不同的扇区中。所以它可被修改并且单独</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">，因此即使发生掉电，也不会给页面数据带来任何风险。请注意，日志文件被单独</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">二回：第一次写页数据（其实也把头部给</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">了）第二次是将页面数量写入</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">(flush)</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">到文件头部中。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">前面的章节描述了当</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">synchronous pragma</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">设置成"</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">full</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"发生的事情。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">PRAGMA synchronous=FULL; </span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">缺省的</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">synchronous</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">设置是"</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">full</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"，所以上面描述是通常会发生的情形。然而，如果</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">synchronous</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">设置成"</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">normal</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">"，那么</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">会只会在页面数量写入之后，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">flush</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">日志文件一次。这将意味着一个数据破损的风险。因为有可能被修改的页面数量（非</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">0</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">）会比所有的数据早一些写入到硬盘之中。数据部分的写入虽然是更早调用的，但</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">假定实际的文件系统会重新调整写入顺序。所以有可能页面数量会更早的记录到磁盘中，即使是它的写请求是发生在最后。所以作为第二个预防手段，</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">SQLite</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">会为日志文件中的每一个页记录一个个</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">32</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">位的校验值。当一个日志回滚进程回滚数据时（节</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">4.4</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">），这些值用来指示这些页是否有效。如果发现一个不正确的校验时，那么回滚就会放弃。要注意的是，由于校验值比较小，所以校验值并不确保页面数据百分百的正确。但也不用过于担心，如果数据损坏了，检验值仍然正确的概率实在很小。所以校验值还是能够有一定作用的。</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'"> </span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">要知道，如果</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">synchronous</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">设置成</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">full</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">时校验时不是必须的。只有当</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">synchronous</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">设置成</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">normal</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">时，我们才使用这些校验值。尽管这样，校验数据是无害的，所以无论</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">synchronous</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">设是什么，他们都保存在日志文件了。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><a name="_Toc189374187"><b><span lang="EN-US" style="FONT-SIZE: 13.5pt; FONT-FAMILY: 'Verdana sans-serif'">6.3 </span></b></a><b><span style="FONT-SIZE: 13.5pt; FONT-FAMILY: 宋体">提交前缓存溢出</span></b></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">节</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.0</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">描述的提交过程都假定了所有变更的数据都保存在用户内存中，直到真正提交。这是通常会出现的状况。但有时一个非常大或（多）的修改会超出用户空间的内存缓存大小。在这种情况下，一个事务完成之前，缓存不得不将数据先写入到数据库中。</span></p>
<p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">在一个缓存发生溢出之前，这个数据库联接的状态如</span><span lang="EN-US" style="FONT-SIZE: 12pt; FONT-FAMILY: 'Verdana sans-serif'">3.6</span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体">节。数据库原始的内容已经被写入回滚日志文件中了，页面修改部分还保存在用户内存中。要处理这种缓存溢