﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Prayer-随笔分类-数据库,SQL</title><link>http://www.cppblog.com/prayer/category/7885.html</link><description>在一般中寻求卓越</description><language>zh-cn</language><lastBuildDate>Wed, 21 Dec 2011 14:27:16 GMT</lastBuildDate><pubDate>Wed, 21 Dec 2011 14:27:16 GMT</pubDate><ttl>60</ttl><item><title>两阶段提交</title><link>http://www.cppblog.com/prayer/archive/2011/12/21/162529.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Wed, 21 Dec 2011 06:30:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2011/12/21/162529.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/162529.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2011/12/21/162529.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/162529.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/162529.html</trackback:ping><description><![CDATA[&nbsp;一阶段提交(1PC One Phase Commit) 
<div>&nbsp;<wbr></wbr>&nbsp;<wbr></wbr>&nbsp;<wbr></wbr>一 阶段提交就是事务处理器向数据库服务器发出提交请求，然后等待数据库服务器的回应，收到回应后完成事务的提交，或者服务器返回提交失败的结果就回撤事务。 危险期从发出请求开始，到收到回应结束，这段时间中数据库完成数据的修改、日志记录等处理，处理越复杂，危险期就越长。</div>
<div>&nbsp;<wbr></wbr></div>
<h5>&nbsp;<wbr></wbr>&nbsp;<wbr></wbr>&nbsp;<wbr></wbr>两阶段提交(2PC&nbsp;<wbr></wbr>Two Phase Commit)</h5>
<p>&nbsp;<wbr></wbr>&nbsp;<wbr></wbr>&nbsp;<wbr></wbr> 两阶段提交把事务提交分成两个阶段：</p>
<ul><li>第一阶段，事务处理器向数据库服务器发出"准备提交"请求，数据库收到请求后执行相同的数据修改和日志记录等处理，不同的是处理完成后只是把事务的状态改成"可以提交",然后把结果返回给事务处理器。</li><li>事务处理器收到回应后进入第二阶段，如果在第一阶段内的危险期中发生了故障，事务处理器收不到回应，则认为事务失败，回撤事务。数据库服务器收不到第二阶段的确认提交请求，把"可以提交"的事务回撤.</li><li>两阶段的第二阶段中事务处理器向数据库服务器发出"确认提交"请求，数据库服务器把事务的"可以提交"状态改为"提交完成"状态，然后返回应答。 </li></ul>
<p>&nbsp;<wbr></wbr>&nbsp;<wbr></wbr> 从严格意义上说，两阶段提交并没有完全解决网络通讯危险期的问题，<strong>但因为第二阶段的处理很简单，只是修改了事务的状态，与第一阶段相比其处理时间极短，所以危险期极短，发生事务提交故障的可能性几乎不存在。&nbsp;<wbr></wbr></strong></p>
<p>&nbsp;</p>
<div>所谓两阶段提交, 即Two Phase Commit (2PC), 是分布式事务采用的一种处理</div><img src ="http://www.cppblog.com/prayer/aggbug/162529.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2011-12-21 14:30 <a href="http://www.cppblog.com/prayer/archive/2011/12/21/162529.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>主键与唯一索引</title><link>http://www.cppblog.com/prayer/archive/2011/12/21/162519.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Wed, 21 Dec 2011 02:58:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2011/12/21/162519.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/162519.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2011/12/21/162519.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/162519.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/162519.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 1.主键一定是唯一性索引，唯一性索引并不一定就是主键；<br />&nbsp;&nbsp;&nbsp;&nbsp; 2.一个表中可以有多个唯一性索引，但只能有一个主键；<br />&nbsp;&nbsp;&nbsp;&nbsp; 3.主键列不允许空值，而唯一性索引列允许空值。<img src ="http://www.cppblog.com/prayer/aggbug/162519.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2011-12-21 10:58 <a href="http://www.cppblog.com/prayer/archive/2011/12/21/162519.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DB2 Merge语句</title><link>http://www.cppblog.com/prayer/archive/2011/10/18/158618.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Tue, 18 Oct 2011 07:42:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2011/10/18/158618.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/158618.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2011/10/18/158618.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/158618.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/158618.html</trackback:ping><description><![CDATA[DB2 Merge语句是经常可以用到的DB2语句，下面对DB2 Merge语句作了详细的介绍，如果您对此方面感兴趣的话，不妨一看。 
<p>　　DB2 Merge语句的作用非常强大，它可以将一个表中的数据合并到另一个表中，在合并的同时可以进行插入、删除、更新等操作。我们还是先来看个简单的例子吧，假设你定义了一个雇员表(employe)，一个经理表(manager)，如下所示：</p>
<p>　　---雇员表(EMPLOYE)</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
<tbody>
<tr>
<td style="word-wrap: break-word" bgcolor="#fdfddf"><font style="font-weight: bold; color: #990000">以下是代码片段：</font><br />&nbsp;&nbsp;&nbsp; CREATE TABLE EMPLOYE ( <br />　　EMPLOYEID INTEGER NOT NULL,---员工号 <br />　　NAME VARCHAR(20) NOT NULL,---姓名 <br />　　SALARY DOUBLE---薪水 <br />　　); <br />　　INSERT INTO EMPLOYE (EMPLOYEID,NAME,SALARY) VALUES <br />　　(1,'张三',1000), <br />　　(2,'李四',2000), <br />　　(3,'王五',3000), <br />　　(4,'赵六',4000), <br />　　(5,'高七',5000);</td></tr></tbody></table></p>
<p>　　--经理表(MANAGER)</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
<tbody>
<tr>
<td style="word-wrap: break-word" bgcolor="#fdfddf"><font style="font-weight: bold; color: #990000">以下是代码片段：</font><br />&nbsp;&nbsp;&nbsp; CREATE TABLE MANAGER ( <br />　　EMPLOYEID INTEGER NOT NULL,---经理号 <br />　　NAME VARCHAR(20) NOT NULL,---姓名 <br />　　SALARY DOUBLE---薪水 <br />　　); <br />　　INSERT INTO MANAGER (MANAGERID,NAME,SALARY) VALUES <br />　　(3,'王五',5000), <br />　　(4,'赵六',6000);</td></tr></tbody></table></p>
<p>　　---雇员表(EMPLOYE)</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
<tbody>
<tr>
<td style="word-wrap: break-word" bgcolor="#fdfddf"><font style="font-weight: bold; color: #990000">以下是代码片段：</font><br />&nbsp;&nbsp;&nbsp; CREATE TABLE EMPLOYE ( <br />　　EMPLOYEID INTEGER NOT NULL,---员工号 <br />　　NAME VARCHAR(20) NOT NULL,---姓名 <br />　　SALARY DOUBLE---薪水 <br />　　); <br />　　INSERT INTO EMPLOYE (EMPLOYEID,NAME,SALARY) VALUES <br />　　(1,'张三',1000), <br />　　(2,'李四',2000), <br />　　(3,'王五',3000), <br />　　(4,'赵六',4000), <br />　　(5,'高七',5000);</td></tr></tbody></table></p>
<p>　　--经理表(MANAGER)</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
<tbody>
<tr>
<td style="word-wrap: break-word" bgcolor="#fdfddf"><font style="font-weight: bold; color: #990000">以下是代码片段：</font><br />&nbsp;&nbsp;&nbsp; CREATE TABLE MANAGER ( <br />　　EMPLOYEID INTEGER NOT NULL,---经理号 <br />　　NAME VARCHAR(20) NOT NULL,---姓名 <br />　　SALARY DOUBLE---薪水 <br />　　); <br />　　INSERT INTO MANAGER (MANAGERID,NAME,SALARY) VALUES <br />　　(3,'王五',5000), <br />　　(4,'赵六',6000);</td></tr></tbody></table></p>　经过一段时间，你发现这样的数据模型，或者说表结构设计简直就是一大败笔，经理和雇员都是员工嘛，为什么要设计两个表呢？发现错误后就需要改正，所以你决定，删除经理表(MANAGER)表，将MANAGER 表中的数据合并到EMPLOYE 表中，仔细分析发现，王五在两个表中都存在(可能是干的好升官了)，而刘八在EMPLOYE 表中并不存在，现在，我们要求把EMPLOYE 表中不存在的MANAGER都插入到EMPLOYE 表中，存在的更新薪水。该怎么办呢？这个问题并不难，通常，我们可以分两步，如下所示： 
<p>　　--更新存在的</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
<tbody>
<tr>
<td style="word-wrap: break-word" bgcolor="#fdfddf"><font style="font-weight: bold; color: #990000">以下是代码片段：</font><br />&nbsp;&nbsp;&nbsp; UPDATE EMPLOYE AS EM SET SALARY=(SELECT SALARY FROM MANAGER WHERE MANAGERID=EM.EMPLOYEID) <br />　　WHERE EMPLOYEID IN ( <br />　　SELECT MANAGERID FROM MANAGER <br />　　);</td></tr></tbody></table></p>
<p>　　---插入不存在的</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
<tbody>
<tr>
<td style="word-wrap: break-word" bgcolor="#fdfddf"><font style="font-weight: bold; color: #990000">以下是代码片段：</font><br />&nbsp;&nbsp;&nbsp; INSERT INTO EMPLOYE (EMPLOYEID,NAME,SALARY) <br />　　SELECT MANAGERID,NAME,SALARY FROM MANAGER WHERE MANAGERID NOT IN ( <br />　　SELECT EMPLOYEID FROM EMPLOYE <br />　　);</td></tr></tbody></table></p>
<p>　　--更新存在的</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
<tbody>
<tr>
<td style="word-wrap: break-word" bgcolor="#fdfddf"><font style="font-weight: bold; color: #990000">以下是代码片段：</font><br />&nbsp;&nbsp;&nbsp; UPDATE EMPLOYE AS EM SET SALARY=(SELECT SALARY FROM MANAGER WHERE MANAGERID=EM.EMPLOYEID) <br />　　WHERE EMPLOYEID IN ( <br />　　SELECT MANAGERID FROM MANAGER <br />　　);</td></tr></tbody></table></p>
<p>　　---插入不存在的</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
<tbody>
<tr>
<td style="word-wrap: break-word" bgcolor="#fdfddf"><font style="font-weight: bold; color: #990000">以下是代码片段：</font><br />&nbsp;&nbsp;&nbsp; INSERT INTO EMPLOYE (EMPLOYEID,NAME,SALARY) <br />　　SELECT MANAGERID,NAME,SALARY FROM MANAGER WHERE MANAGERID NOT IN ( <br />　　SELECT EMPLOYEID FROM EMPLOYE <br />　　);</td></tr></tbody></table></p>
<p>　　上面的处理是可以的，但是我们还可以有更简单的方法，就是用Merge语句，如下所示：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
<tbody>
<tr>
<td style="word-wrap: break-word" bgcolor="#fdfddf">
<p><font style="font-weight: bold; color: #990000">以下是代码片段：</font><br />&nbsp;&nbsp;&nbsp; MERGE INTO EMPLOYE AS EM <br />　　USING MANAGER AS MA <br />　　ON EM.EMPLOYEID=MA.MANAGERID <br />　　WHEN MATCHED THEN UPDATE SET EM.SALARY=MA.SALARY <br />　　WHEN NOT MATCHED THEN INSERT VALUES (MA.MANAGERID,MA.NAME,MA.SALARY); <br />　　MERGE INTO EMPLOYE AS EM <br />　　USING MANAGER AS MA <br />　　ON EM.EMPLOYEID=MA.MANAGERID <br />　　WHEN MATCHED THEN UPDATE SET EM.SALARY=MA.SALARY <br />　　WHEN NOT MATCHED THEN INSERT VALUES (MA.MANAGERID,MA.NAME,MA.SALARY);</p>
<p>&nbsp;</p></td></tr></tbody></table></p><br />　在上面的处理中，我们用经理表(MANAGER)的薪水更新了雇员表(EMPLOYE)的薪水，假设现在要求，如果经理表(MANAGER)的薪水&gt;雇员表(EMPLOYE)的薪水的时候更新，否则不更新，怎么办呢？如下： 
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
<tbody>
<tr>
<td style="word-wrap: break-word" bgcolor="#fdfddf"><font style="font-weight: bold; color: #990000">以下是代码片段：</font><br />&nbsp;&nbsp;&nbsp; MERGE INTO EMPLOYE AS EM <br />　　USING MANAGER AS MA <br />　　ON EM.EMPLOYEID=MA.MANAGERID <br />　　WHEN MATCHED AND EM.SALARY <br />　　WHEN NOT MATCHED THEN INSERT VALUES (MA.MANAGERID,MA.NAME,MA.SALARY); <br />　　MERGE INTO EMPLOYE AS EM <br />　　USING MANAGER AS MA <br />　　ON EM.EMPLOYEID=MA.MANAGERID <br />　　WHEN MATCHED AND EM.SALARY <br />　　WHEN NOT MATCHED THEN INSERT VALUES (MA.MANAGERID,MA.NAME,MA.SALARY);</td></tr></tbody></table></p>
<p>　　不仔细的朋友可能没有看出上面两条语句的区别，哈哈，请仔细对比一下这两条语句。上面的语句中多了ELSE IGNORE语句，它的意思正如它英文的意思，其它情况忽略不处理。如果你认为理论上应该不存在EM.SALARY&gt;MA.SALARY的数据，如果有，说明有问题，你想抛个异常，怎么办？如下：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
<tbody>
<tr>
<td style="word-wrap: break-word" bgcolor="#fdfddf"><font style="font-weight: bold; color: #990000">以下是代码片段：</font><br />&nbsp;&nbsp;&nbsp; MERGE INTO EMPLOYE AS EM <br />　　USING MANAGER AS MA <br />　　ON EM.EMPLOYEID=MA.MANAGERID <br />　　WHEN MATCHED AND EM.SALARY <br />　　WHEN MATCHED AND EM.SALARY&gt;MA.SALARY THEN SIGNAL SQLSTATE '70001' SET MESSAGE_TEXT = 'EM.SALARY&gt;MA.SALARY' <br />　　WHEN NOT MATCHED THEN INSERT VALUES (MA.MANAGERID,MA.NAME,MA.SALARY) <br />　　ELSE IGNORE; <br />　　MERGE INTO EMPLOYE AS EM <br />　　USING MANAGER AS MA <br />　　ON EM.EMPLOYEID=MA.MANAGERID <br />　　WHEN MATCHED AND EM.SALARY <br />　　WHEN MATCHED AND EM.SALARY&gt;MA.SALARY THEN SIGNAL SQLSTATE '70001' SET MESSAGE_TEXT = 'EM.SALARY&gt;MA.SALARY' <br />　　WHEN NOT MATCHED THEN INSERT VALUES (MA.MANAGERID,MA.NAME,MA.SALARY) <br />　　ELSE IGNORE;</td></tr></tbody></table></p>
<p>　　对于EM.SALARY&gt;MA.SALARY的情况，如果你不想抛异常，而是删除EMPLOYE中的数据，怎么办？如下：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
<tbody>
<tr>
<td style="word-wrap: break-word" bgcolor="#fdfddf"><font style="font-weight: bold; color: #990000">以下是代码片段：</font><br />&nbsp;&nbsp;&nbsp; MERGE INTO EMPLOYE AS EM <br />　　USING MANAGER AS MA <br />　　ON EM.EMPLOYEID=MA.MANAGERID <br />　　WHEN MATCHED AND EM.SALARY <br />　　WHEN MATCHED AND EM.SALARY&gt;MA.SALARY THEN DELETE <br />　　WHEN NOT MATCHED THEN INSERT VALUES (MA.MANAGERID,MA.NAME,MA.SALARY) <br />　　ELSE IGNORE; <br />　　MERGE INTO EMPLOYE AS EM <br />　　USING MANAGER AS MA <br />　　ON EM.EMPLOYEID=MA.MANAGERID <br />　　WHEN MATCHED AND EM.SALARY <br />　　WHEN MATCHED AND EM.SALARY&gt;MA.SALARY THEN DELETE <br />　　WHEN NOT MATCHED THEN INSERT VALUES (MA.MANAGERID,MA.NAME,MA.SALARY) <br />　　ELSE IGNORE;</td></tr></tbody></table></p>
<p>　　以上简单介绍了Merge语句的使用，它的应用不只是上面介绍的情况，其实它可以应用在很多其他语句不好处理情况，这需要你去发现，记住熟能生巧</p><br /><br /><img src ="http://www.cppblog.com/prayer/aggbug/158618.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2011-10-18 15:42 <a href="http://www.cppblog.com/prayer/archive/2011/10/18/158618.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LDAP</title><link>http://www.cppblog.com/prayer/archive/2010/10/21/130816.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Thu, 21 Oct 2010 15:40:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/10/21/130816.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/130816.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/10/21/130816.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/130816.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/130816.html</trackback:ping><description><![CDATA[<p>LDAP是轻量目录访问协议，英文全称是Lightweight Directory Access Protocol，一般都简称为LDAP。它是基于X.500标准的，但是简单多了并且可以根据需要定制。与X.500不同，LDAP支持TCP/IP，这对访问Internet是必须的。LDAP的核心规范在RFC中都有定义，所有与LDAP相关的RFC都可以在LDAPman RFC网页中找到。</p>
<br>LDAP是一个协议，一个标准。<br>为了实现这个协议，需要一个实体，这就是LDAP的产品。Server, Client, Storage，Interface.<br><br>
<table cellSpacing=0 cellPadding=0>
    <tbody>
        <tr>
            <td class=t_msgfont id=postmessage_7567487>置顶有一篇文章, 讲述了什么是LDAP<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B7%FE%CE%F1%C6%F7">服务器</span>, 看了一下,我觉得作者在概念上还有些模糊的地方。比如和<span class=t_tag onclick=tagshow(event) href="tag.php?name=%CA%FD%BE%DD%BF%E2">数据库</span>的关系等，作者是用了一个MySQL作的比较和对比。<br>我也看了一些这里的朋友提到的问题，其实如果了解LDAP的内涵，就很好解答这些问题了。<br><br>下面我从自己的理解，来说一下，希望和大家共享。<br>首先LDAP是一个轻量级的产品(LightWeight)，是一个Directory(D)，存取的协议(Access Protocol)。 <br><br>我要着重指出，LDAP是一个<span class=t_tag onclick=tagshow(event) href="tag.php?name=%CA%FD%BE%DD">数据</span>库，但是又不是一个数据库。说他是数据库，因为他是一个数据存储的东西。但是说他不是数据库，是因为他的作用没有数据库这么强大，而是一个目录。<br>为了理解，给一个例子就是电话簿（黄页）。我们用电话簿的目的是为了查找某个公司的电话，在这个电话簿中附带了一些这个公司的基本信息，比如地址，经营范围，联系方式等。<br>其实这个例子就是一个LDAP在现实生活中的表现。电话簿的组织结构是一条一条的信息组成，信息按照行业，类比进行了分类。每条记录都分成了若干的区域，其中涵盖了我们要的信息。这就是一个Directory。一个树状的结构，每个叶子都是由一条一条的分成若干区域的记录。LDAP就是这么一个东西。<br>从概念上说，LDAP分成了DN, OU等。OU就是一个树，DN就可以理解为是叶子，叶子还可以有更小的叶子。但是LDAP最大的分层按照IBM的文档是4层。<br><br>还是上面这个例子，电话簿由电话公司进行维护，因此写是由他们去写，去组织。写完了，组织好了，就完成了，以后再写，再组织的次数是有限的。而其作用是为了查找。LDAP也是类似，目的不是为了写，主要是为了查找。这就回答了有同志问，有人要写有人要读的并发怎么解决的问题。LDAP的用途不是针对这个来设计的，如果你有这样的需求，解决办法就应该是数据库，而不是LDAP。这就是另外一个例子，Access和SQL Server。Access就是一个数据库产品，但是主要用于家庭，功能和性能都比较弱。SQL Server就是一个专业的数据库<span class=t_tag onclick=tagshow(event) href="tag.php?name=%CF%B5%CD%B3">系统</span>，功能强大。LDAP是一个轻量级的产品，主要目的是为了查，因此在架构和优化主要是针对读，而不是写。但并不是说LDAP不能满足，只是说强项不在这里。<br><br>LDAP作为一个统一认证的解决<span class=t_tag onclick=tagshow(event) href="tag.php?name=%B7%BD%B0%B8">方案</span>，主要的优点就在能够快速响<span class=t_tag onclick=tagshow(event) href="tag.php?name=%D3%A6%D3%C3">应用</span>户的查找需求。比如用户的认证，这可能会有大量的并发。如果用数据库来实现，由于数据库结构分成了各个表，要满足认证这个非常简单的需求，每次都需要去搜索数据库，合成过滤，效率慢也没有好处。虽然可以有Cache，但是还是有点浪费。LDAP就是一张表，只需要用户名和口令，加上一些其他的东西，非常简单。从效率和结构上都可以满足认证的需求。这就是为什么LDAP成为现在很人们的统一认证的解决方案的优势所在。<br><br>当然LDAP也有数据写入的借口，是可以满足录入的要求的。这里就不多说了。<br>我认为现在最大的LDAP Server，应该还是Microsoft的AD。虽然不一定是标准的，但是的确是用的最多的一个LDAP Server。每个公司只要用到域，就肯定会用到了。</td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/prayer/aggbug/130816.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-10-21 23:40 <a href="http://www.cppblog.com/prayer/archive/2010/10/21/130816.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>三十五个非主流开源数据库 MongoDB领衔主演</title><link>http://www.cppblog.com/prayer/archive/2010/10/09/129189.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Sat, 09 Oct 2010 05:54:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/10/09/129189.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/129189.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/10/09/129189.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/129189.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/129189.html</trackback:ping><description><![CDATA[<p><font face=Verdana>几乎每个Web开发人员都有自己喜欢的数据库，或自己最熟悉的数据库，但最常见的无外乎以下几种：</font></p>
<p><font face=Verdana>MySQL</font></p>
<p><font face=Verdana>PostgreSQL</font></p>
<p><font face=Verdana>MSSQL Server</font></p>
<p><font face=Verdana>SQLite</font></p>
<p><font face=Verdana>MS Access</font></p>
<p><font face=Verdana>或是更简单的XML，文本文件等。这些数据库有优秀的文档，背后有强大的社区支持，大部分流行的CMS都使用了其中之一或多个，它们都易于使用，大多数托管服务供应商都提供了相应的产品，因此它们的使用量很多，名气也很大。但除了这些主流的数据库外，还有很多其它非主流数据库存在，其中有一些也开始受到人们的高度重视，下面我们就一起来看看吧，注意本文只介绍开源数据库，说不定在下一个项目中，你就有尝试它们的冲动。</font></p>
<p><font face=Verdana><strong>1、MongoDB</strong></font></p>
<p align=center><font face=Verdana><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007139591281686612143.jpg" border=0></font></p>
<p><font face=Verdana>MongoDB是一款开源，高性能，可扩展，无模式，面向文档(与JSON类似的数据模式)的数据库，它为时下最流行的编程语言提供了驱动，如PHP，Python，Perl，Ruby，JavaScript，C++等，支持全文索引，自动分片，跨LAN或WAN扩展，采用Key/Value方式存储数据。MongoDB服务端可运行在Linux、Windows或OS X平台，支持32位和64位应用。世界上最大的单词收录网站Wordnik就从MySQL转向了MongoDB。</font></p>
<p><font face=Verdana><strong>2、Hypertable</strong></font></p>
<p align=center><font face=Verdana><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007132731281686623034.jpg" border=0></font></p>
<p><font face=Verdana>Hypertable是一款高性能分布式数据存储系统，旨在为应用程序提供最好的性能，可扩展性和可靠性，它建立在Google的BigTable之上，主要面向大规模数据集应用，其目标是要成为世界上最好的大规模并发高性能数据库平台。百度目前也使用了Hypertable，也是它的赞助商。</font></p>
<p><font face=Verdana><strong>3、Apache CouchDB</strong></font></p>
<p align=center><font face=Verdana><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007136731281686632878.jpg" border=0></font></p>
<p><font face=Verdana>Apache CouchDB是一款面向文档的数据库，可以使用JavaScript通过MapReduce方法进行查询和索引，它提供了一个RESTful JSON API，因此可以在任何环境中通过HTTP访问，CouchDB内置了Web管理控制台，支持通过浏览器管理数据库。CouchDB使用Erlang编写，Erlang是一种健壮的函数式编程语言，非常适合于构建并发的分布式系统，Erlang的设计非常灵活，其可伸缩性与可扩展性都非常棒。</font></p>
<p><font face=Verdana><strong>4、Neo4j</strong></font></p>
<p align=center><font face=Verdana><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007132331281686642675.jpg" border=0></font></p>
<p><font face=Verdana>Neo4j是一个嵌入式，基于磁盘的，支持完整事务的Java持久化引擎，它在图像中而不是表中存储数据。Neo4j提供了大规模可扩展性，在一台机器上可以处理数十亿节点/关系/属性的图像，可以扩展到多台机器并行运行。相对于关系数据库来说，图形数据库善于处理大量复杂、互连接、低结构化的数据，这些数据变化迅速，需要频繁的查询——在关系数据库中，这些查询会导致大量的表连接，因此会产生性能上的问题。Neo4j重点解决了拥有大量连接的传统RDBMS在查询时出现的性能衰退问题。通过围绕图形进行数据建模，Neo4j会以相同的速度遍历节点与边，其遍历速度与构成图形的数据量没有任何关系。此外，Neo4j还提供了非常快的图形算法、推荐系统和OLAP风格的分析，而这一切在目前的RDBMS系统中都是无法实现的。</font></p>
<p><font face=Verdana><strong>5、Riak</strong></font></p>
<p align=center><font face=Verdana><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007131181281686658003.jpg" border=0></font></p>
<p><font face=Verdana>Riak是一款非常适合于Web应用程序的数据库，它提供了去中心化的Key/Value存储，灵活的map/reduce引擎和友好的HTTP/JSON查询接口。它是一个真正的容错系统，不会出现单点故障，在Riak世界中，没有哪台机器是特殊的或属核心服务器，它们都是对等的。</font></p>
<p><font face=Verdana><strong>6、Oracle Berkeley DB</strong></font></p>
<p align=center><font face=Verdana><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007133491281686668096.jpg" border=0></font></p>
<p><font face=Verdana>Oracle Berkeley DB是一系列开源的嵌入式数据库，使开发人员能够将一个快速、可伸缩、具有工业级别的可靠性和可用性的事务处理数据库引擎结合进他们的应用程序中。Berkeley DB最先由伯克利加州大学为了移除受到AT&amp;T限制的程式码，从BSD 4.3到4.4时所改写的软件。Berkeley DB运行在大多数的操作系统中，例如大多数的UNIX系统， 和windows系统，以及实时操作系统。</font></p>
<p><font face=Verdana><strong>7、Apache Cassandra</strong></font></p>
<p align=center><font face=Verdana><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007139581281686679862.jpg" border=0></font></p>
<p><font face=Verdana>Cassandra是一款高可扩展性第二代分布式数据库，属于混合型的非关系的数据库，类似于Google的BigTable，支持的数据结构非常松散，类似于JSON的BJSON格式，因此可以存储比较复杂的数据类型。Cassandra最初由Facebook开发，后转变成了开源项目。Cassandra的主要特点就是它不是一个数据库，而是由一堆数据库节点共同构成的一个分布式网络服务，对Cassandra 的一个写操作，会被复制到其他节点上去，对Cassandra的读操作，也会被路由到某个节点上面去读取。对于一个Cassandra群集来说，扩展性能是比较简单的事情，只管在群集里面添加节点就可以了。Facebook，Digg，Twitter和Cisco等大型网站都使用了Cassandra。</font></p>
<font face=Verdana></font>
<p><strong>8、Memcached</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007130331281686695081.jpg" border=0></p>
<p>Memcached是开源的分布式cache系统，现在很多的大型web应用程序包括facebook，youtube，wikipedia，yahoo等等都在使用memcached来支持他们每天数亿级的页面访问。通过把cache层与他们的web架构集成，他们的应用程序在提高了性能的同时，还大大降低了数据库的负载。</p>
<p>Memcached处理的原子是每一个key/value对，key会通过一个hash算法转化成hash-key，便于查找、对比以及做到尽可能的散列。同时，memcached用的是一个二级散列，通过一张大hash表来维护。</p>
<p><strong>9、Firebird</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007133841281686705018.jpg" border=0></p>
<p>Firebird是一个关系数据库，可以运行在Linux，Windows和各种Unix平台上，Firebird相对MySQL和PostgreSQL来说比较小，这也使其可以称得上是理想的嵌入式数据库，可用于与其它应用程序服务器和应用程序捆绑。Firebird具有大部分成熟数据库所具有的功能，比如支持存储过程、SQL兼容等。</p>
<p><strong>10、Redis</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007133881281686714768.jpg" border=0></p>
<p>Redis是一款快速的Key/Value数据库引擎，它在保持键值数据库简单快捷特点的同时，又吸收了部分关系数据库的优点，从而使它的位置处于关系数据库和键值数据库之间。Redis不仅能保存Strings类型的数据，还能保存Lists类型(有序)和Sets类型(无序)的数据，而且还能完成排序(SORT)等高级功能，在实现INCR，SETNX等功能的时候，保证了其操作的原子性，除此以外，还支持主从复制等功能。Redis使用C语言编写，可以想memcached那样使用，放在传统数据库的前端，它支持许多编程语言，受到许多流行的项目使用，如GitHub和Engine Yard，有一个用PHP编写的客户端叫做Rediska，专门来管理Redis数据库。</p>
<p><strong>11、HBase</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007135481281686725143.jpg" border=0></p>
<p>HBase是一个分布式，面向列存储的数据库引擎，也可以叫做Hadoop数据库，因为它是Hadoop的子项目，HBase的目标是托管数十亿行，数百万列的大表，它提供了一个REST风格的Web服务器网关，支持XML，Protobuf和二进制数据编码选项。</p>
<p><strong>12、Keyspace</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007130221281686735300.jpg" border=0></p>
<p>Keyspace 是一家叫做 Scalien 的创业公司开发的高可靠 key/value 存储系统，Keyspace 强调的技术点是高可靠性，有以下一些特点：</p>
<p>Key/Value存储：一个 key/value 数据存储系统，只支持一些基本操作，如：SET(key, value) 和 GET(key) 等;</p>
<p>分布式：多台机器(nodes)同时存储数据和状态，彼此交换消息来保持数据一致，可视为一个完整的存储系统。为了更可靠，Keyspace 推荐使用奇数个 nodes，比如：3，5，7等;</p>
<p>数据一致：所有机器上的数据都是同步更新的、不用担心得到不一致的结果，Keyspace 使用著名的 Paxos 分布式算法;</p>
<p>冗余：所有机器(nodes)保存相同的数据，整个系统的存储能力取决于单台机器(node)的能力;</p>
<p>容错：如果有少数 nodes 出错，比如重启、当机、断网、网络丢包等各种 fault/fail 都不影响整个系统的运行;</p>
<p>高可靠性：容错、冗余等保证了 Keyspace 的可靠性。</p>
<p><strong>13、4store</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007130631281686857143.jpg" border=0></p>
<p>4store是一个容纳RDF数据的数据库存储和查询引擎，它使用ANSI C99编写，可在类Unix系统上运行，提供一个高性能，可扩展和稳定的平台。4store专门为无共享集群进行优化，最大可支持32节点集群，导入性能最大可以达到120kT/s，它的查询性能也相当出众。</p>
<p><strong>14、MariaDB</strong></p>
<p align=center><img src="http://www.cnw.com.cn:8080/resources/2010_07/2010_07_13/201007130391281686827675.jpg" border=0></p>
<p>MariaDB是一个向后兼容的，旨在替换MySQL数据库的MySQL分支，它包括所有主要的开源存储引擎，另外也开发了属于自己的Maria存储引擎。MariaDB是由原来 MySQL 的作者 Michael Widenius 创办的公司所开发的免费开源数据库服务器，与 MySQL 相比较，MariaDB 更强的地方在于：</p>
<p>Maria 存储引擎</p>
<p>PBXT 存储引擎</p>
<p>XtraDB 存储引擎</p>
<p>FederatedX 存储引擎</p>
<p>更快的复制查询处理</p>
<p>线程池</p>
<p>更少的警告和bug</p>
<p>运行速度更快</p>
<p>更多的 Extensions (More index parts, new startup options etc)</p>
<p>更好的功能测试</p>
<p>数据表消除</p>
<p>慢查询日志的扩展统计</p>
<p>支持对 Unicode 的排序</p>
<p><strong>15、Drizzle</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007130661281686907675.jpg" border=0></p>
<p>Drizzle是从MySQL衍生出来的一个数据库，但它的目的不是要取代MySQL，它的宗旨是构建一个&#8220;更精练、更轻量、更快速&#8221;的MySQL版本，它的扩展性和易用性与MySQL相当，但为了提高性能和扩展性，它从原来的核心系统里移除了部分功能。Drizzle是一种为云和网络程序进行了特别优化的数据库，它是为在现代多CPU/多核架构上实现大规模并发而设计的。</p>
<p><strong>16、HyperSQL</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007130611281686934253.jpg" border=0></p>
<p>HyperSQL是用Java编写的一款SQL关系数据库引擎，它的核心完全是多线程的，支持双向锁和MVCC(多版本并发控制)，几乎完整支持ANSI-92 SQL，支持常见数据类型，最新版本增加了对BLOB和CLOB数据的支持，最高支持达64T的数据量。同时，HyperSQL也是一个不错的嵌入式数据库。</p>
<p><strong>17、MonetDB</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007133531281686946315.jpg" border=0></p>
<p>MonetDB是一个高性能数据库引擎，主要用在数据挖掘，OLAP，GIS，XML Query，文本和多媒体检索等领域。MonetDB对DBMS的各个层都进行创新设计，如基于垂直分片的存储层，为现代CPU优化的查询执行架构，自动和自助调整索引，运行时查询优化，以及模块化的软件架构。MonetDB/SQL是MonetDB提供的关系数据库解决方案，MonetDB/XQuery是XML数据库解决方案，MonetDB Server是MonetDB的多模型数据库服务器。</p>
<p><strong>18、Persevere</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007130771281686983862.jpg" border=0></p>
<p>Persevere 是针对Javascript设计的基于REST的JSON数据库，分布式计算，持久对象映射的框架，提供独立的web服务器，主要用于设计富客户端应用，可以用在任何框架和客户端上。Persevere Server是一个基于Java/Rhino的对象存储引擎，在交互式的客户端JavaScript环境中提供持久性的JSON数据格式。</p>
<p><strong>19、eXist-db</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007134901281686992175.jpg" border=0></p>
<p>eXist-db是使用XML技术构建的数据库存储引擎，它根据XML数据模型存储XML数据，提供高效的，基于索引的XQuery查询。eXist-db支持许多Web技术标准，使得它非常适合Web应用程序开发：</p>
<p>XQuery 1.0 / XPath 2.0 / XSLT 1.0 (使用pache Xalan)或XSLT 2.0</p>
<p>HTTP接口：REST，WebDAV，SOAP，XMLRPC，Atom发布协议</p>
<p>XML数据库规范：XMLDB，Xupdate，XQuery更新扩展</p>
<p>最新的1.4版本还增加了基于Apache Lucene的全文索引，轻量级URL重写和MVC框架，以及对XProc的支持。eXist-db与XQuery标准高度兼容(目前XQTS的得分是99.4%)。</p>
<p><strong>20、Gladius</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007134881281687001628.jpg" border=0></p>
<p>Gladius是用纯PHP编写的平面文件数据库引擎，它的SQL语法与SQL92的一个子集兼容，它捆绑了一个轻量级的adoDB驱动。</p>
<p><strong>21、CloudStore</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007134541281687011471.jpg" border=0></p>
<p>CloudStore(以前叫做Kosmos文件系统)是一个开源的高性能分布式文件系统，它是用C++编写的，CloudStore可以和Hadoop以及Hypertable集成，这样就允许应用程序构建在那些系统上，而底层数据存储无缝地使用CloudStore。CloudStore支持Linux和Solaris，主要用来存储Web日志和Web爬行数据。<br></p>
<p><strong>22、OpenQM</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007133771281687023206.jpg" border=0></p>
<p>OpenQM是唯一一款同时有商业支持和免费的开源多值数据库，基于GPL协议发布，多值数据库对NoSQL运动起到了推动作用，它自身也因速度快，体积小，比关系数据库便宜而很快得到了认可。名称OpenQM中的Open表示开源版本，QM表示商业闭源QM数据库。商业版本支持Windows，Linux(RedHat，Fedora，Debian，Ubuntu)，FreeBSD，Mac OS X和Windows Mobile，其列表价格还不到其它多值产品的1/5，商业版本还包括一个GUI管理界面和终端模拟器，开源版本仅包括核心多值数据库引擎，主要是为开发人员准备的。</p>
<p><strong>23、ScarletDME</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007132201281687033237.jpg" border=0></p>
<p>ScarletDME也是一个开源多值数据库，它是OpenQM的社区分支版，最初由Ladybridge开发，这个项目创立于2008年11月28日，它既在独立开发自己的功能，也在为OpenQM贡献代码。这个项目最初的名字叫做Ladybridges GPL OpenQM，现在正式改为ScarletDME，其中的DME是Data Management Environment(数据管理环境)的首字母缩写。</p>
<p><strong>24、SmallSQL</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007132041281687049440.jpg" border=0></p>
<p>SmallSQL是一个100%纯Java编写的轻量级数据库，一般用于嵌入式领域，兼容SQL 99标准，支持JDBC 3.0 API，定位于高端Java桌面SQL数据库。支持所有能运行Java的平台，可直接嵌入到应用程序中。不过它也有一些不足，如没有网络接口，必须安装Java运行时，同一时间不能在多个应用程序之间共享数据库，没有用户管理。</p>
<p><strong>25、LucidDB</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007131681281687058643.jpg" border=0></p>
<p>LucidDB是唯一一款专注于数据仓库和商务智能的开源RDBMS，它使用了列存储架构，支持位图索引，哈希连接/聚合和页面级多版本，大部分数据库最初都注重事务处理能力，而分析功能都是后来才加上去的。相反，LucidDB中的所有组件从一开始就是为满足灵活的需求，高性能数据集成和大规模数据查询而设计的，此外，其架构设计彻底从用户出发，操作简单，完全无需DBA。</p>
<p>LucidDB对硬件要求也极低，即使不搭建集群环境，在单一的Linux或Windows服务器上也能获得极好的性能。最新版本还加入了对Mac OS X和Windows 64位的支持，官方网站上的文档和教程也非常丰富，非常值得你体验一下。</p>
<p><strong>26、HyperGraphDB</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007130281281687068612.jpg" border=0></p>
<p>HyperGraphDB是一种通用的，可扩展的，可移植的，分布式，嵌入式和开源数据存储机制，它是一个图形数据库，专门为人工智能和语义Web项目而设计，它也可用于任意规模的嵌入式面向对象的数据库。正如其名，HyperGraphDB是用来存储超图的，但它也属于一般图形数据库家族，作为一个图形数据库，它不施加任何限制，相比其他图形数据库它的功能更丰富。</p>
<p>HyperGraphDB非常稳定，已经应用在多个生产环境，包括一个搜索引擎和Seco scripting IDE。它支持*nix和Windows平台，需要Java 5+。</p>
<p><strong>27、InfoGrid</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007130061281687079096.jpg" border=0></p>
<p>InfoGrid是一个互联网图形数据库，它提供了许多额外的组件，使得在图像基础上开发RESTful Web应用程序变得更加容易。InfoGrid是开源的，包括一系列项目：</p>
<p>InfoGrid图形数据库项目 &#8211; InfoGrid的心脏GraphDatabase，可以独立使用，也可以附加到其它InfoGrid项目。</p>
<p>InfoGrid图形数据库网格项目 &#8211; 在GraphDatabase基础上增加了复制协议，因此多个分布式GraphDatabase就可以在一个非常大的图像管理环境中协作。</p>
<p>InfoGrid存储项目 &#8211;象SQL数据库和分布式NoSQL哈希表那样，为存储技术提供一个抽象的通用接口，这样InfoGrid GraphDatabase就可以使用任何存储技术持久化数据。</p>
<p>InfoGrid用户接口项目 &#8211; 将GraphDatabase中的内容以REST风格映射成浏览器可访问的URL。</p>
<p>InfoGrid轻量级身份识别项目 &#8211; 实现以用户为中心的身份识别技术，如LID和OpenID。</p>
<p>InfoGrid模型库项目 &#8211; 定义一个可复用对象模型库，作为InfoGrid应用程序的模式使用。</p>
<p>InfoGrid Probe项目 &#8211; 实现Probe框架，它允许开发人员将任何互联网上的数据源当作一个图像对象看待。</p>
<p>InfoGrid Utilities项目 &#8211; 收集InfoGrid使用的常见对象框架和实用代码。</p>
<p><strong>28、Apache Derby</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007135181281687090565.jpg" border=0></p>
<p>Apache Derby是Apache DB的子项目，它完全用Java编写，是一个开源关系数据库，它的体积非常小，基础引擎加上JDBC驱动只有2.6MB，它支持SQL标准，它提供了一个嵌入式JDBC驱动，因此可以嵌入到任何基于Java的应用程序中，Derby也支持常见的客户端/服务器模式，它也易于安装和使用。</p>
<p><strong>29、hamsterdb</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007136431281687103034.jpg" border=0></p>
<p>Hamsterdb是一个轻量级嵌入式NoSQL Key/Value存储引擎，它已经有5年历史，现在它的开发重点放在易用性，高性能，稳定性和可扩展性上。Hamsterdb支持事务(同一时间只能处理一个事务)，支持内存数据库，支持基于HTTP服务器的嵌入式远程数据库，支持日志/恢复，AES加密，基于zlib的压缩，支持C++，Python，.NET和Java编程语言。</p>
<p><strong>30、H2 Database</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007131341281687117643.jpg" border=0></p>
<p>H2 Database是一个开源的Java数据库，它的速度很快，包括JDBC API，支持嵌入式和服务器模式，内存数据库，提供了一个基于浏览器的控制台程序，它的体积也非常小，只有一个大小约1MB的jar文件，它还支持ODBC驱动和全文搜索。</p>
<p><strong>31、EyeDB</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007135831281687126596.jpg" border=0></p>
<p>EyeDB是一款基于ODMG 3规范的面向对象数据库管理系统，为C++和Java提供了编程接口，它功能非常强大，并且成熟，稳定和安全，实际上，它起源于1992年的Genome View项目，1994年又进行了重写，广泛用于生物信息项目。</p>
<p><strong>32、txtSQL</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007131481281687134346.jpg" border=0></p>
<p>txtSQL是一个面向对象的平面文件数据库管理系统，它使用PHP编写，支持对普通文本文件的操作，虽然是一个文本数据库，但同样支持SQL的一个子集，并且执行效率非常高，txtSQL使用文件系统的方法与MySQL的表和数据库原理类似，它有一个类似于phpMyAdmin管理界面。</p>
<p><strong>33、db4o</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007136541281687148987.jpg" border=0></p>
<p>db4o是一个面向对象的开源数据库，允许Java和.NET开发人员用一行代码存储和检索任何应用程序对象，无需预定义或维护一个独立的，僵化的数据模型，因为模型现在是由db4o根据需要自动创建和更新的。db4o成功的秘密是因为它的易用性，它原生为Java和.NET设计，存储数据对象的方法直接在应用程序中定义，因此db4o很容易集成到应用程序中，由于只需要一行代码，因此执行效率非常高。</p>
<p><strong>34、Tokyo Cabinet</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007132671281687158893.jpg" border=0></p>
<p>Tokyo Cabinet是一个Kay/Value型数据库，每个Key和Value的长度都可以不同，Kay和Value既可以是二进制数据，也可以是字符串，无数据表和数据类型的概念，记录是以哈希表、B+树和固定长度数组形式组织的。Tokyo Cabinet具有以下优点：</p>
<p>空间利用率高 &#8211; 数据文件尺寸更小;</p>
<p>执行效率高 &#8211; 更快的处理速度;</p>
<p>并发性能好 &#8211; 在多线程环境性能更好;</p>
<p>改善的可用性 &#8211; 简化的API;</p>
<p>改善的可靠性 &#8211; 即使在发生灾难的情况下，数据文件也不会损坏;</p>
<p>支持64位架构 &#8211; 支持海量的存储空间和巨型数据库文件。</p>
<p>Tokyo Cabinet是用C语言编写的，为C，Perl，Ruby，Java和Lua提供了API。</p>
<p><strong>35、Voldemort项目</strong></p>
<p align=center><img src="http://newtest.cnw.cn/resources/2010_07/2010_07_13/201007131581281687169721.jpg" border=0></p>
<p>Voldemort是一个分布式Key/Value存储系统，它具有以下特点：</p>
<p>数据自动在多个服务器之间复制;</p>
<p>数据自动分区，因此每个服务器只包括整体数据的一个子集;</p>
<p>服务器故障处理是透明的;</p>
<p>支持插入式序列化，允许丰富的Key和Value类型，包括列表和元组，也可以集成常见的序列化框架，如Protocol Buffers，Thrift，Avro和Java Serialization</p>
<p>数据项支持版本化，即使在故障情况下，数据完整性也可以得到保障;</p>
<p>每个节点都是独立的，无需其他节点协调，因此也没有中央节点;</p>
<p>单节点性能优秀：根据机器配置、网络、磁盘系统和数据复制因素的不同，每秒可以执行10-20k操作;</p>
<p>支持地理分散式部署。</p>
<p>LinkedIn目前就使用Voldemort解决了高可伸缩性存储问题。</p>
<p>不知道你是否一口气看完本文，我想你也一定会惊讶于这么多开源数据库吧，事实上，本文也尚未完全罗列，欢迎你的补充。</font></p>
<img src ="http://www.cppblog.com/prayer/aggbug/129189.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-10-09 13:54 <a href="http://www.cppblog.com/prayer/archive/2010/10/09/129189.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>系统临时表使用问题</title><link>http://www.cppblog.com/prayer/archive/2010/05/13/115318.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Thu, 13 May 2010 15:14:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/05/13/115318.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/115318.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/05/13/115318.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/115318.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/115318.html</trackback:ping><description><![CDATA[系统临时表的使用：<br>在一些程序中，我们需要一些仅仅在程序中使用的临时表，但是程序结束后就不再使用，数据库系统对这些应用提供系统临时表，关于系统临时表的生命存在周期和临时表的数据存在周期说明一下：<br><br>1、生命存在周期：<br>Ａ、理论上系统临时表是不需要显示的drop的，它是基于会话的，当系统临时表基于的连接关闭的时候，系统临时表将结束它的生命，这是最普通也是最常用的。<br><br>Ｂ、当一个被调用对象的返回值是一个在临时表上执行的结果集，这个被调用对象执行完毕的时候，是关闭连接的，但是，这时候临时表是不消失的，这时候系统临时表在调用者结束的时候才消失。因为返回的结果集只是一个相当于指针的东西，指向临时表内存中的地址，指向临时表的指针还在使用的时候，临时表是不能drop掉的。这带来了很复杂的问题，首先：存储过程中是不能drop临时表的，而程序中没有创建临时表，也应该是不drop的，临时表什么时间drop呢？其次：我们在一个连接中，无法２次调用一个存储过程，他将告诉你临时表已经存在。可以做一个简单的例子：写一个带有临时表返回结果的存储过程，在调用存储存储过程的程序中，我们完全可以访问这个临时表。<br>简单例子：<br>存储过程<br>/**<br>* JDBC 存储过程 ADMINISTRATOR.P1<br>*/<br>import java.sql.*;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; // JDBC 类<br><br>public class P1<br>{<br>&nbsp; &nbsp; public static void p1 ( ResultSet[] rs ) throws SQLException, Exception<br>&nbsp; &nbsp; {<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;// 获取与数据库的连接<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;Connection con = DriverManager.getConnection("jdbc:default:connection");<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;PreparedStatement stmt = null;<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;String sql;<br><br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;sql = "declare global temporary table session.temp(cc char(5)) not logged";<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;stmt = con.prepareStatement( sql );<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;stmt.executeUpdate();<br><br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;sql = "insert into&nbsp;&nbsp;session.temp values ('1'),('2')";<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;stmt = con.prepareStatement( sql );<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;stmt.executeUpdate();<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;sql = "SELECT * from session.temp";<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;stmt = con.prepareStatement( sql );<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;rs[0] = stmt.executeQuery();<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;／／关闭连接（注意，这个地方在rs[0]为临时表的结果集返回的时候，stmt是无法关闭的，临时表是无法drop的，而con是可以关闭的，关闭后临时表还存在）<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;if (con != null) con.close();<br>&nbsp; &nbsp; }<br>}&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br><br>客户端调用我直接用命令行调用的。<br>db2 =&gt;; connect to sample<br><br>&nbsp; &nbsp;数据库连接信息<br><br>数据库服务器&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;= DB2/NT 7.2.1<br>SQL 授权标识&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;= ADMINIST...<br>本地数据库别名&nbsp; &nbsp;&nbsp; &nbsp; = SAMPLE<br>／／将自动提交设为false。<br>db2 =&gt;; update command options using c off<br>DB20000I&nbsp;&nbsp;UPDATE COMMAND OPTIONS 命令成功完成。<br><br>／／调用过程<br>db2 =&gt;; call p1()<br><br>CC<br>1<br>2<br><br>"P1" RETURN_STATUS："0"<br>／／看看存储过程中使用的临时表，数据是可以看到的。<br>db2 =&gt;; select *&nbsp;&nbsp;from session.temp<br><br>CC<br>-----<br>1<br>2<br><br>&nbsp;&nbsp;2 条记录已选择。<br>／／一个连接中再次调用，失败了<br>db2 =&gt;; call p1()<br>SQL0601N&nbsp;&nbsp;要创建的对象名与类型为"DECLARED TEMPORARY TABLE" 的现存名称 "SESSION.TEMP" 相同。&nbsp;&nbsp;SQLSTATE=42710<br>／／drop一下？ok，可以的<br>db2 =&gt;; drop table session.temp<br>DB20000I&nbsp;&nbsp;SQL 命令成功完成。<br>／／看看还有吗？没了！<br>db2 =&gt;; select *&nbsp;&nbsp;from session.temp<br>SQL0204N&nbsp;&nbsp;"SESSION.TEMP" 是未定义的名称。&nbsp;&nbsp;SQLSTATE=42704<br>／／再次调用，成功了<br>db2 =&gt;; call p1()<br><br>CC<br>1<br>2<br><br>"P1" RETURN_STATUS："0"<br><br><br>Ｃ、Websphere上的程序中使用系统临时表：因为websphere的连接使用连接池的技术，这带来了好处，但是同时也带来了一些让人容易误解的地方，我们在程序中要关闭连接，很多时候看上去是关闭了数据库的连接，事实上也是这样的，但是当websphere的连接数在websphere连接池规定的连接数的范围之内的时候，程序中关闭连接是不能直接关闭数据库的连接的，连接池使连接继续保持，这时候，我们的关闭连接释放的是该连接和相关因素在websphere和java程序中使用的资源，而该连接使用的数据库资源是无法得到释放的。也就是说，当我们在该连接上使用临时表的时候，我们在程序中关闭了连接，但是临时表是还存在的，连接池中把这个连接分配给其他程序使用的时候，其他程序还可以使用这个临时表，这并不是我们想要的。这要求我们在程序的中显式的drop掉临时表。（这是在南宁解决系统临时表使用问题中，碰到的一个问题，大家可以很容易的模拟出来）<br><br>同时这也让我们注意，一些设置，应该采取人为控制的方式，而不要采取默认，比如autoCommit，我们不能觉得程序结束了，就提交了，因为默认是程序结束提交的，如果错了就都回滚了，但是如果连接上设定的是autoCommit为true的话，程序出错就只能回滚你的出错前最后一次未提交事务，也许你还在为你程序中出现的这种错误头疼，他为什么前面的会提交呢？<br>一段代码，应尽可能的保持它的独立性，执行不要过多依赖于环境和其他的代码，我想这是应该考虑的。就象在oracle数据库上执行sql和在db2数据库上执行sql有很明显的区别一样，oracle默认是不提交的，而db2默认是提交的，这样在不主动控制事务的情况下，一个sql执行的结果是完全不同的。<br><br>2、数据存在周期<br>临时表的数据是在内存中的，当你向一个临时表插入数据的时候，他同时是直接的写到硬盘中的，如果你的缓冲池可以满足临时表的数据都存在内存中，它在使用的时候是不需要读硬盘上的数据的，除非你的缓冲池不能满足，这样会降低临时表的性能。我们知道，事务的提交和回滚是对数据库的更改做永久化，从内存中的更改到硬盘上的更改或者放弃更改（在更改实现的同时，是回收曾经占用的内存资源的）。对一个永久表，插入数据，就是在你提交之前，别的程序访问不了你插入的数据，在你提交之后，所有的程序都可以访问你插入的数据；而临时表不是这样的，无论执行提交还是回滚，临时表数据占用的内存资源都将被释放，同时临时表写到硬盘上的数据也全部删除。<br>也就是说，无论执行提交还是回滚，临时表的数据都没了，但是临时表还是存在的，这一点需要大家注意，在使用的过程中说插入了数据，但是没有数据，为什么呢？？<br>看一个简单的命令行模拟的例子：<br>db2 =&gt;; connect to sample<br><br>&nbsp; &nbsp;数据库连接信息<br><br>数据库服务器&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;= DB2/NT 7.2.1<br>SQL 授权标识&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;= ADMINIST...<br>本地数据库别名&nbsp; &nbsp;&nbsp; &nbsp; = SAMPLE<br>//创建临时表<br>db2 =&gt;; declare global temporary table session.test(col1 char(5)) not logged<br>DB20000I&nbsp;&nbsp;SQL 命令成功完成。<br>//插入数据<br>db2 =&gt;; insert into session.test values('5')<br>DB20000I&nbsp;&nbsp;SQL 命令成功完成。<br>//选择数据，没有数据？是的！<br>db2 =&gt;; select * from session.test<br><br>COL1<br>-----<br><br>&nbsp;&nbsp;0 条记录已选择。<br>//我们把提交方式改为默认不提交<br>db2 =&gt;; update command options using c off<br>DB20000I&nbsp;&nbsp;UPDATE COMMAND OPTIONS 命令成功完成。<br>//再次插入数据<br>db2 =&gt;; insert into session.test values('5')<br>DB20000I&nbsp;&nbsp;SQL 命令成功完成。<br>//选择数据，ok，我们看到数据了！<br>db2 =&gt;; select * from session.test<br><br>COL1<br>-----<br>5<br><br>&nbsp;&nbsp;1 条记录已选择。<br>//提交一下，或者执行rollback也可以&nbsp;&nbsp;<br>db2 =&gt;; commit<br>DB20000I&nbsp;&nbsp;SQL 命令成功完成。<br>//数据没了<br>db2 =&gt;; select * from session.test<br><br>COL1<br>-----<br><br>&nbsp;&nbsp;0 条记录已选择。<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>以上是系统临时表使用的过程中我们程序开发者需要注意的可能出现的问题，知道问题是怎么出现的，我们应该如何解决出现的问题和如何更好的使用临时表，这是我们的目标。
<img src ="http://www.cppblog.com/prayer/aggbug/115318.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-05-13 23:14 <a href="http://www.cppblog.com/prayer/archive/2010/05/13/115318.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WITH HOLD</title><link>http://www.cppblog.com/prayer/archive/2010/05/12/115235.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Wed, 12 May 2010 15:11:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/05/12/115235.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/115235.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/05/12/115235.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/115235.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/115235.html</trackback:ping><description><![CDATA[$declare &nbsp; aa_cur &nbsp; cursor &nbsp; with &nbsp; hold &nbsp; for &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select &nbsp; * &nbsp; into &nbsp; $table_aa &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; from &nbsp; t_aatable&nbsp;&nbsp;<br><br>WITH &nbsp; HOLD &nbsp; 声明该游标可以在创建它的事务成功提交后继续使用。 &nbsp; WITHOUT &nbsp; HOLD &nbsp; 声明该游标不能在创建它的的事务提交后使用。<br><br>缺省是 &nbsp; WITH&nbsp;&nbsp; HOLD ?!<br><br>DB2<br>
<p><strong>DECLARE CURSOR WITH HOLD 语句</strong></p>
<p>当用包括 WITH HOLD 子句的 DECLARE CURSOR 语句声明游标时，在落实该事务时任何打开的游标仍然打开；并且释放所有锁定，除保护打开的 WITH HOLD 游标的当前游标位置的锁定外。</p>
<p>如果回滚事务，则关闭所有打开的游标且释放所有锁定以及释放 LOB 定位器。</p>
<img src ="http://www.cppblog.com/prayer/aggbug/115235.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-05-12 23:11 <a href="http://www.cppblog.com/prayer/archive/2010/05/12/115235.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>事务--&lt;&lt;SQLu基础教程&gt;&gt;</title><link>http://www.cppblog.com/prayer/archive/2010/05/11/115151.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Tue, 11 May 2010 15:32:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/05/11/115151.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/115151.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/05/11/115151.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/115151.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/115151.html</trackback:ping><description><![CDATA[<p class=MsoNormal style="TEXT-INDENT: 0cm">务（transaction）是一个或多个接连在一起作为一个逻辑单位运行的SQL语句。DBMS认为事务是不可分割的，要么全部执行，要么全不执行。</p>
<p class=MsoNormal style="TEXT-INDENT: 19pt">用银行的例子来说明事务的重要性是很经典的。假定某个客户从他的储蓄账户向支票账户转账500美元。这个操作包括连续执行的两个独立步骤。</p>
<p class=MsoNormal style="TEXT-INDENT: 20pt">(1) 储蓄账户减500美元。</p>
<p class=MsoNormal style="TEXT-INDENT: 20pt">(2) 支票账户增500美元。</p>
<p class=MsoNormal style="TEXT-INDENT: 19pt">图14-1显示了这个事务的两条SQL语句。设想，如果DBMS在执行了第一条语句，但没有执行第二条时突然发生故障——断电、系统崩溃、硬件出问题，账户在神不知鬼不觉的情况下出现了不平衡。渎职控告和牢狱之灾就会接踵而至。</p>
<p class=af5 style="MARGIN-TOP: 10.35pt"><img height=128 src="http://book.csdn.net/BookFiles/1198/img/image009.jpg" width=240></p>
<p class=af0 style="MARGIN: 6.9pt 38pt 6.9pt 73.1pt; TEXT-INDENT: -35.1pt">图14-1　当银行客户从储蓄账户向支票账户转账时，必须有两条SQL语句</p>
<p class=MsoNormal style="TEXT-INDENT: 19pt">为了避免违法记录，应该使用事务来保证两条SQL语句都被执行，以维持账户平衡。如果事务中的一条语句无法执行时，DBMS将撤销（回滚）事务中其他语句。如果一切顺利，变化将被持久化（提交）。</p>
<p class=110 style="MARGIN: 6.9pt 0cm">执行事务</p>
<p class=MsoNormal style="TEXT-INDENT: 19pt">要了解事务如何工作，就要了解一些术语。</p>
<p class=MsoNormal style="TEXT-INDENT: 19pt">提交。提交（committing）事务是使自事务开始后修改的所有数据持久化在数据库中。在事务提交后，即使发生崩溃或其他故障，事务带来的所有变化仍然对其他用户可见并能够保证持久化。</p>
<p class=MsoNormal style="TEXT-INDENT: 19pt">回滚。回滚（rolling back）事务是撤销事务中SQL语句带来的所有变化。事务回滚后，此前影响到的数据回到原状，就好像SQL语句从未执行一样。</p>
<p class=MsoNormal style="TEXT-INDENT: 19pt">事务日志。事务日志文件（transaction logfile）或日志（log）是有关事务对数据库进行修改的一系列记录。事务日志记录了每个事务开始、数据的变化以及撤销或重新执行事务（如果将来需要）的足够信息。日志随着数据库事务的执行不断增长。</p>
<p class=MsoNormal style="TEXT-INDENT: 19.4pt">尽管保证每个事务本身的完整性是DBMS的职责，但依据组织或公司规章来开始和结束事务以保证数据逻辑的一致性则是数据库开发人员的责任。事务应该仅包含能做出一致修改的必要的SQL语句——不多不少。所有引用表中的数据在事务开始前和事务结束后必须保持一致。</p>
<p class=MsoNormal style="TEXT-INDENT: 19pt">在设计和执行事务时，要重点考虑以下方面。</p>
<p class=afb>l 事务相关的SQL语句会修改数据，所以执行事务要得到数据库管理员的授权。</p>
<p class=afb>l 事务过程应用于那些改变数据和数据库对象的语句（INSERT、UPDATE、DELETE、CREATE、ALTER、DROP——因不同DBMS而异）。对于工作中用到的数据库，每一条这样的语句都应该作为事务的一部分执行。</p>
<p class=afb>l 提交了的事务被称作持久化，意味着永久性改变，即便系统发生故障仍能保持。</p>
<p class=afb>l DBMS的数据恢复机制依赖于事务。当DBMS在故障之后被在线复原，DBMS检查事务日志确认是否所有事务都提交给了数据库。如发现没有提交（部分执行）的事务，依据日志将它们回滚。必须重新提交回滚的事务（尽管一些DBMS能够自动完成没有结束的事务）。</p>
<p class=afb>l DBMS的备份/恢复设备依赖于事务。备份设备获得例行的数据库快照并将它们和随后的事务日志存储在备份盘上。假定使用的硬盘发生故障使得数据和事务日志不可读。可以借助于恢复设备，它将采用最近的数据库备份并执行，或前滚所有从快照到故障前最后执行并在日志中提交的事务。这个恢复操作使数据库恢复到故障发生前的正确状态（注意，要再次提交没有提交的事务）。</p>
<p class=afb>l 显然，应该将数据库和它的事务日志存储于不同的物理硬盘。</p>
<div style="BORDER-RIGHT: silver 3pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: silver 3pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 8.5pt; BORDER-LEFT: silver 3pt solid; MARGIN-RIGHT: 8.5pt; PADDING-TOP: 1pt; BORDER-BOTTOM: silver 3pt solid">
<p class=afff0 style="BACKGROUND: silver; MARGIN: 11.75pt 0cm 0pt">并发控制</p>
</div>
<div style="BORDER-RIGHT: black 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: black 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: #e5e5e5; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 5.2pt; BORDER-LEFT: black 1pt solid; MARGIN-RIGHT: 5.2pt; PADDING-TOP: 1pt; BORDER-BOTTOM: black 1pt solid">
<p class=afff5 style="BACKGROUND: #e5e5e5; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 19pt">对人来说，计算机好像在同一时间运行着两个或更多进程。实际上，计算机操作并非同时发生，而是连续的。同时发生的印象是因为微处理器在人们难以察觉的很短的时间段内工作。在DBMS里，并发控制是在两个或更多用户同时访问或修改相同的数据时为防止数据失去完整性的一组策略 。</p>
<p class=afff5 style="BACKGROUND: #e5e5e5; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 19pt">DBMS使用锁定策略来保证事务完整性和数据库的一致性。在读写操作时，锁定限制数据的访问；于是，它阻止用户读那些正在被其他用户修改的数据，并防止多用户同时对同一数据修改。如果没有锁定，数据可能发生逻辑错误，针对这些数据执行的语句将返回不可预料的结果。偶尔会出现两个用户都锁定了对方事务所需的数据并尝试去得到对方的解锁，这时发生死锁问题。大多数DBMS能够侦测和解决死锁问题，通过回滚一个用户的事务让另一个事务可以运行（否则，两个用户都要永远等对方解锁）。锁定机制非常复杂，请查阅DBMS文档了解锁定。</p>
<p class=afff5 style="BACKGROUND: #e5e5e5; MARGIN: 0cm 0cm 9pt; TEXT-INDENT: 19pt">并发透明性是从事务的角度看数据库上运行唯一事务的现象。DBMS分离事务变化与任何其他并发事务的变化。当然，事务永远见不到数据的中间状态；或在其他并发事务之前访问，或在其他并发事务结束以后访问。分离的事务允许重载开始数据并再次执行（前滚）一系列事务来达到它们在最初的事务被执行之后的状态。</p>
</div>
<p class=MsoNormal style="TEXT-INDENT: 19pt">因为事务按照要么全部，要么全不方式被执行，事务的边界（开始点和结束点）必须清晰。边界使DBMS作为一个原子单元来执行这些语句。事务隐式开始于第一个可执行的SQL语句或显式使用 START TRANSACTION语句。事务显式结束于COMMIT或ROLLBACK语句（无法隐式结束），且无法在提交之后回滚事务。</p>
<p class=MsoNormal style="MARGIN-LEFT: 34.6pt; TEXT-INDENT: 0cm">
<table cellSpacing=0 cellPadding=0>
    <tbody>
        <tr>
            <td style="VERTICAL-ALIGN: top" width=15 height=18>
            <table cellSpacing=0 cellPadding=0 width="100%">
                <tbody>
                    <tr>
                        <td>
                        <div style="PADDING-RIGHT: 0pt; PADDING-LEFT: 0pt; PADDING-BOTTOM: 0pt; PADDING-TOP: 0pt">
                        <p class=afff1 style="LINE-HEIGHT: normal">q</p>
                        </div>
                        </td>
                    </tr>
                </tbody>
            </table>
            &nbsp;</td>
        </tr>
    </tbody>
</table>
<img height=27 src="http://book.csdn.net/BookFiles/1198/img/image001.jpg" width=44 align=left>Oracle和DB2的事务总是隐式开始，这些DBMS没有用来开始事务的语句。在Microsoft Access、Microsoft SQL Server、MySQL和PostgreSQL中，可以使用BEGIN语句显式开始事务。SQL:1999引入START TRANSACTION语句——由于这发生在DBMS使用BEGIN开始事务很久以后，因此不同DBMS扩展BEGIN的语法也各不相同。MySQL和PostgreSQL支持START TRANSACTION（作为BEGIN同义词）。</p>
<div style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0cm; BORDER-TOP: medium none; PADDING-LEFT: 0cm; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 20pt; BORDER-LEFT: medium none; MARGIN-RIGHT: 0cm; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1.5pt double">
<p class=af2 style="MARGIN: 2.75pt 0cm 2.75pt 3.95pt">&#254;&nbsp; 显式开始一个事务中</p>
</div>
<p class=MsoNormal style="TEXT-INDENT: 19pt">在Microsoft Access或Microsoft SQL Server中，输入：</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">BEGIN TRANSACTION;</p>
<p class=MsoNormal style="TEXT-INDENT: 19pt">或</p>
<p class=MsoNormal style="TEXT-INDENT: 19pt">在MySQL or PostgreSQL，输入：</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">START TRANSACTION;</p>
<div style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0cm; BORDER-TOP: medium none; PADDING-LEFT: 0cm; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 20pt; BORDER-LEFT: medium none; MARGIN-RIGHT: 0cm; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1.5pt double">
<p class=af2 style="MARGIN: 2.75pt 0cm 2.75pt 3.95pt">&#254;&nbsp; 提交事务中</p>
</div>
<p class=MsoNormal style="TEXT-INDENT: 19pt">输入：</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">COMMIT;</p>
<div style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0cm; BORDER-TOP: medium none; PADDING-LEFT: 0cm; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 20pt; BORDER-LEFT: medium none; MARGIN-RIGHT: 0cm; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1.5pt double">
<p class=af2 style="MARGIN: 2.75pt 0cm 2.75pt 3.95pt">&#254;&nbsp; 回滚事务中</p>
</div>
<p class=MsoNormal style="TEXT-INDENT: 19pt">输入：</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">ROLLBACK;</p>
<p class=MsoNormal style="TEXT-INDENT: 18.4pt">代码14-1中的SELECT语句显示UPDATE操作被DBMS执行后又被ROLLBACK语句取消。结果见图14-2。</p>
<p class=af5 style="MARGIN-TOP: 0cm"><img height=200 src="http://book.csdn.net/BookFiles/1198/img/image010.jpg" width=240></p>
<p class=MsoNormal style="TEXT-INDENT: 18.4pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 图14-2　运行代码14-1的结果。SELECT语<br>句的结果显示DBMS取消了操作</p>
<p class=af9 style="MARGIN: 6.9pt 2pt 4.15pt 52.2pt; TEXT-INDENT: -50.3pt">代码14-1　在一个事务内，更新操作（像插入和删除操作那样）永远不是在最后出现。结果见图14-2</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">SELECT SUM(pages), AVG(price) FROM titles;</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">BEGIN TRANSACTION;</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp; UPDATE titles SET pages = 0;</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp; UPDATE titles SET price = price * 2;</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp; SELECT SUM(pages), AVG(price) FROM titles;</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">ROLLBACK;</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">SELECT SUM(pages), AVG(price) FROM titles;</p>
<p class=MsoNormal style="TEXT-INDENT: 19pt">代码14-2显示更实用的事务例子。要从表publi- shers删除出版社P04而不产生引用完整性错误。因为表titles的有些外键值指向表publishers的出版社P04，所以要先删除表titles、titles_authors、和royalties中相关的行。应该使用事务保证所有DELETE语句都被执行。如果只有一些语句执行成功，数据将无法保持一致（要了解更多有关引用完整性检查的信息，参见11.7节）。</p>
<p class=af9 style="MARGIN: 6.9pt 2pt 4.15pt; TEXT-INDENT: 18pt">代码14-2　使用事务从表publishers中删除出版社P04，及删除其他表中与P04相关的行</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">BEGIN TRANSACTION;</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp; DELETE FROM title_authors</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp; WHERE title_id IN</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (SELECT title_id</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM titles</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE pub_id = 'P04');</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp; DELETE FROM royalties</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp; WHERE title_id IN</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (SELECT title_id</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM titles</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE pub_id = 'P04');</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp; DELETE FROM titles</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp; WHERE pub_id = 'P04';</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp; DELETE FROM publishers</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp; WHERE pub_id = 'P04';</p>
<p class=affd style="MARGIN-RIGHT: 0.5pt">COMMIT;</p>
<div style="BORDER-RIGHT: silver 3pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: silver 3pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 8.5pt; BORDER-LEFT: silver 3pt solid; MARGIN-RIGHT: 8.5pt; PADDING-TOP: 1pt; BORDER-BOTTOM: silver 3pt solid">
<p class=afff0 style="BACKGROUND: silver; MARGIN: 10.35pt 0cm 0pt">ACID</p>
</div>
<div style="BORDER-RIGHT: black 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: black 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: #e5e5e5; PADDING-BOTTOM: 1pt; MARGIN-LEFT: 5.2pt; BORDER-LEFT: black 1pt solid; MARGIN-RIGHT: 5.2pt; PADDING-TOP: 1pt; BORDER-BOTTOM: black 1pt solid">
<p class=afff5 style="BACKGROUND: #e5e5e5; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 19pt">ACID是首字母缩写，它概括了事务的特点：</p>
<p class=afff5 style="BACKGROUND: #e5e5e5; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 19pt">原子性（Atomicity）。要么事务中所有的数据修改都执行，要么都撤销。</p>
<p class=afff5 style="BACKGROUND: #e5e5e5; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 19pt">一致性（Consistency）。完全的事务应让数据保持一致来保证数据完整。一致状态要保证满足所有数据约束。（注意，并不要求在任何事务的中间点保持一致性）。</p>
<p class=afff5 style="BACKGROUND: #e5e5e5; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 19pt">隔离性（Isolation）。事务的影响独立（或隐藏）于其他事务，参见14.1节&#8220;并发控制&#8221;提要栏。</p>
<p class=afff5 style="BACKGROUND: #e5e5e5; MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 19pt">持久性（Durakility）。在事务完成后，它的影响是永久和持续的——即便是系统崩溃。</p>
<p class=afff5 style="BACKGROUND: #e5e5e5; MARGIN: 0cm 0cm 6.9pt; TEXT-INDENT: 12.15pt">事务理论是独立于关系模型的重大问题。由Jim Gray和Andreas Reuter所著的<em>Transaction Processing: Concepts and Techniques</em>（Morgan Kaufmann）是一本很好的参考书。</p>
</div>
<p class=4 style="MARGIN: 2.75pt 0cm"><sub>&#252;</sub>提示</p>
<p class=afb>l 不要忘记使用COMMIT或ROLLBACK显式结束事务。没有结束点将导致回滚的最后未提交事务巨大，可能带来意外的数据变化或程序异常中止。因为事务在生存期锁定行、整个表、索引和其他资源，所以要让事务尽可能小。COMMIT或ROLLBACK为其他事务释放资源。</p>
<p class=afb>l 可以嵌套事务。最大嵌套数因DBMS而异。</p>
<p class=MsoNormal style="TEXT-INDENT: 34.6pt">使用一条SET语句的UPDATE更新多个列比使用多个UPDATE快。例如，查询：</p>
<p class=affd style="TEXT-INDENT: 39.2pt; MARGIN-RIGHT: 0.5pt">UPDATE mytable</p>
<p class=affd style="TEXT-INDENT: 39.2pt; MARGIN-RIGHT: 0.5pt">&nbsp; SET col1 = 1</p>
<p class=affd style="TEXT-INDENT: 39.2pt; MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; col2 = 2</p>
<p class=affd style="TEXT-INDENT: 39.2pt; MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; col3 = 3</p>
<p class=affd style="TEXT-INDENT: 39.2pt; MARGIN-RIGHT: 0.5pt">&nbsp; WHERE col1 &lt;&gt; 1</p>
<p class=affd style="TEXT-INDENT: 39.2pt; MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp;&nbsp; OR col2 &lt;&gt; 2</p>
<p class=affd style="TEXT-INDENT: 39.2pt; MARGIN-RIGHT: 0.5pt">&nbsp;&nbsp;&nbsp;&nbsp; OR col3 &lt;&gt; 3;</p>
<p class=MsoNormal style="TEXT-INDENT: 34.6pt">比3个UPDATE语句好，因为它减少了日志记录（尽管带来锁定）。</p>
<p class=afb>l 默认情况下，DBMS运行在自动提交模式（autocommit mode），除非被其他显式或隐式事务重写（或被系统设置关闭）。在这种模式下，每一条语句作为一个事务执行。如果语句执行成功，DBMS就将它提交；如果DBMS遇到错误，就回滚这条语句。</p>
<p class=afb>l 对于长的事务，可以设置称为存储点（savepoints）的中间标志，将事务分割为小段。存储点允许回滚从事务当前点到事务靠前的时间点之间的变化（假定事务还没有提交）。如果在一系列复杂的插入、更新、删除操作未提交时，意识到最后的变化是不正确的或不必要的，使用存储点就可以避免重新提交所有语句。Microsoft Access不支持存储点。在Oracle、DB2、MySQL和PostgreSQL中，使用语句：</p>
<p class=affd style="TEXT-INDENT: 32.9pt; MARGIN-RIGHT: 0.5pt">SAVEPOINT <em>savepoint_name</em></p>
<p class=MsoNormal style="TEXT-INDENT: 33.8pt">对于Microsoft SQL Server，使用：</p>
<p class=affd style="TEXT-INDENT: 32.9pt; MARGIN-RIGHT: 0.5pt">SAVE TRANSACTION <em>savepoint_name</em>;</p>
<p class=MsoNormal style="TEXT-INDENT: 33.8pt">查阅DBMS文档来了解有关存储点锁定的细节知识及如何COMMIT或ROLLBACK到特定的存储点。</p>
<p class=MsoNormal style="MARGIN-LEFT: 34.6pt; TEXT-INDENT: 0cm"><img height=27 src="http://book.csdn.net/BookFiles/1198/img/image001.jpg" width=44 align=left>
<table cellSpacing=0 cellPadding=0>
    <tbody>
        <tr>
            <td style="VERTICAL-ALIGN: top" width=15 height=18>
            <table cellSpacing=0 cellPadding=0 width="100%">
                <tbody>
                    <tr>
                        <td>
                        <div style="PADDING-RIGHT: 0pt; PADDING-LEFT: 0pt; PADDING-BOTTOM: 0pt; PADDING-TOP: 0pt">
                        <p class=afff1 style="LINE-HEIGHT: normal">q</p>
                        </div>
                        </td>
                    </tr>
                </tbody>
            </table>
            &nbsp;</td>
        </tr>
    </tbody>
</table>
Microsoft Access中，通过SQL视图窗口或DAO无法执行事务，必须使用Microsoft Jet OLE DB Provider和ADO。</p>
<p class=MsoNormal style="MARGIN-LEFT: 34.55pt; TEXT-INDENT: -0.05pt">Oracle和DB2是隐式开始事务的。为了在Oracle 和 DB2中运行代码14-1和代码14-2，要删除语句：BEGIN TRANSACTION；</p>
<p class=MsoNormal style="MARGIN-LEFT: 34.55pt; TEXT-INDENT: -0.05pt">为了在MySQL中运行代码14-1和代码14-2，将语句BEGIN TRANSACTION;变为START TRANSACTION;（或BEGIN）。</p>
<p class=MsoNormal style="MARGIN-LEFT: 34.55pt; TEXT-INDENT: -0.05pt">MySQL通过InnoDB和BDB表支持事务，请查阅MySQL文档了解事务。Microsoft SQL Server、 Oracle、MySQL和PostgreSQL支持SET TRANSACTION语句设置事务特征。DB2通过服务器层和连接初始化设置控制事务特征。</p>
<img src ="http://www.cppblog.com/prayer/aggbug/115151.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-05-11 23:32 <a href="http://www.cppblog.com/prayer/archive/2010/05/11/115151.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MINUS EXCEPT</title><link>http://www.cppblog.com/prayer/archive/2010/04/21/113110.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Tue, 20 Apr 2010 16:13:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/04/21/113110.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/113110.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/04/21/113110.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/113110.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/113110.html</trackback:ping><description><![CDATA[在Oracle中使用<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">MINUS</strong>的地方，在<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">DB2</strong>中换成<a name=baidusnap2></a><strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">EXCEPT</strong>即可！<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">EXCEPT</strong>是SQL92中集合运算-差，<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">DB2</strong>采用SQL92中的表示，而ORACLE是自己的方言用的是<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">MINUS</strong>
<img src ="http://www.cppblog.com/prayer/aggbug/113110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-04-21 00:13 <a href="http://www.cppblog.com/prayer/archive/2010/04/21/113110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OLAP与OLTP的一些基础知识</title><link>http://www.cppblog.com/prayer/archive/2010/04/19/113025.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Mon, 19 Apr 2010 14:55:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/04/19/113025.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/113025.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/04/19/113025.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/113025.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/113025.html</trackback:ping><description><![CDATA[<div>
<p><span style="DISPLAY: block">　　OLTP：On_line Transaction Processing&nbsp; 联机事务处理</span> </p>
<p><span style="DISPLAY: block">　　OLAP：On_line Analytical Processing&nbsp;&nbsp; 联机分析处理</span> </p>
<p><span style="DISPLAY: block">　　OLTP顾名思义，以业务处理为主。OLAP则是专门为支持复杂的分析操作而设计的，侧重于对决策人员和高层管理人员的决策支持，可以应分析人员的要求快速、灵活地进行大数据量的复杂查询处理，并以一直直观的形式把查询结果提供。</span> </p>
<p><span style="DISPLAY: block">　　OLTP与OLAP 的主要区别有以下几点：</span> </p>
<p><span style="DISPLAY: block">&nbsp; （1）、所面向的用户和系统：OLTP是面向客户的，由职员或客户进行事务处理或者查询处理。OLAp是向向市场的，由经理、主管和分析人员进行数据分析和决策的。</span> </p>
<p><span style="DISPLAY: block">&nbsp; （2）、数据内容：OLTP系统管理当前数据，这些数据通常很琐碎，难以用于决策。OLAP系统管理大量历史数据，提供汇总和聚集机制，并在不同的粒度级别上存储和管理信息，这些特点使得数据适合于决策分析。</span> </p>
<p><span style="DISPLAY: block">&nbsp; （3）、数据库设计：通常，OLTP采用ER模型和面向应用的数据库设计，而OLAP系统通常采用星型模式或雪花模式和面向主题的数据库设计。</span> </p>
<p><span style="DISPLAY: block">&nbsp; （4）、视图：OLTP系统主要关注一个企业或部门的当前数据，而不涉及历史数据或不同组织的数据。与之相反，OLAP系统常常跨越一个企业的数据库模式的多个版本，OLAP系统也处理来自不同组织的信息，由多个数据源集成的信息。</span> </p>
<p><span style="DISPLAY: block">&nbsp; （5）、访问模式：OLTP系统的访问主要由短的原子事务组成，这种系统需要并发控制和恢复机制。而OLAP系统的访问大部份是只读操作，其中大部份是复杂查询。</span> </p>
<p><span style="DISPLAY: block">&nbsp; （6）、度量：OLTP专注于日常时实操作，所以以事务吞吐量为度量，OLAP以查询吞吐量和响应时间来度量。</span> </p>
<p><span style="DISPLAY: block">以上初步辨识了这二个概念，以后对于满嘴跑概念的人可以略有防范。</span> </p>
</div>
<img src ="http://www.cppblog.com/prayer/aggbug/113025.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-04-19 22:55 <a href="http://www.cppblog.com/prayer/archive/2010/04/19/113025.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分区表</title><link>http://www.cppblog.com/prayer/archive/2010/04/15/112724.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Thu, 15 Apr 2010 15:25:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/04/15/112724.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/112724.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/04/15/112724.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/112724.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/112724.html</trackback:ping><description><![CDATA[　分区表是将大表的数据分成称为分区的许多小的子集。<br><br>　　9i提供四种分区方法：范围分区，列表分区，哈希分区和混合分区；<br>
<div class=spctrl></div>
　　&#183; 范围分区是根椐分区键的不同取值范围来划分子集的，关键字RANGE， VALUES LESS THAN；<br>
<div class=spctrl></div>
　　&#183; 列表分区是根椐分区键的一些离散的取值来划分子集的，关键字LIST， VALUES；<br>
<div class=spctrl></div>
　　&#183; 哈希分区是应用哈希算法将分区键对应到某个子集中去，关键字HASH， PARTITIONS；<br>
<div class=spctrl></div>
　　&#183; 混合分区只能有两层，第一层是范围分区，第二层可以是列表分区或者哈希分区；<br>
<div class=spctrl></div>
　　&#183; 范围分区和列表分区中，如果插入记录的分区键没有对应的容纳分区，会产生ORA-14400；<br>
<div class=spctrl></div>
　　&#183; update操作如果会使记录从一个分区迁移到另一个分区，且分区表的ROW MOVEMENT属性是DISABLE，会产ORA-14402；<br>
<div class=spctrl></div>
　　&#183; 分区表上的索引有两大类：普通的二叉树索引，分区索引，下面讲到的都是分区索引：<br>
<div class=spctrl></div>
　　&#183; 按索引分区和表分区间的对应关系可以分为局部索引和全局索引；<br>
<div class=spctrl></div>
　　&amp;Oslash; 局部索引的索引分区和表分区间是一一对应的，全局索引则相反；<br>
<div class=spctrl></div>
　　&amp;Oslash; 局部索引的分区方法可以用上面提到四种的任何一种，全局索引的分区方法只有范围分区（而且最高的分区必须用MAXVALUE来定义）；<br>
<div class=spctrl></div>
　　&amp;Oslash; ORACLE自动维护局部索引的分区，当表分区被合并，分裂或删除时，关联的索引分区也会被合并，分裂或删除；对分区表执行管理操作时会使其上的全局索引失效；<br>
<div class=spctrl></div>
　　&amp;Oslash; 建在分区表的位图索引必须是局部分区索引；<br>
<div class=spctrl></div>
　　&amp;Oslash; ORACLE推荐尽可能地使用局部索引；<br>
<div class=spctrl></div>
　　&#183; 按索引栏位和分区键间的关系分为前缀索引和非前缀索引；<br>
<div class=spctrl></div>
　　&amp;Oslash; 前缀索引最前面的栏位是分区键栏位，非前缀索引相反；<br>
<div class=spctrl></div>
　　&#183; 在这两种分类方法的四种组合中，只有三种有效（局部前缀索引，局部非前缀索引，全局前缀索引），不存在全局非前缀索引；<br>
<div class=spctrl></div>
　　&#183; 分区表给CBO带来很多选项，如分区排除，并行分区连接等。<br>
<div class=spctrl></div>
　　一个硬盘经过FDISK的划分和高级格式化以后，会在所属的操作系统中建立分区表，记录一些有关硬盘给哪一种操作系统使用，硬盘的容量大小以及开始磁柱面和结束磁柱面的分配，哪一个硬盘启动，<a href="http://baike.baidu.com/view/1214514.htm" target=_blank><u><font color=#0000ff>引导区</font></u></a>（Boot Sector），文件分配表（FAT）、根目录和数据区等一系列数据。现将分区表内的内容归纳如下： <br>
<div class=spctrl></div>
　　A、分区表是创建在硬盘的第0磁柱面、第0磁道，第1个扇区上。 <br>
<div class=spctrl></div>
　　B、记录操作系统的数据（DOS，OS2或其他OS）。 <br>
<div class=spctrl></div>
　　C、记录分区硬盘的C（磁柱面）、H（磁头），S（扇区）的数量。 <br>
<div class=spctrl></div>
　　D、记录分配的磁柱面（Cylinder）的开始。结束和容量。 <br>
<div class=spctrl></div>
　　E、记录可启动的硬盘（Active）。 <br>
<div class=spctrl></div>
　　F、建立引导区（Boot Sector）。 <br>
<div class=spctrl></div>
　　G、建立文件分配表（FAT）。 <br>
<div class=spctrl></div>
　　H、建立根目录。 <br>
<div class=spctrl></div>
　　I、建立数据存储区。
<img src ="http://www.cppblog.com/prayer/aggbug/112724.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-04-15 23:25 <a href="http://www.cppblog.com/prayer/archive/2010/04/15/112724.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>with check option </title><link>http://www.cppblog.com/prayer/archive/2010/04/13/112515.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Tue, 13 Apr 2010 15:43:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/04/13/112515.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/112515.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/04/13/112515.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/112515.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/112515.html</trackback:ping><description><![CDATA[<p>我们来看下面的例子：<br>create or replace view testview<br>as<br>select empno,ename from emp where ename like &#8216;M%&#8217;<br>with check option;</p>
<p>这里我们创建了一个视图，并使用了with check option来限制了视图。 然后我们来看一下视图包含的结果：<br>select * from testview得到：<br>EMPNO ENAME<br>———- ———&#8211;<br>7654 MARTIN<br>7934 MILLER<br>这两条记录</p>
<p>然后我们在试图将其中一条更新：<br>update testview<br>set ename = &#8216;Mike&#8217;<br>where empno = 7654;<br>OK,这条更新语句可以执行，并没有什么问题，但是当我们执行另一条更新时：<br>update testview<br>set ename = &#8216;Robin&#8217;<br>where empno = &#8216;7654&#8242;;<br>就会出现ORA-01402: 视图 WITH CHECK OPTIDN 违反 where 子句的错误，这是因为什么呢？</p>
<p>这是因为前面我们在创建视图时指定了witch check option关键字，这也就是说，更新后的每一条数据仍然要满足创建视图时指定的where条件，所以我们这里发生了错误ORA-01402。</p>
<p>但是需要说明的时 ，虽然指定了with check option，我们还是可以删除视图中的数据。例如上例中，我们可以使用<br>delete from test where where empno =&nbsp;&nbsp; 7654</p>
<p><br>--------------------------------------------------------------------------------</p>
<p>我创建一个视图：&nbsp;&nbsp; <br>&nbsp; create&nbsp;&nbsp; view&nbsp;&nbsp; IS_student&nbsp;&nbsp; <br>&nbsp; as&nbsp;&nbsp; <br>&nbsp; select&nbsp;&nbsp; sno,sname,sage&nbsp;&nbsp; <br>&nbsp; from&nbsp;&nbsp; student&nbsp;&nbsp; <br>&nbsp; where&nbsp;&nbsp; sdept='IS'&nbsp;&nbsp; <br>&nbsp; with&nbsp;&nbsp; check&nbsp;&nbsp; option;&nbsp;&nbsp; <br>&nbsp; 加上了with&nbsp;&nbsp; check&nbsp;&nbsp; option;后，不能执行插入操作：&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; <br>&nbsp; insert&nbsp;&nbsp; into&nbsp;&nbsp; is_student&nbsp;&nbsp; <br>&nbsp; values('95100','李娜',12)&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; <br>&nbsp; 什么原因？不加上with&nbsp;&nbsp; check&nbsp;&nbsp; option则可以！&nbsp;&nbsp; <br>&nbsp;<br>with&nbsp;&nbsp; check&nbsp;&nbsp; option可以这么解释：通过视图进行的修改，必须也能通过该视图看到修改后的结果。比如你insert，那么加的这条记录在刷新视图后必须可以看到；如果修改，修改完的结果也必须能通过该视图看到；如果删除，当然只能删除视图里有显示的记录。&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; <br>&nbsp; ---&gt;而你只是查询出sdept='is'的纪录，你插入的根本不符合sdept='is'呀，所以就不行<br>&nbsp;<br>默认情况下，由于行通过视图进行添加或更新，当其不再符合定义视图的查询的条件时，它们即从视图范围中消失。例如，可创建一个查询，从而定义一个视图以在表中检索所有员工薪水低于&nbsp;&nbsp; $30,000&nbsp;&nbsp; 的行。如果该员工的薪水涨到了&nbsp;&nbsp; $32,000，则查询视图时该特定员工将不再出现，因其薪水不符合视图所设的标准。但是，WITH&nbsp;&nbsp; CHECK&nbsp;&nbsp; OPTION&nbsp;&nbsp; 子句强制所有数据修改语句均根据视图执行，以符合定义视图的&nbsp;&nbsp; SELECT&nbsp;&nbsp; 语句中所设的条件。如果使用该子句，修改行时需考虑到不让它在修改完后从视图中消失。任何可能导致行消失的修改都会被取消，并显示错误信息。&nbsp;&nbsp; </p>
<p><br>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/hippoppower/archive/2009/09/03/4516733.aspx">http://blog.csdn.net/hippoppower/archive/2009/09/03/4516733.aspx</a></p>
 <img src ="http://www.cppblog.com/prayer/aggbug/112515.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-04-13 23:43 <a href="http://www.cppblog.com/prayer/archive/2010/04/13/112515.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>char varchar varchar2 的区别</title><link>http://www.cppblog.com/prayer/archive/2010/04/13/112508.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Tue, 13 Apr 2010 13:45:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/04/13/112508.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/112508.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/04/13/112508.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/112508.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/112508.html</trackback:ping><description><![CDATA[区别： <br>&nbsp; 1．CHAR的长度是固定的，而VARCHAR2的长度是可以变化的， 比如，存储字符串&#8220;abc"，对于CHAR (20)，表示你存储的字符将占20个字节(包括17个空字符)，而同样的VARCHAR2 (20)则只占用3个字节的长度，20只是最大值，当你存储的字符小于20时，按实际长度存储。 <br>&nbsp; 2．CHAR的效率比VARCHAR2的效率稍高。 <br>&nbsp; 3．目前VARCHAR是VARCHAR2的同义词。工业标准的VARCHAR类型可以存储空字符串，但是oracle不这样做，尽管它保留以后这样做的权利。Oracle自己开发了一个数据类型VARCHAR2，这个类型不是一个标准的VARCHAR，它将在数据库中varchar列可以存储空字符串的特性改为存储NULL值。如果你想有向后兼容的能力，Oracle建议使用VARCHAR2而不是VARCHAR。 <br>&nbsp; 何时该用CHAR，何时该用varchar2？ <br>&nbsp; CHAR与VARCHAR2是一对矛盾的统一体，两者是互补的关系. <br>&nbsp; VARCHAR2比CHAR节省空间，在效率上比CHAR会稍微差一些，即要想获得效率，就必须牺牲一定的空间，这也就是我们在数据库设计上常说的&#8216;以空间换效率&#8217;。 <br>&nbsp; VARCHAR2虽然比CHAR节省空间，但是如果一个VARCHAR2列经常被修改，而且每次被修改的数据的长度不同，这会引起&#8216;行迁移&#8217;(Row Migration)现象，而这造成多余的I/O，是数据库设计和调整中要尽力避免的，在这种情况下用CHAR代替VARCHAR2会更好一些。 
 <img src ="http://www.cppblog.com/prayer/aggbug/112508.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-04-13 21:45 <a href="http://www.cppblog.com/prayer/archive/2010/04/13/112508.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL游标的原理与遍历 </title><link>http://www.cppblog.com/prayer/archive/2010/03/18/109949.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Wed, 17 Mar 2010 16:05:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/03/18/109949.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/109949.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/03/18/109949.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/109949.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/109949.html</trackback:ping><description><![CDATA[<div><font color=#6a5acd size=2>作者：熔岩</font></div>
<div><font color=#6a5acd size=2>日期：2006-12-26</font></div>
<div><font color=#6a5acd size=2>天气：大雾</font></div>
<div><font color=#6a5acd size=2>声明：原创作品，未经授权，拒绝转载！</font></div>
<div><font color=#0000ff size=4><strong></strong></font>&nbsp;</div>
<div><font color=#0000ff size=4><strong>游标的原理</strong></font></div>
<div><font size=2></font>&nbsp;</div>
<div><font size=2>&nbsp;&nbsp;&nbsp; 一般情况下，SQL查询结果都是多条纪录的结果集，而高级语言一次只能处理一条纪录，用游标机制，将多条纪录一次一条读取出来处理。从而把对集合的操作转化为对单个纪录的处理。游标使用的步骤如下：<br></font></div>
<div><font size=2><font color=#ff1493>1、说明游标。</font>说明游标的时候并不执行select语句。<br>&nbsp;declare &lt;游标名&gt; cursor for &lt;select语句&gt;;</font></div>
<div><font size=2></font>&nbsp;</div>
<div><font size=2><font color=#ff1493>2、打开游标。</font>打开游标实际上是执行相应的select语句，把查询结果读取到缓冲区中。这时候游标处于活动状态，指针指向查询结果集的第一条纪录。<br>&nbsp;open &lt;游标名&gt;;</font></div>
<div><font size=2></font>&nbsp;</div>
<div><font size=2><font color=#ff1493>3、推进游标指针并读取当前纪录。</font>用fetch语句把游标指针向前推进一条纪录，同时将缓冲区中的当前纪录读取出来送到变量中。fetch语句通常用在一个循环结构体中，通过循环执行fetch语句逐条取出结果集中的行进行处理。现在好多数据库中，还允许任意方向任意步长易懂游标指针，而不仅仅是把游标指针向前推进一行了。<br>&nbsp;fetch &lt;游标名&gt; into &lt;变量1&gt;,&lt;变量2&gt;...</font></div>
<div><font size=2></font>&nbsp;</div>
<div><font size=2><font color=#ff1493>4、关闭游标。</font>用close语句关闭游标，释放结果集占用的缓冲区及其他资源。游标关闭后，就不再和原来的查询结果集相联系。但游标可以再次打开，与新的查询结果相联系。<br>&nbsp;close &lt;游标名&gt;;</font></div>
<div>&nbsp;</div>
<div><font color=#0000ff size=4><strong>DB2游标的循环控制</strong></font></div>
<div><strong><font color=#0000ff size=4></font></strong>&nbsp;</div>
<div><font size=2>&nbsp;&nbsp;&nbsp; DB2下游标控制不是非常的轻松和方便的，也可以使用sqlcode,sqlstate来控制，或者用户自己控制，DB2下SQLCODE,SQLSTATE不能直接使用，必须声明后使用，（也就是说将系统的SQLCODE,SQLSTATE本地实例化一分拷贝）。一般采用用户定义游标开关和sqlcode返回信息一起共同控制的方法.</font></div>
<img src ="http://www.cppblog.com/prayer/aggbug/109949.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-03-18 00:05 <a href="http://www.cppblog.com/prayer/archive/2010/03/18/109949.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>PL/SQL的SELECT FOR UPDATE游标</title><link>http://www.cppblog.com/prayer/archive/2010/03/17/109942.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Wed, 17 Mar 2010 15:51:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/03/17/109942.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/109942.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/03/17/109942.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/109942.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/109942.html</trackback:ping><description><![CDATA[在多数情况下，提取循环中所完成的处理都会修改由游标检查出的行，PL/SQL提供了进行这样处理的一种语法。 <br>这种语法包括两部分——在游标声明部分的FOR&nbsp;UPDATE子句和在UPDATE或DELETE语句中的WHERE&nbsp;CURRENT&nbsp;OF&nbsp;子句。 <br>通常，SELECT操作将不会对正处理的行执行任何锁定设置，这使得连接到该数据库的其他会话可以改变正在选择的数据。 <br>但是，结果集仍然是一致性的。当确定了活动集以后，在执行OPEN的时刻，ORACLE会截取下该表的一个快照。在此时刻以前所提交的任何更改操作都会在活动集中反映出来。在此时刻以后所进行的任何更改操作，即使已经提交了它们，都不会被反映出来，除非将该游标重新打开。但是使用FOR&nbsp;UPDATE子句，在OPEN返回以前的活动集的相应行上会加上互斥锁，这些锁会避免其他的会话对活动集中的行进行更改。直到整个事务被提交为止。 <br><br>示例： <br>DECLARE <br>CURSOR&nbsp;C_CUR&nbsp;IS&nbsp;SELECT&nbsp;*&nbsp;FROM&nbsp;STUDENDS&nbsp;FOR&nbsp;UPDATE&nbsp;OF&nbsp;XM; <br>BEGIN <br>OPEN&nbsp;C_CUR; <br>WHILE&nbsp;C_CUR%FOUND&nbsp;LOOP <br><br>UPDATE&nbsp;STUDENDS&nbsp;SET&nbsp;XM='AA'||XM&nbsp;WHERE&nbsp;CURRENT&nbsp;OF&nbsp;C_CUR; <br><br>END&nbsp;LOOP; <br>CLOSE&nbsp;C_CUR; <br>COMMIT; <br>END; <br><br><br>需要注意的是：1、UPDATE语句仅更新在游标声明的FOR&nbsp;UPDATE子句处列出的列。如果没有列出任何列，那么所有的列都可以更新。 <br>2、示例中的COMMIT是在提取循环完成以后才完成的，因为COMMIT将释放由该会话持有的所有锁。因为FOR&nbsp;UPDATE子句获得了锁，所以COMMIT将释放这些锁。当锁释放了，该游标就无效了。所以后继的提取操作都将返回ORACLE错误。<br>
<img src ="http://www.cppblog.com/prayer/aggbug/109942.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-03-17 23:51 <a href="http://www.cppblog.com/prayer/archive/2010/03/17/109942.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>where current of</title><link>http://www.cppblog.com/prayer/archive/2010/03/17/109941.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Wed, 17 Mar 2010 15:51:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/03/17/109941.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/109941.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/03/17/109941.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/109941.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/109941.html</trackback:ping><description><![CDATA[<strong>　UPDATE或DELETE语句中的WHERE CURRENT OF子串专门处理要执行UPDATE或DELETE操作的表中取出的最近的数据。要使用这个方法，在声明游标时必须使用FOR UPDATE子串，当对话使用FOR UPDATE子串打开一个游标时，所有返回集中的数据行都将处于行级（ROW-LEVEL）独占式锁定，其他对象只能查询这些数据行，不能进行UPDATE、DELETE或SELECT...FOR UPDATE操作。</strong>
<img src ="http://www.cppblog.com/prayer/aggbug/109941.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-03-17 23:51 <a href="http://www.cppblog.com/prayer/archive/2010/03/17/109941.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle中如何掌握与使用游标</title><link>http://www.cppblog.com/prayer/archive/2010/03/17/109940.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Wed, 17 Mar 2010 15:50:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/03/17/109940.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/109940.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/03/17/109940.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/109940.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/109940.html</trackback:ping><description><![CDATA[<p>　1 游标的属性</p>
<p>　　oracle 游标有4个属性：%ISOPEN，%FOUND，%NOTFOUND，%ROWCOUNT。</p>
<p><br>　　%ISOPEN判断游标是否被打开，如果打开%ISOPEN等于true,否则等于false；</p>
<p><br>　　%FOUND %NOTFOUND判断游标所在的行是否有效，如果有效，则%FOUNDD等于true，否则等于false；</p>
<p><br>　　%ROWCOUNT返回当前位置为止游标读取的记录行数。</p>
<p><br>　　隐式游标和显式游标</p>
<p><br>　　隐式游标 <br>&nbsp;<br>　　显式游标 <br>&nbsp;</p>
<p>PL/SQL维护，当执行查询时自动打开和关闭 <br>&nbsp;<br>在程序中显式定义、打开、关闭，游标有一个名字。 <br>&nbsp;</p>
<p>游标属性前缀是SQL <br>&nbsp;<br>游标属性的前缀是游标名 <br>&nbsp;</p>
<p>属性%ISOPEN总是为FALSE <br>&nbsp;<br>%ISOPEN根据游标的状态确定值 <br>&nbsp;</p>
<p>SELECT语句带有INTO子串，只有一行数据被处理 <br>&nbsp;<br>可以处理多行数据，在程序中设置循环，取出每一行数据。 <br>&nbsp;</p>
<p>&nbsp;　　记录变量 </p>
<p><br>　　定义一个记录变量使用TYPE命令和%ROWTYPE，</p>
<p>DECLARER_emp EMP%ROWTYPE;CURSOR c_emp IS SELECT * FROM emp;</p>
<p><br>　　或：</p>
<p>DECLARECURSOR c_emp IS SELECT ename,salary FROM emp;R_emp c_emp%ROWTYPE;</p>
<p><br>　　带参数的游标 </p>
<p><br>　　与存储过程和函数相似，可以将参数传递给游标并在查询中使用。这对于处理在某种条件下打开游标的情况非常有用。它的语法如下：</p>
<p><br>　　CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;</p>
<p><br>　　定义参数的语法如下：</p>
<p><br>　　Parameter_name [IN] data_type[{:=|DEFAULT} value]</p>
<p><br>　　与存储过程不同的是，游标只能接受传递的值，而不能返回值。参数只定义数据类型，没有大小。　　<br>　　<br>　　另外可以给参数设定一个缺省值，当没有参数值传递给游标时，就使用缺省值。游标中定义的参数只是一个占位符，在别处引用该参数不一定可靠。<br>　　<br>　　在打开游标时给参数赋值，语法如下：</p>
<p><br>　　OPEN cursor_name[value[,value]....]; </p>
<p><br>　　游标FOR循环 </p>
<p><br>　　FOR循环的游标按照正常的声明方式声明，它的优点在于不需要显式的打开、关闭、取数据，测试数据的存在、定义存放数据的变量等等。游标FOR 循环的语法如下：</p>
<p>FOR record_name IN(corsor_name[(parameter[,parameter]...)]| (query_difinition)LOOPstatementsEND LOOP;</p>
<p>&nbsp;<br>　　2 游标的更新和删除</p>
<p>　　在PL/SQL中依然可以使用UPDATE和DELETE语句更新或删除数据行。显式游标只有在需要获得多行数据的情况下使用。PL/SQL提供了仅仅使用游标就可以执行删除或更新记录的方法。</p>
<p><br>　<strong>　UPDATE或DELETE语句中的WHERE CURRENT OF子串专门处理要执行UPDATE或DELETE操作的表中取出的最近的数据。要使用这个方法，在声明游标时必须使用FOR UPDATE子串，当对话使用FOR UPDATE子串打开一个游标时，所有返回集中的数据行都将处于行级（ROW-LEVEL）独占式锁定，其他对象只能查询这些数据行，不能进行UPDATE、DELETE或SELECT...FOR UPDATE操作。</strong></p>
<p><br>　　语法：</p>
<p><br>　　FOR UPDATE [OF [schema.]table.column[,[schema.]table.column]..<br>[nowait]</p>
<p><br>　　在多表查询中，使用OF子句来锁定特定的表,如果忽略了OF子句，那么所有表中选择的数据行都将被锁定。如果这些数据行已经被其他会话锁定，那么正常情况下ORACLE将等待，直到数据行解锁。</p>
<p><br>　　在UPDATE和DELETE中使用WHERE CURRENT OF子串的语法如下：</p>
<p><br>　　WHERE{CURRENT OF cursor_name|search_condition}</p>
<p><br>　　例： <br>DELCARECURSOR c1 IS SELECT empno,salaryFROM empWHERE comm IS NULLFOR UPDATE OF comm;v_comm NUMBER(10,2);BEGINFOR r1 IN c1 LOOPIF r1.salary&lt;500 THENv_comm:=r1.salary*0.25;ELSEIF r1.salary&lt;1000 THENv_comm:=r1.salary*0.20;ELSEIF r1.salary&lt;3000 THENv_comm:=r1.salary*0.15;ELSEv_comm:=r1.salary*0.12;END IF;UPDATE emp;SET comm=v_commWHERE CURRENT OF c1l;END </p>
<p><br>本篇文章来源于 IT中国 转载请以链接形式注明出处 网址：<a href="http://www.it86.cc/oracle/2008/0410/30076.shtml">http://www.it86.cc/oracle/2008/0410/30076.shtml</a></p>
<img src ="http://www.cppblog.com/prayer/aggbug/109940.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-03-17 23:50 <a href="http://www.cppblog.com/prayer/archive/2010/03/17/109940.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Select For Update行级锁定</title><link>http://www.cppblog.com/prayer/archive/2010/03/17/109939.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Wed, 17 Mar 2010 15:42:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/03/17/109939.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/109939.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/03/17/109939.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/109939.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/109939.html</trackback:ping><description><![CDATA[<span style="FONT-FAMILY: Courier New"></span><span style="FONT-FAMILY: Courier New"><a onclick="javascript:tagshow(event, 'Oracle');" href="javascript:;" target=_self><u><strong><font color=#0000ff>Oracle</font></strong></u></a>的<a onclick="javascript:tagshow(event, 'Select');" href="javascript:;" target=_self><u><strong><font color=#0000ff>Select</font></strong></u></a> <a onclick="javascript:tagshow(event, 'For');" href="javascript:;" target=_self><u><strong><font color=#0000ff>For</font></strong></u></a> <a onclick="javascript:tagshow(event, 'Update');" href="javascript:;" target=_self><u><strong><font color=#0000ff>Update</font></strong></u></a>语句可以实现在读取数据后马上锁定相关资源，防止被其他session修改数据的目的。也就是我们常常谈到的&#8220;悲观锁定&#8221;（现实应用开发中，使用悲观锁定的情况少之又少，也许是因为乐观锁定的实现更加灵活和便捷的缘故）。</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">这个小文儿做一个小小的<a onclick="javascript:tagshow(event, '%CA%B5%D1%E9');" href="javascript:;" target=_self><u><strong><font color=#0000ff>实验</font></strong></u></a>，来看看Select For Update语句实现的<a onclick="javascript:tagshow(event, '%D0%D0%BC%B6%CB%F8%B6%A8');" href="javascript:;" target=_self><u><strong><font color=#0000ff>行级锁定</font></strong></u></a></span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">1.创建实验表table_sfu，并初始化三条数据</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; create table table_sfu (a number);</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">Table created.</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; insert into table_sfu values (1);</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">1 row created.</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; insert into table_sfu values (2);</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">1 row created.</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; insert into table_sfu values (3);</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">1 row created.</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; commit;</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">Commit complete.</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; select * from table_sfu;</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">----------</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">2.使用Select For Update语句得到第一条数据</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; select * from table_sfu where a = 1 for update;</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">----------</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">3.查看一下现在系统中的锁定情况，152会话（即上面语句所在的会话）获得了一个TX锁和一个TM锁了，锁定的表就是TABLE_SFU</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; @lock</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">lock&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">holder&nbsp;&nbsp;&nbsp; holder&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock request&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blocked</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">username&nbsp; sessid SERIAL# type&nbsp;&nbsp;&nbsp; id1&nbsp; id2 mode&nbsp;&nbsp;&nbsp; mode BLOCK&nbsp; sessid</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">-------- ------- ------- ---- ------ ---- ---- ------- ----- -------</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">SEC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 152&nbsp;&nbsp; 14985 TM&nbsp;&nbsp;&nbsp; 15396&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">SEC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 152&nbsp;&nbsp; 14985 TX&nbsp;&nbsp; 327722 1790&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 164&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 TS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 165&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 CF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 165&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 RS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 25&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 165&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 XR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 166&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 RT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">7 rows selected.</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; col OWNER for a6</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; col OBJECT_NAME for a10</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; select OWNER,OBJECT_NAME,OBJECT_ID,OBJECT_TYPE from dba_objects where object_id = '15396';</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">OWNER&nbsp; OBJECT_NAM&nbsp; OBJECT_ID OBJECT_TYPE</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">------ ---------- ---------- -------------------</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">SEC&nbsp;&nbsp;&nbsp; TABLE_SFU&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 15396 TABLE</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">4.另外新打开一个session，执行以下修改任务</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; update table_sfu set a = 100 where a = 1;</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">OK，效果出现了，这里出现了&#8220;锁等待&#8221;现象，原因就是因为在第一个session中使用Select For Update语句锁定了第一行数据，不允许其他的session对它修改。</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">5.这时系统中锁定情况如下，可以看到第一个session（session id是152）会话锁定了第二个session（session id是145）会话的事务</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; @lock</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">lock&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">holder&nbsp;&nbsp;&nbsp; holder&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock request&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blocked</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">username&nbsp; sessid SERIAL# type&nbsp;&nbsp;&nbsp; id1&nbsp; id2 mode&nbsp;&nbsp;&nbsp; mode BLOCK&nbsp; sessid</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">-------- ------- ------- ---- ------ ---- ---- ------- ----- -------</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">SEC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 145&nbsp;&nbsp; 11388 TM&nbsp;&nbsp;&nbsp; 15396&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">SEC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 152&nbsp;&nbsp; 14985 TM&nbsp;&nbsp;&nbsp; 15396&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">SEC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 152&nbsp;&nbsp; 14985 TX&nbsp;&nbsp; 327722 1790&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; 145</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 164&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 TS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 165&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 CF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 165&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 RS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 25&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 165&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 XR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 166&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 RT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; 0</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">8 rows selected.</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">6.因为仅仅是锁定了第一条数据，所以其他记录可以顺利的进行修改，如下</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; update table_sfu set a = 200 where a = 2;</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">1 row updated.</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; commit;</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">Commit complete.</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">7.解锁方式：commit或rollback后即完成锁定的接触</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">8.反过来思考一下，如果Select For Update与要锁定的行已经在其他session中完成了修改，再执行回出现什么效果呢？这个很显然，同样的会出现&#8220;锁等待&#8221;的现象，不过我想强调的是，这里可以使用nowait和wait选项来进行&#8220;探测&#8221;待锁定行是否可被锁定</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">实验效果如下：</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">第一个session：</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; update table_sfu set a = 100 where a = 1;</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">1 row updated.</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">第二个session：</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; select * from table_sfu where a = 1 for update;</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">此处是&#8220;锁等待&#8221;效果</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; select * from table_sfu where a = 1 for update nowait;</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">select * from table_sfu where a = 1 for update nowait</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">ERROR at line 1:</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">ORA-00054: resource busy and acquire with NOWAIT specified</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">这里提示了错误，原因就是已经&#8220;探测&#8221;到该行已经被别的事务锁定，这里无法对其进行锁定操作。</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">sec@ora10g&gt; select * from table_sfu where a = 1 for update wait 3;</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">select * from table_sfu where a = 1 for update wait 3</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">ERROR at line 1:</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">ORA-30006: resource busy; acquire with WAIT timeout expired</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">这里提示的错误内容与上面的一样，不过这里wait 3表示，我等你三秒的时间，如果三秒过后还无法锁定资源，就报错。</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">9.更进一步，请参考Oracle官方文档中相关的描述</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">《for_update_clause ::=》</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_10002.htm#i2126016</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">语法格式：</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">FOR UPDATE</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">[ OF [ [ schema. ]</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { table | view } . ]column</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [, [ [ schema. ]</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { table | view } . ]column</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ]...</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">]</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">[ NOWAIT | WAIT integer ]</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">同上述连接，搜索关键字&#8220;for_update_clause&#8221;可以得到每个选项的解释信息</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">《Using the FOR UPDATE Clause: Examples 》</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_10002.htm#i2130052</span><br style="FONT-FAMILY: Courier New"><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">10.小结</span><br style="FONT-FAMILY: Courier New"><span style="FONT-FAMILY: Courier New">上面的小实验展示了一下Select For Update行级锁定的效果，Oracle的锁定机制还是非常的灵活的，基于这个锁定可以实现&#8220;悲观锁定&#8221;。</span><br style="FONT-FAMILY: Courier New">
<img src ="http://www.cppblog.com/prayer/aggbug/109939.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-03-17 23:42 <a href="http://www.cppblog.com/prayer/archive/2010/03/17/109939.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有关"SELECT FOR UPDATE"的一些概念</title><link>http://www.cppblog.com/prayer/archive/2010/03/17/109938.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Wed, 17 Mar 2010 15:39:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/03/17/109938.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/109938.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/03/17/109938.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/109938.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/109938.html</trackback:ping><description><![CDATA[<p style="TEXT-INDENT: 2em">statement: 一个SQL语句。</p>
<p style="TEXT-INDENT: 2em"></p>
<p style="TEXT-INDENT: 2em">session: 一个由ORACLE用户产生的连接，一个用户可以产生多个SESSION ，但相互之间是独立的。</p>
<p style="TEXT-INDENT: 2em">transaction:所有的改变都可以划分到transaction里，一个 transaction包含一个或多个SQL。当一个SESSION建立的时候就是一个TRANSACTION开始的时刻，此后transaction的 开始和结束由DCL控制，也就是每个COMMIT/ROLLBACK都标示着一个transaction的结束。</p>
<p style="TEXT-INDENT: 2em">consistency：是对于statement级别而不是transaction级别来说的。sql statement 得到的数据都是以sql statement开始的IMAGE。</p>
<p style="TEXT-INDENT: 2em"><strong>LOCK的基本情况：</strong></p>
<p style="TEXT-INDENT: 2em">update, insert ,delete, select ... for update会LOCK相应的ROW 。</p>
<p style="TEXT-INDENT: 2em">只有一个TRANSACTION可以LOCK相应的行，也就是说如果一个ROW已经LOCKED了，那就不能被其他TRANSACTION所LOCK了。</p>
<p style="TEXT-INDENT: 2em">LOCK由statement产生但却由TRANSACTION结尾（commit，rollback），也就是说一个SQL完成后LOCK还会存在，只有在COMMIT/ROLLBACK后才会RELEASE。</p>
<center><ccid_nobr></ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SELECT.... FOR UPDATE [OF cols] [NOWAIT];<br>OF cols<br>SELECT cols FROM tables [WHERE...] FOR UPDATE [OF cols] [NOWAIT];</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<p style="TEXT-INDENT: 2em">前面的FOR UPDATE省略，下面我们来讲一下OF。</p>
<center><ccid_nobr></ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>transaction A运行<br>select a.object_name,a.object_id from wwm2 a,wwm3 b<br>2 where b.status='VALID' and a.object_id=b.object_id<br>3* for update of a.status</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<p style="TEXT-INDENT: 2em">则transaction B可以对b表wwm3的相应行进行DML操作,但不能对a表wwm2相应行进行DML操作.</p>
<p style="TEXT-INDENT: 2em">反一下看看。</p>
<center><ccid_nobr></ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>transaction A运行<br>select a.object_name,a.object_id from wwm2 a,wwm3 b<br>2 where b.status='VALID' and a.object_id=b.object_id<br>3* for update of b.status</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<p style="TEXT-INDENT: 2em">则transaction B可以对a表wwm2的相应行进行DML操作,但不能对b表wwm3相应行进行DML操作.</p>
<p style="TEXT-INDENT: 2em">也就是说LOCK的还是行,只是如果不加OF的话会对所有涉及的表LOCK的,加了OF后只会LOCK OF 字句所在的TABLE.</p>
<p style="TEXT-INDENT: 2em">NOWAIT（如果一定要用FOR UPDATE，我更建议加上NOWAIT）</p>
<p style="TEXT-INDENT: 2em">当有LOCK冲突时会提示错误并结束STATEMENT而不是在那里等待.返回错误是"ORA-00054: resource busy and acquire with NOWAIT specified"</p>
<p style="TEXT-INDENT: 2em">另外如下用法也值得推荐，应该酌情考虑使用。</p>
<center><ccid_nobr></ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>FOR UPDATE WAIT 5</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<p style="TEXT-INDENT: 2em">5秒后会出现提示：</p>
<center><ccid_nobr></ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>ORA-30006: resource busy; acquire with WAIT timeout expired<br>FOR UPDATE NOWAIT SKIP LOCKED;</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<p style="TEXT-INDENT: 2em">出现提示：</p>
<center><ccid_nobr></ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>no rows selected<br>TABLE LOCKS<br>LOCK TABLE table(s) IN EXCLUSIVE MODE [NOWAIT];</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<p style="TEXT-INDENT: 2em">同样也是在transaction结束时才会释放lock。</p>
<p style="TEXT-INDENT: 2em"><strong>DEADLOCK:</strong></p>
<center><ccid_nobr></ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>transaction a lock rowA , then transaction b lock rowB<br>then transaction a tries to lock rowB, <br>and transaction b tries to lock rowA</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<p style="TEXT-INDENT: 2em">也<font size=2>就是说</font>两个transaction都相互试图去lock对方已经lock的ROW，都在等待对方释放自己的lock，这样就使死锁。另外，deadlock也会有600提示。</p>
<p style="TEXT-INDENT: 2em"><font size=3><strong>使用说明</strong></font></p>
<p style="TEXT-INDENT: 2em"><span style="FONT-SIZE: 12pt">Select&#8230;For Update</span>语句的语法与select语句相同，只是在select语句的后面加FOR UPDATE [NOWAIT]子句。</p>
<p style="TEXT-INDENT: 2em"><font size=2><span style="FONT-SIZE: 12pt">该语句用来锁定特定的行（如果有where子句，就是满足where条件的那些行）。当这些行被锁定后，其他会话可以选择这些行，但不能更改或删除这些行，直到该语句的事务被commit语句或rollback语句结束为止。</span></font></p>
<div style="TEXT-INDENT: 21pt" align=left><font size=2><span style="FONT-SIZE: 12pt">如 图20.51所示，左上角的会话用Select&#8230;For Update语句锁定了Department表中DeptNo='01'的行，右上角的会话说明其他会话不可以继续更改该行上的数据。从OEM中的锁的信 息可以看出，Select&#8230;For Update语句所加的锁与update语句所加的锁相同：一个行级别的EXCLUSIVE锁（说明多个事务不能同时操作同一行）、一个表级别的ROW EXCLUSIVE锁。</span></font></div>
<div align=left><font size=2><span style="FONT-SIZE: 12pt"><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/cyp207/1ce50102d58c402f9fe9af70a0a9692c.jpg"><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/cyp207/d686a4194380424e9e988113f7ce773c.jpg"></span></font></div>
<div align=left><font size=2><span style="FONT-SIZE: 12pt"><br></span></font></div>
<div align=center><font size=2><span style="FONT-SIZE: 12pt">图20.51&nbsp;&nbsp; Select&#8230;For Update语句锁定了符合where条件的行</span></font></div>
<div style="TEXT-INDENT: 21pt" align=left><font size=2><span style="FONT-SIZE: 12pt">如图20.52所示，左上角的会话用Update语句锁定了Department表中DeptNo='01'的行，右上角的会话说明其他会话不可以用Select&#8230;For Update语句继续锁定该行。</span></font></div>
<div align=left><font size=2><span style="FONT-SIZE: 12pt"><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/cyp207/c6c60e9acec1450da3c7ad62a076218d.jpg"><a href="http://hiphotos.baidu.com/neonway/pic/item/d7285ff4e0a19ae87609d7fa.jpg" target=_blank><span style="TEXT-DECORATION: none"><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/cyp207/736fc2fdfaeb4c71a1c082e140b3af24.jpg"></span></a></span></font></div>
<div align=left><font size=2><span style="FONT-SIZE: 12pt"><br></span></font></div>
<div align=center><font size=2><span style="FONT-SIZE: 12pt">图20.52&nbsp;&nbsp; Select&#8230;For Update语句被其他会话阻塞了</span></font></div>
<div style="TEXT-INDENT: 21pt" align=left><font size=2><span style="FONT-SIZE: 12pt">如 图20.53所示，左上角的会话用Update语句锁定了Department表中DeptNo='01'的行，右上角的会话说明其他会话不可以用 Select&#8230;For Update NOWAIT语句继续锁定该行，且会立即返回一个错误提示&#8220;ORA-00054: 资源正忙, 但指定以 NOWAIT 方式获取资源&#8221;，而不需要等待加锁成功。</span></font></div>
<div align=left><font size=2><span style="FONT-SIZE: 12pt"><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/cyp207/e1ee95fd85b8437ebe689c0686c1a130.jpg"><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/cyp207/a4be333273834737b3d59ffb33306943.jpg"></span></font></div>
<font size=2><br></font>
<div align=center><font size=2><span style="FONT-SIZE: 12pt">图20.53&nbsp;&nbsp;&nbsp; 如果加锁不成功，则Select&#8230;For Update NOWAIT语句就会立即返回错误提示</span></font></div>
<div style="TEXT-INDENT: 21pt" align=left><font size=2><span style="FONT-SIZE: 12pt">可 以看出，如果仅仅用update语句来更改数据时，可能会因为加不上锁而没有响应地、莫名其妙地等待，但如果在此之前，先用Select&#8230;For Update NOWAIT语句将要更改的数据试探性地加锁，</span></font></div>
<img src ="http://www.cppblog.com/prayer/aggbug/109938.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-03-17 23:39 <a href="http://www.cppblog.com/prayer/archive/2010/03/17/109938.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>select..for update </title><link>http://www.cppblog.com/prayer/archive/2010/03/17/109936.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Wed, 17 Mar 2010 15:38:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/03/17/109936.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/109936.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/03/17/109936.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/109936.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/109936.html</trackback:ping><description><![CDATA[update, insert ,delete, select ... for update会LOCK相应的ROW 。<br><strong>只有一个TRANSACTION可以LOCK相应的行，也就是说如果一个ROW已经LOCKED了，那就不能被其他TRANSACTION所LOCK了。<br></strong>LOCK由statement产生但却由TRANSACTION结尾（commit，rollback），也就是说一个SQL完成后LOCK还会存在，只有在COMMIT/ROLLBACK后才会RELEASE。xsb注：同样的道理，<strong>如果一个游标使用了for update打开后，虽然关闭了游标，但这个lock也仍是存在的，直到transaction结束！<br></strong>SELECT.... FOR UPDATE [OF cols] [NOWAIT];<br><br>SELECT cols FROM tables [WHERE...] FOR UPDATE [OF cols] [NOWAIT];<br>transaction A运行<br>select a.c1,a.c2 from t1 a,t2 b<br>2 where b.c3=1 and a.c1=b.c1<br>3* for update of a.c2<br>此时transaction B可以对b表t2的相应行进行DML操作,但不能对a表t1相应行进行DML操作.<br>再看：<br>transaction A运行<br>select a.c1,a.c2 from t1 a,t2 b<br>2 where b.c3=1 and a.c1=b.c1<br>3* for update of b.c2<br>此时transaction B可以对a表t1的相应行进行DML操作,但不能对b表t2相应的行进行DML操作.<br><strong>也就是说LOCK的仍然是行,只是如果不加OF的话会对所有涉及的表LOCK,加了OF后只会LOCK OF 字句所在的TABLE.<br></strong>NOWAIT（如果一定要用FOR UPDATE，可以加上NOWAIT）<br>当有LOCK冲突时会提示错误并结束STATEMENT，返回错误是"ORA-00054: resource busy and acquire with NOWAIT specified"，否则就会在那里等待。<br>另外如下用法也值得推荐，应该酌情考虑使用。<br>FOR UPDATE WAIT 5<br>5秒后会提示ORA-30006: resource busy; acquire with WAIT timeout expired<br>FOR UPDATE NOWAIT SKIP LOCKED;<br>会提示no rows selected<br>TABLE LOCKS<br>LOCK TABLE table(s) IN EXCLUSIVE MODE [NOWAIT];<br>同样也是在transaction结束时才会释放lock。<br>DEADLOCK<br>transaction a lock rowA , then transaction b lock rowB<br>then transaction a tries to lock rowB, and transaction b tries to lock rowA<br>也就是说两个transaction都相互试图去lock对方已经lock的ROW，都在等待对方释放自己的lock，这样就使死锁。deadlock也会有600提示。 
<img src ="http://www.cppblog.com/prayer/aggbug/109936.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-03-17 23:38 <a href="http://www.cppblog.com/prayer/archive/2010/03/17/109936.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>隔离级别和锁</title><link>http://www.cppblog.com/prayer/archive/2010/03/17/109873.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Wed, 17 Mar 2010 01:46:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/03/17/109873.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/109873.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/03/17/109873.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/109873.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/109873.html</trackback:ping><description><![CDATA[<p>我们在进行客户支持时遇到最多的话题之一就是锁。&#8220;为什么 DB2 锁住了这个表、行或者对象？&#8221;，&#8220;这个锁会阻塞多长时间及为什么？&#8221;；&#8220;为什么出现了死锁？&#8221;，&#8220;我的锁请求在等待什么？&#8221;，诸如此类问题等等。更仔细地分析一些常见的锁示例可以说明DB2锁定策略背后的原则。在国内很多DB2用户都会碰到有关锁等待、死锁和锁升级等锁相关的问题，本章将会对这些问题以及解决方法做详细的讲解。</p>
<p>本章主要讲解如下内容：</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 隔离级别和锁</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 加锁总结</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 乐观锁</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 内部锁</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 设置锁相关的注册变量</p>
<h3>6.1&nbsp; 隔离级别和锁</h3>
<p>要维护数据库的一致性和数据完整性，同时又允许多个应用程序同时访问一个数据库，将这样的特性称为并发性。DB2数据库尝试强制实施并发性的方法之一是使用隔离级别，它决定在第一个事务访问数据时，如何对其他事务锁定或隔离该事务所使用的数据。DB2使用下列隔离级别来强制实施并发性：</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可重复读(Reapeatable Read，RR) </p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 读稳定性(Read Stability，RS) </p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 游标稳定性(Cursor Stability，CS) </p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 未提交的读(Uncommitted Read，UR) </p>
<p>隔离级别是根据称为现象(Phenomena)的三个禁止操作序列来声明的： </p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 脏读(Dirty Read)：在事务A提交修改结果之前，其他事务即可看到事务Ａ的修改结果。</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不可重复读(Non-Repeatable Read)：在事务Ａ提交之前，<strong>允许其他事务修改和删除事务Ａ涉及的数据，导致事务Ａ中执行同样操作的结果集变小。</strong></p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 幻像读(Phantom Read)：事务Ａ在提交查询结果之前，其他事务可以插入或者更改事务A涉及的数据，<strong>导致事务A中执行同样操作的结果集增大。</strong></p>
<p>数据库并发性(可以同时访问同一资源的事务数量)因隔离级别不同而有所差异，可重复读隔离级别可以防止所有现象，但是会大大降低并发性。未提交读隔离级别提供了最大的并发性，但可能会造成&#8220;脏读&#8221;、&#8220;幻像读&#8221;或&#8220;不可重复读&#8221;现象。DB2默认的隔离级别是CS。</p>
<h3>6.1.1&nbsp; 可重复读</h3>
<p>可重复读隔离级别是最严格的隔离级别。在使用它时，一个事务的操作结果完全与其他并发事务隔离，脏读、不可重复读、幻像读都不会发生。当使用可重复读隔离级别时，在事务执行期间会共享(S)锁定该事务以任何方式引用的所有行，在该事务中多次执行同一条SELECT语句，得到的结果数据集总是相同的。因此，使用可重复读隔离级别的事务可以多次检索同一行集，并可以对它们执行任意操作，直到提交或回滚操作终止事务。但是，在事务提交前，不允许其他事务执行会影响该事务正在访问的任何行的插入、更新或删除操作。为了确保这种行为，需要锁定该事务所引用的<em>每一</em>行—— 而不是仅锁定被实际检索或修改的那些行。因此，如果一个表中有1000行，但只检索两行，则整个表(1000行，而不仅是被检索的两行)都会被锁定。输出结果如下：</p>
<p>C:\&gt;db2 +c select empno,firstnme,salary from employee where empno between '000010' and '000020' with &nbsp;rr</p>
<p>EMPNO&nbsp; FIRSTNME&nbsp;&nbsp;&nbsp;&nbsp; SALARY</p>
<p>------ ------------ -----------</p>
<p>000010 CHRISTINE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 152750.00</p>
<p>000020 MICHAEL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 94250.00</p>
<p>&nbsp; 2 条记录已选择。</p>
<p align=left>我们通过&#8220;get snapshot for locks on sample&#8221;命令来监控表加锁情况，输出结果如下：</p>
<p>C:\&gt;db2 update monitor switches using lock on</p>
<p>DB20000I&nbsp; UPDATE MONITOR SWITCHES命令成功完成。</p>
<p>C:\&gt;db2 get snapshot for locks on sample | more</p>
<p>--------------略------------------</p>
<p>锁定列表</p>
<p>锁定名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x020006000E0040010000000052</p>
<p>锁定属性&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000010</p>
<p>发行版标志&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= 0x00000004</p>
<p>锁定计数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 1</p>
<p>挂起计数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0</p>
<p>锁定对象名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 20971534</p>
<p><strong>对象类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 表</strong></p>
<p>表空间名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = USERSPACE1</p>
<p>表模式&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = DB2ADMIN</p>
<p>表名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = EMPLOYEE</p>
<p><strong>方式&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = S&nbsp;&nbsp;&nbsp; --注：虽然读取了两行，但是整个表加S锁</strong></p>
<p>如果使用这种隔离级别，不管你从表中读多少数据，<strong>整个表上都加S锁</strong>，直到该事务被提交或回滚，表上的锁才会被释放。这样可以保证在一个事务中即使多次读取同一行，都会得到相同结果集。另外，在同一事务中如果以同样的搜索标准重新打开已被处理过的游标，那么得到的结果集不会改变。可重复读相对于读稳定性而言，加锁的范围更大：对于读稳定性，应用程序只对符合要求的所有行加锁；而对于重复读，应用程序将对整个表都加S锁。</p>
<p>可重复读会锁定应用程序在工作单元中引用的整个表。利用可重复读，一个应用程序在打开游标的相同工作单元内发出一个SELECT语句两次，每次都返回相同的结果。利用可重复读隔离级别，不可能出现丢失更新、脏读和幻像读的情况。</p>
<p>在该工作单元完成之前，&#8220;可重复读&#8221;应用程序可以多次检索和操作这些行。但是，在该工作单元完成之前其他应用程序均不能更新、删除或插入可能会影响结果表的行。&#8220;可重复读&#8221;应用程序不能查看其他应用程序未提交的更改。</p>
<h3>6.1.2&nbsp; 读稳定性</h3>
<p>读稳定性隔离级别没有可重复读隔离级别那么严格；因此，它没有将事务与其他并发事务的效果完全隔离。读稳定性隔离级别可以防止脏读和不可重复读，但是可能出现幻像读。在使用这个隔离级别时，只锁定事务实际检索和修改的行。因此，如果一个表中有1000行，但只检索两行(通过索引扫描)，则只锁定被检索的两行(而不是所扫描的 1000 行)。因此，如果在同一个事务中发出同一个SELECT语句两次或更多次，那么每次产生的结果数据集可能不同。</p>
<p>与可重复读隔离级别一样，在读稳定性隔离级别下运行的事务可以检索一个行集(ROWS SET)，并可以对它们执行任意操作，直到事务终止。在这个事务存在期间，其他事务不能执行那些会影响这个事务检索到的行集的更新或删除操作，但是可以执行插入操作。如果插入的行与第一个事务的查询的选择条件匹配，那么这些行可能作为幻像出现在后续产生的结果数据集中。其他事务对其他行所作的更改，在提交之前是不可见的。下面我们还用上面的那个例子锁定读稳定性，输出结果如下：</p>
<p>C:\&gt;db2 +c select empno,firstnme,salary from employee where empno between '000010' and '000020' with &nbsp;rs</p>
<p>EMPNO&nbsp; FIRSTNME&nbsp;&nbsp;&nbsp;&nbsp; SALARY</p>
<p>------ ------------ -----------</p>
<p>000010 CHRISTINE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 152750.00</p>
<p>000020 MICHAEL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 94250.00</p>
<p>&nbsp; 2 条记录已选择。</p>
<p>我们通过&#8220;get snapshot for locks on sample&#8221;命令来监控表加锁情况，输出结果如下：</p>
<p>C:\&gt;db2 update monitor switches using lock on</p>
<p>DB20000I&nbsp; UPDATE MONITOR SWITCHES命令成功完成。</p>
<p>C:\&gt;db2 get snapshot for locks on sample | more</p>
<p>--------------略------------------</p>
<p>锁定列表</p>
<p>锁定名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x02000600050040010000000052</p>
<p>锁定属性&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000010</p>
<p>发行版标志&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000001</p>
<p>锁定计数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 1</p>
<p>挂起计数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0</p>
<p>锁定对象名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 20971525</p>
<p><strong>对象类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 行</strong></p>
<p>表名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　　　　　= EMPLOYEE</p>
<p><strong>方式&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = S　--注：只在读取的行上加S锁</strong></p>
<p>锁定名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x02000600040040010000000052</p>
<p>锁定属性&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000010</p>
<p>发行版标志&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000001</p>
<p>锁定计数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 1</p>
<p>挂起计数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0</p>
<p>锁定对象名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 20971524</p>
<p>对象类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 行</p>
<p>表名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;　　　　 = EMPLOYEE</p>
<p>方式&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = S　--注：只在读取的行上加S锁</p>
<p>锁定名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x02000600000000000000000053</p>
<p>锁定属性&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000010</p>
<p>发行版标志&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000001</p>
<p>锁定计数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 1</p>
<p>挂起计数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= 0</p>
<p>锁定对象名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 6</p>
<p><strong>对象类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 表</strong></p>
<p>表名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　　　　　= EMPLOYEE</p>
<p><strong>方式&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = IS　--注：表上加IS锁</strong></p>
<p>如果使用这种隔离级，那么在一个事务中将有N+1个锁，<strong>其中N是所有被读取(通过索引扫描)过的行的数目，这些行上都会被加上NS锁，在表上加上1个IS锁。</strong>这些锁直到该事务被提交或回滚才会被释放。这样可以保证在一个事务中即使多次读取同一行，得到的值也不会改变。但是使用这种隔离级别，在一个事务中，如果使用同样的搜索标准重新打开已被处理过的游标，则结果集可能改变(可能会增加某些行，这些行被称为幻影行(Phantom))。这是因为RS隔离级别不能阻止通过插入或更新操作在结果集中加入新行。</p>
<p>注意：</p>
<p>NS是下一键共享锁，此时锁拥有者和所有并发的事务都可以读(但不能更改)被锁定行中的数据。这种锁用来在使用读稳定性或游标稳定性事务隔离级别读取的数据上代替共享锁。</p>
<p>读稳定性(RS)只锁定应用程序在工作单元中检索的那些行。它确保在某个工作单元完成之前，在该工作单元运行期间的任何限定行读取不被其他应用程序进程更改，且确保不会读取由另一个应用程序进程所更改的任何行，直至该进程提交了这些更改。也就是说，不可能出现&#8220;不可重复读&#8221;情形。</p>
<p>&#8220;读稳定性&#8221;隔离级别的其中一个目标是提供较高并行性以及数据的稳定视图，为了有助于达到此目标，优化器确保在发生锁定升级前不获取表级锁定。</p>
<p>&#8220;读稳定性&#8221;隔离级别最适用于包括下列所有特征的应用程序： </p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在并发环境下运行。</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 需要限定某些行在工作单元运行期间保持稳定。</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在工作单元中不会多次发出相同的查询，或者在同一工作单元中发出多次查询时并不要求该查询获得相同的回答。 </p>
<h3>6.1.3&nbsp; 游标稳定性</h3>
<p>游标稳定性隔离级别在隔离事务效果方面非常宽松。它可以防止脏读；但有可能出现不可重复读和幻像读。这是因为在大多数情况下，游标稳定性隔离级别只锁定事务声明并打开的游标当前引用的行。 </p>
<p>当使用游标稳定性隔离级别的事务通过游标从表中检索行时，其他事务不能更新或删除游标所引用的行。但是，如果被锁定的行本身不是用索引访问的，那么其他事务可以将新的行添加到表中，以及对被游标锁定行前后的行进行更新或删除操作。所获取的锁一直有效，直到游标重定位或事务终止为止(如果游标重定位，原来行上的锁就被释放，并获得游标现在引用的行上的锁)。此外，如果事务修改了它检索到的任何行，那么在事务终止之前，其他事务不能更新或删除该行，即使在游标不再位于被修改的行时。与可重复读和读稳定性隔离级别一样，其他事务在其他行上进行的更改，在这些更改提交之前对于使用游标稳定性隔离级别的事务(这是默认的隔离级别)是不可见的。我们还用上面那个例子，一个表中有1000行数据，我们只检索其中两行数据。那么对于可重复读隔离级别会锁住整个表，对于读稳定性隔离级别会对读到的数据(两行)加锁，而对于游标稳定性隔离级别只对游标当前所在那一行加锁，游标所在行的前一行和下一行都不加锁。下面我们举一个游标稳定性的例子，输出结果如下：</p>
<p>C:\&gt;db2 +c declare c1 cursor for &nbsp;select empno,firstnme,salary from employee where empno between '000010' and '000020' with cs</p>
<p>C:\&gt;db2 +c open c1</p>
<p>C:\&gt;db2 +c fetch c1</p>
<p>EMPNO&nbsp; &nbsp;FIRSTNME&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;SALARY</p>
<p>------ ------------ -----------</p>
<p>000010 CHRISTINE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 152750.00&nbsp;&nbsp; --注：游标当前所在行，DB2只对这一行加锁。游标的</p>
<p>上一行和下一行都不加锁。当游标移动到下一行时，锁自动释放。</p>
<p>&nbsp; 1 条记录已选择。</p>
<p>我们通过&#8220;get snapshot for locks on sample&#8221;命令来监控表加锁情况，输出结果如下：</p>
<p>C:\&gt;db2 update monitor switches using lock on</p>
<p>DB20000I&nbsp; UPDATE MONITOR SWITCHES命令成功完成。</p>
<p>C:\&gt;db2 get snapshot for locks on sample | more</p>
<p>--------------略------------------</p>
<p>锁定名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; = 0x02000600040040010000000052</p>
<p>锁定属性&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; = 0x00000010</p>
<p>发行版标志&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; = 0x00000001</p>
<p>锁定计数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; = 1</p>
<p>挂起计数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; = 0</p>
<p>锁定对象名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; = 20971524</p>
<p>对象类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 行</p>
<p>表名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = EMPLOYEE</p>
<p>方式&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; = S　--注：只在游标所在行上加S锁</p>
<p>锁定名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; = 0x02000600000000000000000053</p>
<p>锁定属性&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; = 0x00000010</p>
<p>发行版标志&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; = 0x00000001</p>
<p>锁定计数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; = 1</p>
<p>挂起计数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; = 0</p>
<p>锁定对象名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; = 6</p>
<p>对象类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 表</p>
<p>表名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= EMPLOYEE</p>
<p>方式&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = IS　--注：表上加IS锁</p>
<p>如果使用这种隔离级，那么在一个事务中只有两个锁：结果集中只有正在被读取的那一行(游标指向的行)被加上NS锁，在表上加IS锁。其他未被处理的行上不加锁。这种隔离级别只能保证正在处理的行的值不会被其他并发的程序所改变。该隔离级别是DB2默认的隔离级别。</p>
<p>游标稳定性(CS)当在行上定位游标时会锁定任何由应用程序的事务所访问的行。此锁定在读取下一行或终止事务之前有效。但是，如果更改了某一行上的任何数据，那么在对数据库提交更改之前必须挂起该锁定。</p>
<p>对于具有&#8220;游标稳定性&#8221;的应用程序已检索的行，当该行上有任何可更新的游标时，任何其他应用程序都不能更新或删除该行。&#8220;游标稳定性&#8221;应用程序不能查看其他应用程序的未提交操作。</p>
<p>使用&#8220;游标稳定性&#8221;，可能会出现不可重复读和幻像读现象。&#8220;游标稳定性&#8221;是默认隔离级别，应在需要最大并行性，但只看到其他应用程序中的已提交行的情况下才使用。</p>
<h3>6.1.4&nbsp; 未提交读</h3>
<p>未提交读隔离级别是最不严格的隔离级别。实际上，在使用这个隔离级别时，仅当另一个事务试图删除或更改被检索的行所在的表时，才会锁定一个事务检索的行。因为在使用这种隔离级别时，行通常保持未锁定状态，所以脏读、不可重复读和幻像读都可能会发生。因此，未提交读隔离级别通常用于那些访问只读表和视图的事务，以及某些执行SELECT语句的事务(只要其他事务的未提交数据对这些语句没有负面效果)。 </p>
<p>顾名思义，其他事务对行所做的更改在提交之前对于使用未提交读隔离级别的事务是可见的。但是，此类事务不能看见或访问其他事务DDL(CREATE、ALTER和DROP)语句所创建的表、视图或索引，直到那些事务被提交为止。类似地，如果其他事务删除了现有的表、视图或索引，那么仅当进行删除操作的事务终止时，使用未提交读隔离级别的事务才能知道这些对象不再存在了。</p>
<p>一定要注意一点：当运行在未提交读隔离级别下的事务使用可更新游标时，该事务的行为和在游标稳定性隔离级别下运行一样，并应用游标稳定性隔离级别的约束。下面我们举一个例子。</p>
<p>我们编写一个SQL存储过程，在存储过程中我们显式地在SELECT语句中使用UR隔离级别。</p>
<p>创建一个存储过程，保存为LOCKS.SQL，输出结果如下：</p>
<p align=left>CREATE PROCEDURE locks()</p>
<p align=left>LANGUAGE SQL</p>
<p align=left>BEGIN</p>
<p align=left>declare c1 cursor for select * from staff with UR;</p>
<p align=left>open c1;</p>
<p align=left>while 1=1 do　——注：死循环</p>
<p align=left>end while;</p>
<p align=left>END @</p>
<p>为了方便抓住锁信息，我们在这个存储过程的结尾处使用了一个死循环。利用一个命令窗口运行存储过程，输出结果如下： </p>
<p align=left>C:\ &gt;db2 &#8211;td@ -vf locks.sql</p>
<p align=left>C:\ &gt;db2 "call locks()"</p>
<p align=left>再打开一个新的窗口，得到在STAFF表上的当前锁信息，输出结果如下：</p>
<p align=left>C:\&gt;db2pd -db sample -locks show detail</p>
<p align=left>Locks:</p>
<p align=left>Address TranHdl Lockname Type Mode Sts Owner Dur HldCnt Att ReleaseFlg</p>
<p align=left>0x408E0290 2 00020003000000000000000054 Table .IS G 2 1 0 0x0000 0x00000001 </p>
<p align=left>TbspaceID 2 TableID 3</p>
<p>但是会发现此时在STAFF表上出现的是IS锁，而不是IN锁。是什么原因呢？<strong>这是因为UR隔离级别允许应用程序存取其他事务的未落实的更改，但是对于只读和可更新这两种不同的游标类型，UR的工作方式有所不同。对于可更新的游标，当它使用隔离级别 UR 运行程序时，应用程序会自动使用隔离级别 CS。 </strong></p>
<p>在上面的例子当中，虽然显式地指定了SQL语句的隔离级别是UR，但是，由于在存储过程中使用的游标是模糊游标(也就是没有显式地声明游标是只读的还是可更新的)，因而系统会默认地将这个模糊游标当成可更新游标处理，存储过程的隔离级别自动从UR升级为CS。要防止此升级，可以采用以下办法：</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 修改应用程序中的游标，以使这些游标是非模糊游标。将SELECT语句更改为包括FOR READ ONLY子句。 </p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将模糊游标保留在应用程序中，但是预编译程序或使用BLOCKING ALL和STATIC READONLY YES选项绑定它以允许在运行该程序时将任何模糊游标视为只读游标。 </p>
<p>我们还是使用上面的例子，显式地将该游标声明成只读游标，输出结果如下： </p>
<p align=left>declare c1 cursor for select * from staff<strong> for read only with UR;</strong></p>
<p>此时我们再运行这个存储过程，并利用DB2PD获取锁的情况，输出结果如下： </p>
<p align=left>c:\&gt; db2pd -db sample -locks show locks</p>
<p align=left>Locks:</p>
<p align=left>Address TranHdl Lockname Type Mode Sts Owner Dur HldCnt Att ReleaseFlg</p>
<p align=left>0x408E07E0 2 00020003000000000000000054 Table .IN G 2 1 0 0x0000 0x00000001 </p>
<p align=left>TbspaceID 2 TableID 3</p>
<p align=left>-注：可以看到STAFF表上出现的锁是IN锁。</p>
<p>从上面的例子中我们可以看到：&#8220;未提交读(UR)&#8221;隔离级别允许应用程序访问其他事务的未提交的更改。除非其他应用程序尝试删除或改变该表，否则该应用程序也不会锁定正读取的行而使其他应用程序不能访问该行。对于只读和可更新的游标，&#8220;未提交的读&#8221;的工作方式有所不同。</p>
<p>如果使用这种隔离级别，那么对于只读操作不加行锁。典型的只读操作包括：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT语句的结果集只读(比如语句中包括ORDER BY子句)；定义游标时指明起为FOR FETCH ONLY或FOR READ ONLY。</p>
<p>该隔离级别可以改善应用程序的性能，同时可以达到最大程度的并发性。但是，应用程序的数据完整性将受到威胁。如果需要读取未提交的数据，该隔离级是唯一选择。</p>
<p>使用&#8220;未提交的读&#8221;，可能出现不可重复读行为和幻像读现象。&#8220;未提交读&#8221;隔离级别最常用于只读表上的查询，或者在仅执行选择语句且不关心是否可从其他应用程序中看到未提交的数据时也最常用。</p>
<p>以上我们所讲的隔离级别的加锁范围和持续时间都是针对读操作而言的。对于更改操作，被修改的行上会被加上X锁，无论使用何种隔离级别，X锁都直到提交或回滚之后才会被释放。</p>
<h3>6.1.5&nbsp; 隔离级别加锁示例讲解</h3>
<p>假设有一张表EMP1，表中有42条记录，我们使用FOR READ ONLY分别在UR、CS、RS和RR隔离级别下加锁。</p>
<p>EMP1表在本章后续的内容中也会使用到，其创建过程如下：</p>
<p align=left>C:\&gt; db2 "create table emp1 like employee"</p>
<p align=left>C:\&gt; db2 "insert into emp1 select * from employee" </p>
<p>我们使用EMP1表中JOB字段内容为'CLERK'的数据，输出结果如下：</p>
<p align=left>C:\&gt;db2 +c select empno,job,salary from emp1 where job='CLERK'&nbsp; for read only</p>
<p align=left>EMPNO&nbsp; JOB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SALARY</p>
<p align=left>------ -------- -----------</p>
<p align=left>000120 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 49250.00</p>
<p align=left>000230 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 42180.00</p>
<p align=left>000240 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 48760.00</p>
<p align=left>000250 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 49180.00</p>
<p align=left>000260 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 47250.00</p>
<p align=left>000270 CLERK&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;37380.00</p>
<p align=left>200120 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 39250.00</p>
<p align=left>200240 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 37760.00</p>
<p align=left>&nbsp; 8 条记录已选择。</p>
<p>在上面的SQL语句中，我们从表的42条记录中返回8条记录。下面我们分别看看这条语句在不同的隔离级别下加锁的情况：</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UR隔离级别，输出结果如下：</p>
<p align=left>C:\&gt;db2 +c select empno,job,salary from emp1 where job='CLERK'&nbsp; for read only with ur</p>
<p align=left>EMPNO&nbsp; JOB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;SALARY</p>
<p align=left>------ -------- -----------</p>
<p align=left>000120 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 49250.00</p>
<p align=left>000230 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 42180.00</p>
<p align=left>000240 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 48760.00</p>
<p align=left>000250 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 49180.00</p>
<p align=left>000260 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 47250.00</p>
<p align=left>000270 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 37380.00</p>
<p align=left>200120 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 39250.00</p>
<p align=left>200240 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 37760.00</p>
<p align=left>&nbsp; 8 条记录已选择。</p>
<p>在另外一个窗口中使用&#8220;db2 get snapshot for locks on sample&#8221;命令监控，发现在UR隔离级别下，在表上有一个IN锁，没有加任何行锁。</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CS隔离级别，输出结果如下：</p>
<p align=left>C:\&gt;db2 +c declare c1 cursor for select empno,job,salary from emp1 &nbsp;where job='CLERK'&nbsp; for read only with CS</p>
<p align=left>C: \&gt;db2 +c open c1</p>
<p align=left>C: \&gt;db2 +c fetch c1</p>
<p align=left>EMPNO&nbsp; JOB&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;SALARY</p>
<p align=left>------ -------- -----------</p>
<p align=left>000120 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 49250.00</p>
<p align=left>&nbsp; 1 条记录已选择。</p>
<p>在另外一个窗口中使用&#8220;db2 get snapshot for locks on sample&#8221;命令监控，发现在CS隔离级别下，共有两个锁：在表上有一个IS锁，在行上有一个NS锁。</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RS隔离级别，输出结果如下：</p>
<p align=left>C:\&gt;db2 +c select empno,job,salary from emp1 where job='CLERK'&nbsp; for read only with RS</p>
<p align=left>EMPNO&nbsp; JOB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SALARY</p>
<p align=left>------ -------- -----------</p>
<p align=left>000120 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 49250.00</p>
<p align=left>000230 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 42180.00</p>
<p align=left>000240 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 48760.00</p>
<p align=left>000250 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 49180.00</p>
<p align=left>000260 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 47250.00</p>
<p align=left>000270 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 37380.00</p>
<p align=left>200120 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 39250.00</p>
<p align=left>200240 CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 37760.00</p>
<p align=left>&nbsp; 8 条记录已选择。</p>
<p>在另外一个窗口中使用&#8220;db2 get snapshot for locks on sample&#8221;命令监控，发现在RS隔离级别下，共有9个锁：在表上有一个IS锁，在读取的8行上分别有1个NS锁。</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RR隔离级别，输出结果如下：</p>
<p align=left>C:\&gt;db2 +c select empno,job,salary from emp1 where job='CLERK'&nbsp; for read only with RR</p>
<p align=left>EMPNO&nbsp; JOB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;SALARY</p>
<p align=left>------ -------- -----------</p>
<p align=left>000120 CLERK&nbsp;&nbsp;&nbsp;&nbsp; 49250.00</p>
<p align=left>000230 CLERK&nbsp;&nbsp;&nbsp;&nbsp; 42180.00</p>
<p align=left>000240 CLERK&nbsp;&nbsp;&nbsp;&nbsp; 48760.00</p>
<p align=left>000250 CLERK&nbsp;&nbsp;&nbsp;&nbsp; 49180.00</p>
<p align=left>000260 CLERK&nbsp;&nbsp;&nbsp;&nbsp; 47250.00</p>
<p align=left>000270 CLERK&nbsp;&nbsp;&nbsp;&nbsp; 37380.00</p>
<p align=left>200120 CLERK&nbsp;&nbsp;&nbsp;&nbsp; 39250.00</p>
<p align=left>200240 CLERK&nbsp;&nbsp;&nbsp;&nbsp; 37760.00</p>
<p align=left>&nbsp; 8 条记录已选择。</p>
<p>在另外一个窗口中使用&#8220;db2 get snapshot for locks on sample&#8221;命令监控，发现在RR隔离级别下，分为两种情况：</p>
<p>如果该SQL语句使用全表扫描，那么即使只读取了8行，也会在整个表上加一个S锁，输出结果如下：</p>
<p align=left>C:\&gt;dynexpln -d sample -q&nbsp; "select empno,job,salary from emp1 where job='CLERK'</p>
<p align=left>&nbsp;for read only with rr" &#8211;t</p>
<p align=left>Access Table Name = DB2ADMIN.EMP1&nbsp; ID = 3,12</p>
<p align=left>|&nbsp; #Columns = 2</p>
<p align=left>|&nbsp; Relation Scan　--注：全表扫描</p>
<p align=left>|&nbsp; |&nbsp; Prefetch: Eligible</p>
<p align=left>|&nbsp; Isolation Level: Repeatable Read　--注：RR隔离级别</p>
<p align=left>|&nbsp; Lock Intents</p>
<p align=left>|&nbsp; |&nbsp; Table: Share　--注：整个表上加S锁</p>
<p align=left>|&nbsp; |&nbsp; Row&nbsp; : None</p>
<p align=left>|&nbsp; Sargable Predicate(s)</p>
<p align=left>|&nbsp; |&nbsp; #Predicates = 1</p>
<p align=left>|&nbsp; |&nbsp; Return Data to Application</p>
<p align=left>|&nbsp; |&nbsp; |&nbsp; #Columns = 3</p>
<p align=left>Return Data Completion</p>
<p align=left>End of section</p>
<p>如果创建索引，并进行索引扫描，那么表上加IS锁，读取的每行上加S锁。所以对于RR隔离级别来说，为了保证并发，尽可能创建合理的索引以减少加锁的范围，输出结果如下：</p>
<p align=left>C:\&gt;db2 create index job on DB2ADMIN.emp1(job)</p>
<p align=left>DB20000I&nbsp; SQL命令成功完成。</p>
<p align=left>C:\&gt;db2 runstats on table DB2ADMIN.emp1 and indexes all</p>
<p align=left>DB20000I&nbsp; RUNSTATS命令成功完成。</p>
<p align=left>C:\&gt;dynexpln -d sample -q&nbsp; "select empno,job,salary from emp1 where job='CLERK'</p>
<p align=left>&nbsp;for read only with rr" -t</p>
<p align=left>Access Table Name = DB2ADMIN.EMP1&nbsp; ID = 3,12</p>
<p align=left>|&nbsp; Index Scan:&nbsp; Name = DB2ADMIN.JOB&nbsp; ID = 1　--注：索引扫描</p>
<p align=left>|&nbsp; |&nbsp; Regular Index (Not Clustered)</p>
<p align=left>|&nbsp; |&nbsp; Index Columns:</p>
<p align=left>|&nbsp; |&nbsp; |&nbsp; 1: JOB (Ascending)</p>
<p align=left>|&nbsp; #Columns = 2</p>
<p align=left>|&nbsp; #Key Columns = 1</p>
<p align=left>|&nbsp; |&nbsp; Start Key: Inclusive Value</p>
<p align=left>|&nbsp; |&nbsp; |&nbsp; |&nbsp; 1: 'CLERK&nbsp;&nbsp; '</p>
<p align=left>|&nbsp; |&nbsp; Stop Key: Inclusive Value</p>
<p align=left>|&nbsp; |&nbsp; |&nbsp; |&nbsp; 1: 'CLERK&nbsp;&nbsp; '</p>
<p align=left>|&nbsp; Data Prefetch: Eligible 0</p>
<p align=left>|&nbsp; Index Prefetch: None</p>
<p align=left>|&nbsp; Isolation Level: Repeatable Read　--注：RR隔离级别</p>
<p align=left>|&nbsp; Lock Intents</p>
<p align=left>|&nbsp; |&nbsp; Table: Intent Share　--注：表上加IS锁</p>
<p align=left>|&nbsp; |&nbsp; Row&nbsp; : Share　--注：行上加S锁</p>
<p align=left>|&nbsp; Sargable Predicate(s)</p>
<p align=left>|&nbsp; |&nbsp; Return Data to Application</p>
<p align=left>|&nbsp; |&nbsp; |&nbsp; #Columns = 3</p>
<p align=left>Return Data Completion</p>
<p align=left>End of section</p>
<h3>6.1.6&nbsp; 隔离级别摘要</h3>
<p>表6-1按不期望的结果概述了几个不同的隔离级别。</p>
<div align=center>
<table cellSpacing=0 cellPadding=0 width=548 border=1>
    <thead>
        <tr>
            <td colSpan=4>
            <p>表6-1 &nbsp;隔离级别摘要</p>
            </td>
        </tr>
        <tr>
            <td width="25%">
            <p>隔离级别</p>
            </td>
            <td width="25%">
            <p>访问未提交的数据</p>
            </td>
            <td width="25%">
            <p>不可重复读</p>
            </td>
            <td width="25%">
            <p>幻像读现象</p>
            </td>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td vAlign=top width="25%">
            <p>可重复读(RR)</p>
            </td>
            <td vAlign=top width="25%">
            <p>不可能</p>
            </td>
            <td vAlign=top width="25%">
            <p>不可能</p>
            </td>
            <td vAlign=top width="25%">
            <p>不可能</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width="25%">
            <p>读稳定性(RS)</p>
            </td>
            <td vAlign=top width="25%">
            <p>不可能</p>
            </td>
            <td vAlign=top width="25%">
            <p>不可能</p>
            </td>
            <td vAlign=top width="25%">
            <p>可能</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width="25%">
            <p>游标稳定性(CS)</p>
            </td>
            <td vAlign=top width="25%">
            <p>不可能</p>
            </td>
            <td vAlign=top width="25%">
            <p>可能</p>
            </td>
            <td vAlign=top width="25%">
            <p>可能</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width="25%">
            <p>未提交读(UR)</p>
            </td>
            <td vAlign=top width="25%">
            <p>可能</p>
            </td>
            <td vAlign=top width="25%">
            <p>可能</p>
            </td>
            <td vAlign=top width="25%">
            <p>可能</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p>表6-2提供了简单的试探方法，以帮助您为应用程序选择初始隔离级别。首先考虑表中列示的方法，并参阅先前对影响各隔离级别因素的讨论，可能会找到另一个更适合的隔离级别。 </p>
<div align=center>
<table cellSpacing=0 cellPadding=0 width=548 border=1>
    <thead>
        <tr>
            <td colSpan=3>
            <p>表6-2&nbsp; 选择隔离级别的准则</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top>
            <p>应用程序类型</p>
            </td>
            <td vAlign=top>
            <p>需要高数据稳定性</p>
            </td>
            <td vAlign=top>
            <p><strong>不</strong>需要高数据稳定性 </p>
            </td>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td vAlign=top>
            <p>读写事务</p>
            </td>
            <td vAlign=top>
            <p>RS</p>
            </td>
            <td vAlign=top>
            <p>CS</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top>
            <p>只读事务</p>
            </td>
            <td vAlign=top>
            <p>RR 或 RS</p>
            </td>
            <td vAlign=top>
            <p>UR</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p>为避免应用程序出现用户无法容忍的现象，必须为其选择适当的隔离级别。在不同隔离级别下，应用程序锁定或释放资源需要不同的CPU和内存资源，所以隔离级别不但影响应用程序之间的隔离程度，还可能影响应用程序的个别性能特征。潜在的锁等待情况也会随隔离级别的不同而不同。</p>
<p>因为隔离级别确定访问数据时如何锁定数据并使数据不受其他进程影响，所以您在选择隔离级别时应该平衡并行性和数据完整性需求。您指定的隔离级别在工作单元运行期间生效。 </p>
<p>选择正确的隔离级别</p>
<p>使用的隔离级别不仅影响数据库的并发性，而且影响并发应用程序的性能。通常，使用的隔离级别越严格，并发性就越小，某些应用程序的性能可能会随之越低，因为它们要等待资源上的锁被释放。那么，如何决定要使用哪种隔离级别呢？最好的方法是先确定哪些现象是不可接受的，然后选择能够防止这些现象发生的隔离级别。以下列举了各种隔离级别的适用情况：</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果正在执行大型查询，而且不希望并发事务所做的修改导致查询的多次运行返回不同的结果，则使用可重复读隔离级别。 </p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果希望在应用程序之间获得一定的并发性，还希望限定的行在事务执行期间保持稳定，则使用读稳定性隔离级别。 </p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果希望获得最大的并发性，同时不希望查询看到未提交的数据，则使用游标稳定性隔离级别。 </p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果正在只读的表/视图/数据库上执行查询，或者并不介意查询是否返回未提交的数据，则使用未提交读隔离级别。 </p>
<p>设置隔离级别</p>
<p>尽管隔离级别控制事务级上的行为，但实际上它们是在应用程序级被指定的：</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于嵌入式SQL应用程序，在预编译时或在将应用程序绑定到数据库(如果使用延迟绑定)时指定隔离级别。在这种情况下，使用PRECOMPILE或BIND命令的ISOLATION选项来设置隔离级别。 </p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于开放数据库连接(ODBC)和调用级接口(Call Level Interface，CLI)应用程序，隔离级别是在应用程序运行时通过调用指定了SQL_ATTR_TXN_ISOLATION连接属性的SQLSetConnectAttr()函数进行设置的。另外，也可以通过指定DB2CLI.INI配置文件中的TXNISOLATION关键字的值来设置ODBC/CLI应用程序的隔离级别；但是，这种方法不够灵活，不能像第一种方法那样为一个应用程序中的不同事务修改隔离级别。</p>
<p>●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于Java数据库连接(JDBC)和SQLJ应用程序，隔离级别是在应用程序运行时通过调用DB2的JAVA.SQL连接接口中的&#8220;setTransactionIsolation()&#8221;方法设置的。 </p>
<p>当没有使用这些方法显式指定应用程序的隔离级别时，默认使用游标稳定性(CS)隔离级别。这个默认设置被应用于从命令行处理程序(CLP)执行的DB2 命令、SQL语句和脚本，以及嵌入式SQL、ODBC/CLI、JDBC和SQLJ应用程序。因此，也可以为从CLP执行的操作(以及传递给DB2 CLP进行处理的脚本)指定隔离级别。在这种情况下，隔离级别是通过在建立数据库连接之前在CLP中执行CHANGE ISOLATION命令设置的，输出结果如下：</p>
<p align=left>C:\pp&gt;db2 change isolation to ur</p>
<p align=left>DB21027E&nbsp; 当连接至数据库时未能更改隔离级别。</p>
<p align=left>C:\pp&gt;db2 connect reset</p>
<p align=left>DB20000I&nbsp; SQL命令成功完成。</p>
<p align=left>C:\pp&gt;db2 change isolation to ur</p>
<p align=left>DB21053W&nbsp; 当连接至不支持 UR 的数据库时，会发生自动升级。</p>
<p align=left>DB20000I&nbsp; CHANGE ISOLATION命令成功完成。</p>
<p>在DB2 V7.1及更高版本中，能够指定特定查询所用的隔离级别，方法是在SELECT SQL语句中加上WITH [RR | RS | CS | UR]子句。大家可以看到，本章前面的示例均使用这种方法举例。</p>
<!-- page -->
<img src ="http://www.cppblog.com/prayer/aggbug/109873.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-03-17 09:46 <a href="http://www.cppblog.com/prayer/archive/2010/03/17/109873.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据库中的-脏读，幻读，不可重复读</title><link>http://www.cppblog.com/prayer/archive/2010/03/17/109861.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Tue, 16 Mar 2010 16:10:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/03/17/109861.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/109861.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/03/17/109861.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/109861.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/109861.html</trackback:ping><description><![CDATA[<p>一.丢失更新<br>当两个或多个事务选择同一行，然后基于最初选定的值更新该行时，会发生丢失更新问题。每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新，这将导致数据丢失。 　　</p>
<p>e.g.事务A和事务B同时修改某行的值，</p>
<p>&nbsp;1.事务A将数值改为1并提交</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.事务B将数值改为2并提交。</p>
<p>这时数据的值为2，事务A所做的更新将会丢失。</p>
<p>&nbsp;</p>
<p>解决办法：对行加锁，只允许并发一个更新事务。</p>
<p>二.未确认的相关性（脏读）<br>　　当第二个事务选择其它事务正在更新的行时，会发生未确认的相关性问题。第二个事务正在读取的数据还没有确认并且可能由更新此行的事务所更改。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.g.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.Mary的原工资为1000, 财务人员将Mary的工资改为了8000(但未提交事务)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.Mary读取自己的工资 ,发现自己的工资变为了8000，欢天喜地！</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 3.而财务发现操作有误，回滚了事务,Mary的工资又变为了1000 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 像这样,Mary记取的工资数8000是一个脏数据。</p>
<p>&nbsp;</p>
<p>&nbsp;解决办法：如果在第一个事务提交前，任何其他事务不可读取其修改过的值，则可&nbsp; 以避免该问题。</p>
<p><br>三.不一致的分析（非重复读）<br>　　当第二个事务多次访问同一行而且每次读取不同的数据时，会发生不一致的分析问题。不一致的分析与未确认的相关性类似，因为其它事务也是正在更改第二个事务正在读取的数据。然而，在不一致的分析中，第二个事务读取的数据是由已进行了更改的事务提交的。而且，不一致的分析涉及多次（两次或更多）读取同一行，而且每次信息都由其它事务更改；因而该行被非重复读取。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在一个事务中前后两次读取的结果并不致，导致了不可重复读。</p>
<p><br>e.g.</p>
<p>1.在事务1中，Mary 读取了自己的工资为1000,操作并没有完成 </p>
<p>2.在事务2中，这时财务人员修改了Mary的工资为2000,并提交了事务.</p>
<p>3.在事务1中，Mary 再次读取自己的工资时，工资变为了2000 </p>
<p><br>解决办法：如果只有在修改事务完全提交之后才可以读取数据，则可以避免该问题。</p>
<p><br>&nbsp;四.幻像读 　　 　</p>
<p>&nbsp;　当对某行执行插入或删除操作，而该行属于某个事务正在读取的行的范围时，会发生幻像读问题。事务第一次读的行范围显示出其中一行已不复存在于第二次读或后续读中，因为该行已被其它事务删除。同样，由于其它事务的插入操作，事务的第二次或后续读显示有一行已不存在于原始读中。 </p>
<p>&nbsp;　　e.g. 目前工资为1000的员工有10人。 </p>
<p>1.事务1,读取所有工资为1000的员工。 </p>
<p>2.这时事务2向employee表插入了一条员工记录，工资也为1000 </p>
<p>3.事务1再次读取所有工资为1000的员工 共读取到了11条记录，</p>
<p>&nbsp;</p>
<p>解决办法：如果在操作事务完成数据处理之前，任何其他事务都不可以添加新数据，则可避免该问题</p>
<p><br>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/d8111/archive/2008/06/29/2595635.aspx">http://blog.csdn.net/d8111/archive/2008/06/29/2595635.aspx</a></p>
<img src ="http://www.cppblog.com/prayer/aggbug/109861.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-03-17 00:10 <a href="http://www.cppblog.com/prayer/archive/2010/03/17/109861.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>update case when then 的用法</title><link>http://www.cppblog.com/prayer/archive/2010/01/25/106390.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Mon, 25 Jan 2010 06:25:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/01/25/106390.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/106390.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/01/25/106390.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/106390.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/106390.html</trackback:ping><description><![CDATA[<div class=cnt id=blog_text>
<p>注意要加括号，在更改多个列的时候</p>
<p>&#160;</p>
<p>ALTER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proc usp_clearActiveScoreCalcCommentScore<br>as<br>begin<br>update tbForum set UltimoScore= <br>&nbsp;&nbsp; (case <br>&nbsp;&nbsp;&nbsp; when AllScore-RemainScore&lt;0 then 0<br>&nbsp;&nbsp;&nbsp; else AllScore-RemainScore<br>&nbsp;&nbsp; end),AllScore=<br>&nbsp;&nbsp; (case <br>&nbsp;&nbsp;&nbsp; when ActivityDegree&gt;=0 and ActivityDegree&lt;=300 then 250<br>&nbsp;&nbsp;&nbsp; when ActivityDegree&gt;=301 and ActivityDegree&lt;=800 then 500<br>&nbsp;&nbsp;&nbsp; when ActivityDegree&gt;=801 and ActivityDegree&lt;=2000 then 1000<br>&nbsp;&nbsp;&nbsp; when ActivityDegree&gt;=2001 and ActivityDegree&lt;=4000 then 2000<br>&nbsp;&nbsp;&nbsp; when ActivityDegree&gt;=4001 and ActivityDegree&lt;=8000 then 4500<br>&nbsp;&nbsp;&nbsp; when ActivityDegree&gt;8000 then 9000&nbsp;&nbsp; <br>&nbsp;&nbsp; end),UltimoDegree=ActivityDegree,ActivityDegree = 0<br>update tbForum set RemainScore=AllScore<br>end</p>
</div>
<img src ="http://www.cppblog.com/prayer/aggbug/106390.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-01-25 14:25 <a href="http://www.cppblog.com/prayer/archive/2010/01/25/106390.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>嵌入式SQL介绍</title><link>http://www.cppblog.com/prayer/archive/2010/01/11/105415.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Mon, 11 Jan 2010 10:14:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2010/01/11/105415.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/105415.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2010/01/11/105415.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/105415.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/105415.html</trackback:ping><description><![CDATA[<p>SQL语言是基于关系数据模型的语言，而高级语言是基于整数、实数、字符、记录、数组等数据类型，因此两者之间尚有很大差别。如：SQL语句不能直接使用指针、数组等数据结构，而高级语言一般不能直接进行集合运算。为了能在宿主语言的<br>程序中嵌入SQL语句，必须做某些规定。<br>&nbsp; 本节主要介绍嵌入式SQL的一些使用规定和使用技术。 <br>&nbsp;&nbsp; SQL语言的使用有两种方式：<br>(1)在终端交互方式下独立使用的SQL称为交互式SQL。<br>(2)嵌入到程序设计语言中（即宿主语言）使用的SQL称为嵌入式SQL。<br>&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp; 嵌入式SQL须解决下列几个问题：</p>
<p>&nbsp; (1)如何将嵌有SQL的宿主语言程序编译成可执行码（这是首要问题）。<br>&nbsp; (2)宿主语言和DBMS之间如何传递数据和信息。<br>&nbsp; (3)如何将查询结果赋值给宿主语言程序中的变量（通过游标语句）。<br>&nbsp; (4)宿主语言与SQL之间数据类型的转换问题（按系统约定转换）。</p>
<p>&nbsp; 以SQL嵌入C为例，说明实现的一般方法。</p>
<p>&nbsp;&nbsp; 如何在C中嵌入SQL？<strong>通常是以&#8220;EXEC SQL&#8221;开始，以&#8220;；&#8221;结尾。</strong><br>&nbsp;&nbsp; SQL与C之间数据的传送通过宿主变量。（即SQL中可引用的C语言变量）<br>&nbsp;&nbsp; 在SQL语句中引用宿主变量时，为了区别数据库中变量，宿主变量前须加&#8220;：&#8221;，它可与数据库中变量同名。在宿主语言语句中，宿主变量可与其它变量一样使用，不须加冒号。当宿主变量的数据类型与数据库中不一致时，由系统按约定转换。</p>
<p>&nbsp;&nbsp; 在宿主变量中，有一个系统定义的特殊变量，叫SQLCA（SQL通信区）。<strong>它是全局变量。供应用程序与DBMS之间通信用。</strong></p>
<p>&nbsp;&nbsp; EXEC&nbsp; SQL&nbsp; INCLUDE&nbsp; SQLCA</p>
<p>&nbsp;&nbsp; SQLCA中有一个分量叫SQLCODE，可表示为：SQLCA.SQLCODE. 它是一个整数，供DBMS向应用程序报告SQL语句执行情况用。</p>
<p>&nbsp;&nbsp; SQLCODE &gt; 0 ，SQL已执行，但有异常；<br>&nbsp;&nbsp; SQLCODE &lt; 0 ，SQL没执行，有错误；<br>&nbsp;&nbsp; SQLCODE = 0 ，执行成功， 无异常。 <br>&nbsp; 注：SQLCODE的值与具体含义，不同系统有所区别。&nbsp; </p>
<p>&nbsp; 允许在嵌入的SQL语句中引用宿主语言的程序变量，但有两条规定：<br>（1）引用时，这些变量前必须加&#8220;：&#8221;作为前缀，<br>以示与数据库中变量区别。<br>（2）这些&#8220;共享变量&#8221;有宿主语言的持续定义，并用SQL的DECLARE语句说明。</p>
<p>&nbsp; 例如，在C语言中说明共享变量：<br>&nbsp;&nbsp; EXEC&nbsp; SQL&nbsp; BEGIN&nbsp; DECLARE&nbsp; SECTION;/说明语句开头<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CHAR&nbsp;&nbsp; SNO [7];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CHAR&nbsp;&nbsp; GIVENSNO[7];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CHAR&nbsp;&nbsp; CNO[6];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CHAR&nbsp;&nbsp; GIVENCNO[6];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FLOAT&nbsp; GRADE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SHORT&nbsp; GRADEI;/*GRADEI是GRADE的指示变量，两者必须连用 <br>&nbsp;&nbsp; EXEC&nbsp; SQL&nbsp; END DECLARE&nbsp; SECTION;/*说明语句结束</p>
<p>&nbsp;&nbsp; SQL的集合处理方式与宿主语言单记录处理方式的协调<br>&nbsp;&nbsp; 由于SQL语句可以处理一组记录，而宿主语言语句一次只能处理一个记录，因此需要游标机制，把集合操作转换成单记录方式。</p>
<p>&nbsp; 嵌入式SQL的可执行语句内容包括：嵌入式DDL、QL、DML、及DCL语句，进入数据库的CONNECT语句以及控制事务结束的语句。<br>&nbsp;&nbsp; 对于SQL DDL语句，<strong>只要加上前缀标识&#8220;EXEC SQL&#8221;和结束标识&#8220;；&#8221;（对C语言），</strong>就能嵌入在宿主语言程序中使用。而SQL DML语句在嵌入使用时，要注意是否使用了游标机制。<br>&nbsp;&nbsp; 可执行语句格式：<br>&nbsp;&nbsp; EXEC SQL CONNECT :uid IDENTIFIED BY :pwd；<br>&nbsp;&nbsp; 这里uid、pwd为两个宿主变量；uid为用户标识符，pwd为用户的口令。执行CONNECT前由宿主语言程序赋值。只有当CONNECT语句执行成功后才能执行事务处理中的其它可执行语句。</p>
<p>&nbsp;&nbsp; 例：<br>&nbsp;&nbsp; EXEC SQL INSERT INTO SC (SNO, CNO, GRADE )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VALUES (:SNO, :CNO, :GRADE);<br>&nbsp;&nbsp; 功能：将一个元组插入到表SC中。<br>&nbsp;&nbsp; 插入的元组由三个宿主变量构成，由宿主语言程序赋值。&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp; 例：<br>&nbsp;&nbsp; EXEC SQL SELECT GRADE <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INTO :GRADE,:GRADEI<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM SC<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE SNO=:GIVENSNO AND CNO=:GIVENCNO;</p>
<p>&nbsp;&nbsp; 功能：查询学生成绩。<br>&nbsp;&nbsp; 如查询结果只有一个元组，可将结果直接用INTO子句对有关的宿主变量直接赋值。<br>&nbsp;&nbsp; 如查询结果超过一个元组，需在程序中开辟一个区域，存放查询的结果。该区域及其相应的数据结构称为游标。然后逐个地取出每个元组给宿主变量赋值。&nbsp;&nbsp;&nbsp; </p>
<p>嵌入式SQL的实现，有两种处理方式： </p>
<p><br>&nbsp;&nbsp; (1)扩充宿主语言的编译程序，使之能处理SQL语句；<br>&nbsp;&nbsp; (2)采用预处理方式。<br>&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp; 目前多数系统采用后一种方式。预处理方式是先用预处理程序对源程序进行扫描，识别出SQL语句，并处理成宿主语言的过程调用语句；然后再用宿主语言的编译程序把源程序编译成目标程序。</p>
<p>&nbsp;</p>
<p><br>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/prayforever/archive/2008/08/06/2778495.aspx">http://blog.csdn.net/prayforever/archive/2008/08/06/2778495.aspx</a></p>
<img src ="http://www.cppblog.com/prayer/aggbug/105415.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2010-01-11 18:14 <a href="http://www.cppblog.com/prayer/archive/2010/01/11/105415.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何降低DB2的管理表空间的高水位标记</title><link>http://www.cppblog.com/prayer/archive/2009/10/08/98110.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Thu, 08 Oct 2009 14:22:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2009/10/08/98110.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/98110.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2009/10/08/98110.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/98110.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/98110.html</trackback:ping><description><![CDATA[<p>对于DB2数据库管理（DMS）表空间的高水位标记（HWM）是指该表空间曾经使用到的最大数据页数。如果使用：db2 list tablespaces show detail，看到某个DMS表空间的已用页数低于高水位标记，则有可能通过如下方法降低高水位标记：重组表空间的某个表；或者将某个表中的数据导出，然后将它删除，重新创建该表再将数据导入。 </p>
<br>oracle中的解释<br>在oracle中，<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">高水位标记</strong>是指段至启动以来增长到的最大大小，在表中，<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">高水位标记</strong>指该表所使用的最后一个块，向表中插入数据时，<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">高水位标记</strong>会移动来标记最后使用的块，当删除数据时，<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">高水位标记</strong>不会重新设置，当oracle服务器执行全表扫描时，它会读取<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">高水位标记</strong>以下所有的块。<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">高水位标记</strong>存储在表的段头部。<br><br>&nbsp;&nbsp;&nbsp; 从上面这段定义，我们可以想象，新建两张表，向其中一张表插入一条数据，另一张插入1000万条，再删除999万条，查询这两张表，所耗费的资源显然是不同的，查询前一张表更快一些，因为它读的数据块更少。<br><br>&nbsp;&nbsp;&nbsp; 使用alter table table_name deallocate unused 或者 alter table table_name move tablespace tablespace_name可以清除<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">高水位标记</strong>。<br>
<img src ="http://www.cppblog.com/prayer/aggbug/98110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2009-10-08 22:22 <a href="http://www.cppblog.com/prayer/archive/2009/10/08/98110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>全面了解ODBC技术</title><link>http://www.cppblog.com/prayer/archive/2009/09/17/96512.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Thu, 17 Sep 2009 04:14:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2009/09/17/96512.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/96512.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2009/09/17/96512.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/96512.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/96512.html</trackback:ping><description><![CDATA[<p>目前，众多的厂商推出了行行色色的数据库系统，它们在性能、价格和应用范围上各有千秋。一个综合信息系统的各部门由于需求差异等原因，往往会存在多种数据库，它们之间的互连访问成为一个棘手的问题，特别是当用户需要从客户机端访问不同的服务器时。<br>微软提出的开放式数据库互连（Open-DataBase-Connectivity，即ODBC）成为目前一个强有力解决[本文由网站<a href="http://www.gwdq.com/">www.gwdq.com</a>公文大全<a href="http://www.gwdq.cn/">www.gwdq.cn</a>收集整理]方案，并逐步成为Windows和Macintosh平台上的标准接口，并推动了这方面的开放性和标准化。<br>一、ODBC的产生和发展<br>关系型数据库产生后很快就成为数据库系统的主流产品，由于每个DBMS厂商都有自己的一套标准，人们很早就产生了标准化的想法，于是产生了SQL，由于其语法规范逐渐为人所接受，成为RDBMS上的主导语言。最初，各数据库厂商为了解决[本文由网站<a href="http://www.gwdq.com/">www.gwdq.com</a>公文大全<a href="http://www.gwdq.cn/">www.gwdq.cn</a>收集整理]互连的问题，往往提供嵌入式SQL API，用户在客户机端要操作系统中的RDBMS时，往往要在程序中嵌入SQL语句进行预编译。由于不同厂商在数据格式、数据操作、具体实现甚至语法方面都具有不同程度的差异，所以彼此不能兼容。<br>长期以来，这种API的非规范情况令用户和RDBMS厂商都不能满意。在80年代后期，一些著名的厂商包括Oracle、Sybase、Lotus、Ingres、Informix、HP、DEC等结成了SQL Access Group（简称SAG），提出了SQL API的规范核心：调用级接口（Call Level Interface），简称CLI。<br>1991年11月，微软宣布了ODBC，次年推出可用版本。1992年2月，推出了ODBC SDK 2.0版。ODBC基于SAG的SQL CAE草案所规定的语法，共分为Core、Level 1、 Level 2三种定义，分别规范了22、16、13共51条命令，其中29条命令甚至超越了SAG CLI中原有的定义，功能强大而灵活。它还包括标准的错误代码集、标准的连接和登录DBMS方法、标准的数据类型表示等。<br>由于ODBC思想上的先进性，且没有同类的标准或产品与之竞争，它一枝独秀，推出后仅仅两三年就受到了众多厂家与用户的青睐，成为一种广为接受的标准。目前，已经有130多家独立厂商宣布了对ODBC的支持，常见的DBMS都提供了ODBC的驱动接口，这些厂商包括Oracle、Sybase、Informix、Ingres、IBM(DB/2)、DEC(RDB)、HP(ALLBASE/SQL)、Gupta、Borland(Paradox)等。目前，ODBC已经成为客户机/服务器系统中的一个重要支持技术。<br>二、ODBC的基本思想与特点<br>ODBC的基本思想是为用户提供简单、标准、透明的数据库连接的公共编程接口，开发厂商根据ODBC的标准去实现底层的驱动程序，这个驱动对用户是透明的，并允许根据不同的DBMS采用不同的技术加以优化实现，这就利于不断吸收新的技术而趋完善。<br>这同时也就是数据库驱动的思想，它很类似于Windows中打印驱动的思想。在Windows中，用户安装不同的打印驱动程序，使用同样一条打印语句或操作，就可很容易地实现在不同打印机上打印输出，而不需要了解内部的具体原理。ODBC出现以后，用户安装不同的DBMS驱动就可用同样的SQL语句实现在不同DBMS上进行同样的操作，而且无需预编译。ODBC带来了数据库连接方式的变革，如图1所示。在传统方式中，开发人员要熟悉多个DBMS及其API，一旦DBMS端出现变动，则往往导致用户端系统重新编建或者源代码的修改，这给开发和维护工作带来了很大困难。在ODBC方式中，不管底层网络环境如何，也无论采用何种DBMS，用户在程序中都使用同一套标准代码，无需逐个了解各DBMS及其API的特点，源程序不因底层的变化而重新编建或修改，从而减轻了开发维护的工作量，缩短了开发周期。<br>@@12W03500.GIF;图1 数据库连接方式的转变@@<br>概括起来，ODBC具有以下灵活的特点：<br>1. 使用户程序有很高的互操作性，相同的目标代码适用于不同的DBMS；<br>2. 由于ODBC的开放性，它为程序集成提供了便利，为客户机/服务器结构提供了技术支持；<br>3. 由于应用与底层网络环境和DBMS分开，简化了开发维护上的困难。<br>三、ODBC的体系结构和实现<br>ODBC是依靠分层结构来实现的，如此可保证其标准性和开放性。图2所示为ODBC的体系结构，它共分为四层：应用程序、驱动程序管理器、驱动程序和数据源。微软公司对ODBC规程进行了规范，它为应用层的开发者和用户提供标准的函数、语法和错误代码等，微软还提供了驱动程序管理器，它在Windows中是一个动态链接库即ODBC.DLL。驱动程序层由微软、DBMS厂商或第三开发商提供，它必须符合ODBC的规程，对于Oracle，它是O<br>本文来自: 公文大全(<a href="http://www.gwdq.com/">www.gwdq.com</a>) 详细出处参考：<a href="http://www.gwdq.com/lwzx/jsj/jsjll/146960.html">http://www.gwdq.com/lwzx/jsj/jsjll/146960.html</a><br>RA6WIN.DLL，对于SQL Server，它是SQLSRVR.DLL。</p>
<p><br>@@12W03501.GIF;图2 ODBC体系结构@@<br>下面我们详细介绍各层的功能。<br>1. 应用程序层(Application)<br>使用ODBC接口的应用程序可执行以下任务：<br>①请求与数据源的连接和会话(SQLConnect)；<br>②向数据源发送SQL请求(SQLExecDirct或SQLExecute)；<br>③对SQL请求的结果定义存储区和数据格式；<br>④请求结果；<br>⑤处理错误；<br>⑥如果需要，把结果返回给用户；<br>⑦对事务进行控制，请求执行或回退操作(SQLTransact)；<br>⑧终止对数据源的连接(SQLDisconnect)。<br>2. 驱动程序管理器(Driver Manager)<br>由微软提供的驱动程序管理器是带有输入库的动态连接库ODBC.DLL，其主要目的是装入驱动程序，此外还执行以下工作:<br>①处理几个ODBC初始化调用；<br>②为每一个驱动程序提供ODBC函数入口点；<br>③为ODBC调用提供参数和次序验证。<br>3. 驱动程序(Driver)<br>驱动程序是实现ODBC函数和数据源交互的DLL，当应用程序调用SQL Connect或者SQLDriver Connect函数时，驱动程序管理器装入相应的驱动程序，它对来自应用程序的ODBC函数调用进行应答，按照其要求执行以下任务:<br>①建立与数据源的连接；<br>②向数据源提交请求；<br>③在应用程序需求时，转换数据格式；<br>④返回结果给应用程序；<br>⑤将运行错误格式化为标准代码返回；<br>⑥在需要时说明和处理光标。<br>以上这些功能都是对应用程序层功能的具体实现。驱动程序的配置方式可以划分为以下两种。<br>(1)单层次(single-tier) 这种方式下，驱动程序要处理ODBC调用SQL语句，并直接操纵数据库，因此具有数据存取功能。这种配置最常见的是同一台微机之上异种数据库通过ODBC存取，如在Powerbuilder中存取XBase、Excel、Paradox等数据文件,如图3所示。@@12W03502.GIF;图3 一层配置示意图@@<br>(2)多层次(multiple-tier) 这种配置中驱动程序仅仅处理ODBC调用，而将SQL语句交给服务器执行，然后返回结果。这种情况往往是应用程序、驱动程序管理器、驱动程序驻留在客户机端，而数据源和数据存取功能放在服务器端。譬如用Foxpro或Excel存取SQL Server或Oracle上的数据,如图4所示。<br>@@12W03503.GIF;图4 二层配置示意图@@<br>有时在以上两者之间加上网关以解决[本文由网站<a href="http://www.gwdq.com/">www.gwdq.com</a>公文大全<a href="http://www.gwdq.cn/">www.gwdq.cn</a>收集整理]通信协议的转换等问题，这时驱动程序要将请求先传送给网关，如访问DEC RDB和IBM AS/400时的配置,如图5所示。<br>@@12W03504.GIF;图5 三层配置示意图@@<br>4. 数据源<br>数据源由用户想要存取的数据和它相关的操作系统、DBMS及网络环境组成。<br>四、一致性级别<br>从应用程序观点来看，最理想的情况是每个数据源和驱动程序都支持同一套ODBC函数调用和SQL语句。但是由于形形色色的DBMS在实现上有很大的差异，它们所依赖的系统和环境也各不相同，在对ODBC支持的程度上就不一致。一致性级别(Conformance Levels)建立了对众多功能的标准划分，为应用程序和驱动程序提供帮助和选择的依据。它划定了驱动程序所支持的ODBC函数和SQL语句的范围，我们可以用SQLGetInfo、SQLGetFunctions、SQLTypeInfo三个函数获知驱动程序所支持的功能集。ODBC从API和SQL语法两方面划分级别。<br>1. API的一致性<br>ODBC将函数调用划分为三级。<br>(1)核心API 它包括了与SAG的CLI相匹配的基本功能，包括：分配与释放环境、连接及语句句柄；连接到数据源；准备并执行SQL语句或立即执行SQL语句；为SQL语句和结果列中的参数分配存储器；从结果中检索数据，检索结果的信息；提交和撤消事务处理；检索错误信息。<br>(2)一级API 它包括了核心API的全部功能，比如用特定驱动程序的对话框连接到数据源；设置和查询语句值和连接选项；送部分或全部参数值；检索部分和全部结果；检索目录信息；检索关于驱动程序和数据源的信息。<br>(3)二级API 其功能包括核心和一级API的全部功能；浏览可获得的连接和可获得的数据源列表；发送参数值数组，检索结果数组；检索参数个数及参数描述；应用可卷动的光标；检索SQL语句和本机表格；检索各种目录信息；调用转换DLL。<br>2. SQL语法的一致性级别<br>从SQL方面可划分为最小的SQL语法、核心SQL语法和扩展SQL语法三个等级。<br>五、ODBC的应用与前景<br>ODBC的出现给用户描绘了一个诱人的前景，即网络中的Windows用户可以方便地访问各种数据库。现在，在微软推出的许多产品中都提供了ODBC支持，如Visal Basic 3.0、Visal C1.5、Excel 5.0、Word 6.0、FoxPro、Access等。同时其他一些应用软件和开发工具也提供了对ODBC的支持。因此用户只要安装不同的ODBC驱动程序，就可存取相应的数据库产品，而不管用户使用何种前台应用软件，也不管后台是何种数据库，这个存取的<br>本文来自: 公文大全(<a href="http://www.gwdq.com/">www.gwdq.com</a>) 详细出处参考：<a href="http://www.gwdq.com/lwzx/jsj/jsjll/146960_2.html">http://www.gwdq.com/lwzx/jsj/jsjll/146960_2.html</a><br>过程是一致的。<br>但是由于ODBC产生的时间还不长，其应用也同时存在着一些问题。首先，它的层次比较多，表现在性能上比专有的API要慢，这是其标准化和开发性所带来的必要的代价；其次，由于ODBC规定了三个层次的一致性级别，应用程序与驱动程序之间的匹配就会出现一些问题和矛盾，比如某些驱动程序支持的级别比较低，而应用程序要求的比较高；再者，由于不同的驱动程序为不同的开发商所开发，测试工作不能统一，而现有的开发和测试工具并不很完善；同时，在非SQL的数据库系统上的应用也存在一些问题。<br>微软公司将ODBC作为一项很重要的技术，它已承诺进一步改进ODBC技术，为驱动程序开发者提供更先进的开发和测试工具，还将交付系统管理和监控工具，它还将与DBMS厂商和第三方厂商建立更密切的合作，以期使驱动程序支持更高级别的一致性，并在规范化方面有所完善。目前，ODBC已为数据库供应商组织内部所认可，同时为众多应用软件厂商和第三方开发商所使用，相信随着SQL的推广和规范，用户和开发商会更加依赖于这一技术<br>本文来自: 公文大全(<a href="http://www.gwdq.com/">www.gwdq.com</a>) 详细出处参考：<a href="http://www.gwdq.com/lwzx/jsj/jsjll/146960_3.html">http://www.gwdq.com/lwzx/jsj/jsjll/146960_3.html</a><br></p>
<img src ="http://www.cppblog.com/prayer/aggbug/96512.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2009-09-17 12:14 <a href="http://www.cppblog.com/prayer/archive/2009/09/17/96512.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CLI/ODBC中的CLI是什么</title><link>http://www.cppblog.com/prayer/archive/2009/09/17/96504.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Thu, 17 Sep 2009 03:02:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2009/09/17/96504.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/96504.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2009/09/17/96504.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/96504.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/96504.html</trackback:ping><description><![CDATA[<p>CLI是Call Level Interface<br><br>关系型数据库产生后很快就成为数据库系统的主流产品，由于每个DBMS厂商都有自己的一套标准，人们很早就产生了标准化的想法，于是产生了SQL，由于其语法规范逐渐为人所接受，成为RDBMS上的主导语言。最初，各数据库厂商为了解决[本文由网站<a href="http://www.gwdq.com/">www.gwdq.com</a>公文大全<a href="http://www.gwdq.cn/">www.gwdq.cn</a>收集整理]互连的问题，往往提供嵌入式SQL API，用户在客户机端要操作系统中的RDBMS时，往往要在程序中嵌入SQL语句进行预编译。由于不同厂商在数据格式、数据操作、具体实现甚至语法方面都具有不同程度的差异，所以彼此不能兼容。<br>长期以来，这种API的非规范情况令用户和RDBMS厂商都不能满意。在80年代后期，一些著名的厂商包括Oracle、Sybase、Lotus、Ingres、Informix、HP、DEC等结成了SQL Access Group（简称SAG），<strong>提出了SQL API的规范核心：调用级接口（Call Level Interface），简称CLI。</strong><br>1991年11月，微软宣布了ODBC，次年推出可用版本。1992年2月，推出了ODBC SDK 2.0版。ODBC基于SAG的SQL CAE草案所规定的语法，共分为Core、Level 1、 Level 2三种定义，分别规范了22、16、13共51条命令，其中29条命令甚至超越了SAG CLI中原有的定义，功能强大而灵活。它还包括标准的错误代码集、标准的连接和登录DBMS方法、标准的数据类型表示等。<br>由于ODBC思想上的先进性，且没有同类的标准或产品与之竞争，它一枝独秀，推出后仅仅两三年就受到了众多厂家与用户的青睐，成为一种广为接受的标准。目前，已经有130多家独立厂商宣布了对ODBC的支持，常见的DBMS都提供了ODBC的驱动接口，这些厂商包括Oracle、Sybase、Informix、Ingres、IBM(DB/2)、DEC(RDB)、HP(ALLBASE/SQL)、Gupta、Borland(Paradox)等。目前，ODBC已经成为客户机/服务器系统中的一个重要支持技术。</p>
<p><a href="http://www.gwdq.com/lwzx/jsj/jsjll/146960.html"></a>&nbsp;</p>
<img src ="http://www.cppblog.com/prayer/aggbug/96504.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2009-09-17 11:02 <a href="http://www.cppblog.com/prayer/archive/2009/09/17/96504.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DB2 V9.1新功能：单独的ODBC 和 CLI驱动程序</title><link>http://www.cppblog.com/prayer/archive/2009/09/17/96503.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Thu, 17 Sep 2009 02:59:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2009/09/17/96503.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/96503.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2009/09/17/96503.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/96503.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/96503.html</trackback:ping><description><![CDATA[<p>产品: DB2 UDB<br>平台: 跨平台<br>版本：V9.1及以后</p>
<p><br>问题 在一台机器上运行DB2 CLI或者ODBC应用程序，必须要安装DB2运行客户端，DB2是否提供了单独的ODBC驱动程序？</p>
<p><br>解答 DB2在版本9.1以前，没有提供单独的ODBC/CLI驱动程序，如果要运行ODBC/CLI程序，您必须安装DB2的运行客户端，在DB2版本8.1补丁9以后，DB2还提供了一个轻量级的DB2运行客户端。但是没有提供单独的ODBC/CLI驱动程序。</p>
<p>从版本9.1开始，DB2提供了一个单独的ODBC/CLI驱动程序，现在，您只需安装ODBC/CLI驱动程序，就可以方便地运行您的ODBC/CLI应用程序了。通过使用单独的ODBC/CLI驱动程序，您可以将驱动程序包含在您的应用程序安装包中，使用该驱动程序，应用程序的大小，安装大小和内存需求都有所减少。</p>
<p>你可以单独安装ODBC/CLI驱动程序，驱动程序可以安装在已经包含DB2客户端的机器上，也可以在一台机器上安装多个ODBC/CLI驱动程序。</p>
<p>DB2 ODBC/CLI驱动程序需要通过ODBC驱动程序管理器加载，目前它符合ODBC 3.51标准。DB2 ODBC/CLI驱动程序提供如下功能：</p>
<p>* DB2 CLI API 运行环境<br>* ODBC API 运行环境<br>* XA API 运行环境<br>* 数据库连接功能<br>* 支持 LDAP 数据库目录<br>* 支持跟踪、日志和诊断功能<br>本文来自: IXPUB技术社区(<a href="http://www.ixpub.net/">www.ixpub.net</a>) 详细出处参考：<a href="http://www.ixpub.net/thread-855959-1-1.html">http://www.ixpub.net/thread-855959-1-1.html</a></p>
<img src ="http://www.cppblog.com/prayer/aggbug/96503.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2009-09-17 10:59 <a href="http://www.cppblog.com/prayer/archive/2009/09/17/96503.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ODBC</title><link>http://www.cppblog.com/prayer/archive/2009/09/17/96502.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Thu, 17 Sep 2009 02:58:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2009/09/17/96502.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/96502.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2009/09/17/96502.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/96502.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/96502.html</trackback:ping><description><![CDATA[　ODBC(Open Database Connectivity，开放数据库互连)是微软公司开放服务结构(WOSA，Windows Open Services Architecture)中有关数据库的一个组成部分，它建立了一组规范，并提供了一组对数据库访问的标准API（应用程序编程接口）。这些API利用SQL来完成其大部分任务。ODBC本身也提供了对SQL语言的支持，用户可以直接将SQL语句送给ODBC。<br>
<div class=spctrl></div>
　　一个基于ODBC的应用程序对数据库的操作不依赖任何DBMS，不直接与DBMS打交道，所有的数据库操作由对应的DBMS的ODBC驱动程序完成。也就是说，不论是FoxPro、Access , MYSQL还是Oracle数据库，均可用ODBC API进行访问。由此可见，ODBC的最大优点是能以统一的方式处理所有的数据库。<br>
<div class=spctrl></div>
　　一个完整的ODBC由下列几个部件组成：<br>
<div class=spctrl></div>
　　应用程序(Application)。<br>
<div class=spctrl></div>
　　ODBC管理器(Administrator)。该程序位于Windows 95控制面板(Control Panel)的32位ODBC内，其主要任务是管理安装的ODBC驱动程序和管理数据源。<br>
<div class=spctrl></div>
　　驱动程序管理器(Driver Manager)。驱动程序管理器包含在ODBC32.DLL中，对用户是透明的。其任务是管理ODBC驱动程序，是ODBC中最重要的部件。<br>
<div class=spctrl></div>
　　ODBC API。<br>
<div class=spctrl></div>
　　ODBC 驱动程序。是一些DLL，提供了ODBC和数据库之间的接口。<br>
<div class=spctrl></div>
　　数据源。数据源包含了数据库位置和数据库类型等信息，实际上是一种数据连接的抽象。<br>
<div class=spctrl></div>
　　各部件之间的关系如图下图所示：<br>
<div class=spctrl></div>
　　应用程序要访问一个数据库，首先必须用ODBC管理器注册一个数据源，管理器根据数据源提供的数据库位置、数据库类型及ODBC驱动程序等信息，建立起ODBC与具体数据库的联系。这样，只要应用程序将数据源名提供给ODBC，ODBC就能建立起与相应数据库的连接。<br>
<div class=spctrl></div>
　　在ODBC中，ODBC API不能直接访问数据库，必须通过驱动程序管理器与数据库交换信息。驱动程序管理器负责将应用程序对ODBC API的调用传递给正确的驱动程序，而驱动程序在执行完相应的操作后，将结果通过驱动程序管理器返回给应用程序。<br>
<div class=spctrl></div>
　　在访问ODBC数据源时需要ODBC驱动程序的支持。用Visual C++ 5.0安装程序可以安装SQL Server、 Access、 Paradox、 dBase、 FoxPro、 Excel、 Oracle 和Microsoft Text等驱动程序．在缺省情况下，VC5.0只会安装SQL Server、 Access、 FoxPro和dBase的驱动程序．如果用户需要安装别的驱动程序，则需要重新运行VC 5.0的安装程序并选择所需的驱动程序。 <br>
<div class=spctrl></div>
　　ODBC 使用层次的方法来管理数据库，在数据库通信结构的每一层，对可能出现依赖数据库产品自身特性的地方，ODBC 都引入一个公共接口以解决潜在的不一致性，从而很好地解决了基于数据库系统应用程序的相对独立性，这也是ODBC 一经推出就获得巨大成功的重要原因之一。 <br>
<div class=spctrl></div>
　　从结构上分，ODBC 分为单束式和多束式两类。 <br>
<div class=spctrl></div>
　　1.单束式驱动程序 <br>
<div class=spctrl></div>
　　单束式驱动程序介于应用程序和数据库之间，像中介驱动程序一样数据提供一个统一的数据访问方式。当用户进行数据库操作时，应用程序传递一个ODBC 函数调用给ODBC 驱动程序管理器，由ODBC API 判断该调用是由它直接处理并将结果返回还是送交驱动程序执行并将结果返回。由上可见，单束式驱动程序本身是一个数据库引擎，由它直接可完成对数据库的操作，尽管该数据库可能位于网络的任何地方。 <br>
<div class=spctrl></div>
　　2.多束式驱动程序 <br>
<div class=spctrl></div>
　　多束式驱动程序负责在数据库引擎和客户应用程序之间传送命令和数据，它本身并不执行数据处理操作而用于远程操作的网络通信协议的一个界面。前端应用程序提出对数据库处理的请求，该请求转给ODBC 驱动程序管理器，驱动程序管理器依据请求的情况，就地完成或传给多束驱动程序，多束式驱动程序将请求翻译为特定厂家的数据库通信接口（如Oracle 的SQLNet）所能理解的形式并交于接口去处理，接口把请求经网络传送给服务器上的数据引擎，服务器处理完后把结果发回给数据库通信接口，数据库接口将结果传给多束式ODBC 驱动程序，再由驱动程序将结果传给应用程序。<br>
<img src ="http://www.cppblog.com/prayer/aggbug/96502.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2009-09-17 10:58 <a href="http://www.cppblog.com/prayer/archive/2009/09/17/96502.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle数据库中序列用法讲解(1)</title><link>http://www.cppblog.com/prayer/archive/2009/08/18/93714.html</link><dc:creator>Prayer</dc:creator><author>Prayer</author><pubDate>Tue, 18 Aug 2009 09:55:00 GMT</pubDate><guid>http://www.cppblog.com/prayer/archive/2009/08/18/93714.html</guid><wfw:comment>http://www.cppblog.com/prayer/comments/93714.html</wfw:comment><comments>http://www.cppblog.com/prayer/archive/2009/08/18/93714.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/prayer/comments/commentRss/93714.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/prayer/services/trackbacks/93714.html</trackback:ping><description><![CDATA[<p>序列(SEQUENCE)是序列号生成器，可以为表中的行自动生成序列号，产生一组等间隔的数值(类型为数字)。其主要的用途是生成表的主键值，可以在插入语句中引用，也可以通过查询检查当前值，或使序列增至下一个值。</p>
<p>创建序列需要CREATE SEQUENCE系统权限。序列的创建语法如下：</p>
<p>CREATE SEQUENCE 序列名</p>
<p>[INCREMENT BY n]</p>
<p>[START WITH n]</p>
<p>[{MAXVALUE/ MINVALUE n|NOMAXVALUE}]</p>
<p>[{CYCLE|NOCYCLE}]</p>
<p>[{CACHE n|NOCACHE}];</p>
<p>INCREMENT BY 用于定义序列的步长，如果省略，则默认为1，如果出现负值，则代表序列的值是按照此步长递减的。</p>
<p>START WITH 定义序列的初始值(即产生的第一个值)，默认为1。</p>
<p>MAXVALUE 定义序列生成器能产生的最大值。选项NOMAXVALUE是默认选项，代表没有最大值定义，这时对于递增序列，系统能够产生的最大值是10的27次方;对于递减序列，最大值是-1。</p>
<p>MINVALUE定义序列生成器能产生的最小值。选项NOMAXVALUE是默认选项，代表没有最小值定义，这时对于递减序列，系统能够产生的最小值是?10的26次方;对于递增序列，最小值是1。</p>
<p>CYCLE和NOCYCLE 表示当序列生成器的值达到限制值后是否循环。CYCLE代表循环，NOCYCLE代表不循环。如果循环，则当递增序列达到最大值时，循环到最小值;对于递减序列达到最小值时，循环到最大值。如果不循环，达到限制值后，继续产生新值就会发生错误。</p>
<p>CACHE(缓冲)定义存放序列的内存块的大小，默认为20。NOCACHE表示不对序列进行内存缓冲。对序列进行内存缓冲，可以改善序列的性能。</p>
<p>删除序列的语法是：</p>
<p>DROP SEQUENCE 序列名;</p>
<p>其中：</p>
<p>删除序列的人应该是序列的创建者或拥有DROP ANY SEQUENCE系统权限的用户。序列一旦删除就不能被引用了。</p>
<p>序列的某些部分也可以在使用中进行修改，但不能修改SATRT WITH选项。对序列的修改只影响随后产生的序号，已经产生的序号不变。修改序列的语法如下：</p>
<p>创建和删除序列</p>
<p>例1：创建序列：</p>
<p>CREATE SEQUENCE ABC INCREMENT BY 1 START WITH 10 MAXVALUE 9999999 NOCYCLE NOCACHE;</p>
<p>执行结果</p>
<p>序列已创建。</p>
<img src ="http://www.cppblog.com/prayer/aggbug/93714.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/prayer/" target="_blank">Prayer</a> 2009-08-18 17:55 <a href="http://www.cppblog.com/prayer/archive/2009/08/18/93714.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>