﻿<?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>BlogJava-kangdy-随笔分类-数据库</title><link>http://www.blogjava.net/kangdy/category/47815.html</link><description>我就像AK47里打出去的子弹。目标TMD永远在前方。我只能TMD拼命向前。</description><language>zh-cn</language><lastBuildDate>Wed, 30 Nov 2011 11:47:28 GMT</lastBuildDate><pubDate>Wed, 30 Nov 2011 11:47:28 GMT</pubDate><ttl>60</ttl><item><title>(转贴)数据库连接(内连接，外连接，交叉连接)</title><link>http://www.blogjava.net/kangdy/archive/2011/11/30/365223.html</link><dc:creator>AK47</dc:creator><author>AK47</author><pubDate>Wed, 30 Nov 2011 09:24:00 GMT</pubDate><guid>http://www.blogjava.net/kangdy/archive/2011/11/30/365223.html</guid><wfw:comment>http://www.blogjava.net/kangdy/comments/365223.html</wfw:comment><comments>http://www.blogjava.net/kangdy/archive/2011/11/30/365223.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kangdy/comments/commentRss/365223.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kangdy/services/trackbacks/365223.html</trackback:ping><description><![CDATA[数据库连接分为：内连接，外连接(左、右连接，全连接)，交叉连接<br />文章地址 ：&nbsp;<a href="http://www.zxbc.cn/html/20080527/51189.html">http://www.zxbc.cn/html/20080527/51189.html</a><fieldset><legend>转载&nbsp;</legend><div><div>内连接：把两个表中数据对应的数据查出来&nbsp;</div><div>外连接：以某个表为基础把对应数据查出来（全连接是以多个表为基础）&nbsp;</div><div></div><div>student表&nbsp;</div><div>no name&nbsp;</div><div>1 &nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;</div><div>2 &nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;</div><div>3 &nbsp;&nbsp;&nbsp;&nbsp;c&nbsp;</div><div>4 &nbsp;&nbsp;&nbsp;&nbsp;d&nbsp;</div><div></div><div>grade表&nbsp;</div><div>no grade&nbsp;</div><div>1 &nbsp;&nbsp;&nbsp;&nbsp;90&nbsp;</div><div>2&nbsp;&nbsp;&nbsp;&nbsp; 98&nbsp;</div><div>3 &nbsp;&nbsp;&nbsp;&nbsp;95&nbsp;</div><div></div><div>内连接 inner join（查找条件中对应的数据，no4没有数据不列出来）&nbsp;</div><div>语法：select * from student inner join grade on student.no = grade.no&nbsp;</div><div>结果&nbsp;</div><div>student.no name grade.no grade&nbsp;</div><div>1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;90&nbsp;</div><div>2 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;98&nbsp;</div><div>3 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;95&nbsp;</div><div></div><div>左连接（左表中所有数据，右表中对应数据）&nbsp;</div><div>语法：select * from student left join grade on student.no = grade.no&nbsp;</div><div>结果：&nbsp;</div><div>student.no name grade.no grade&nbsp;</div><div>1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;90&nbsp;</div><div>2 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;98&nbsp;</div><div>3 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3 &nbsp; &nbsp; &nbsp; &nbsp; 95&nbsp;</div><div>4 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div></div><div>右连接（右表中所有数据，左表中对应数据）&nbsp;</div><div>语法：select * from student right join grade on student.no = grade.no&nbsp;</div><div>结果：&nbsp;</div><div>student.no name grade.no grade&nbsp;</div><div>1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;90&nbsp;</div><div>2 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;98&nbsp;</div><div>3 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;95&nbsp;</div><div></div><div>全连接&nbsp;</div><div>语法：select * from student full join grade on student.no = grade.no&nbsp;</div><div>结果：&nbsp;</div><div>no name grade&nbsp;</div><div>1 &nbsp;&nbsp;&nbsp;&nbsp;a &nbsp;&nbsp;&nbsp;&nbsp;90&nbsp;</div><div>2 &nbsp;&nbsp;&nbsp;&nbsp;b &nbsp;&nbsp;&nbsp;&nbsp;98&nbsp;</div><div>3 &nbsp;&nbsp;&nbsp;&nbsp;c &nbsp;&nbsp;&nbsp;&nbsp;95&nbsp;</div><div>4 &nbsp;&nbsp;&nbsp;&nbsp;d&nbsp;</div><div>1 &nbsp;&nbsp;&nbsp;&nbsp;a &nbsp;&nbsp;&nbsp;&nbsp;90&nbsp;</div><div>2 &nbsp;&nbsp;&nbsp;&nbsp;b &nbsp;&nbsp;&nbsp;&nbsp;98&nbsp;</div><div>3 &nbsp;&nbsp;&nbsp;&nbsp;c &nbsp;&nbsp;&nbsp;&nbsp;95&nbsp;</div><div></div><div>注：access 中不能直接使用full join ，需要使用union all 将左连接和右连接合并后才可以</div></div></fieldset><br />交叉连接<br />将两个表所有行组合，连接后的行数为两个表行数的乘积（笛卡尔积）<br />语法，借用上面的例子应该是<br /><div>select * from student cross join grade<br /><br />行数应该为12行 ：<br /><div><div>no name grade&nbsp;</div><div>1 &nbsp; &nbsp; a &nbsp; &nbsp; 90&nbsp;</div><div>2 &nbsp; &nbsp; b &nbsp; &nbsp; 98&nbsp;</div><div>3 &nbsp;&nbsp;&nbsp;&nbsp;c &nbsp;&nbsp;&nbsp;&nbsp;95&nbsp;</div><div>4 &nbsp;&nbsp;&nbsp;&nbsp;d&nbsp;&nbsp;</div></div><div><div>1 &nbsp;&nbsp;&nbsp;&nbsp;a &nbsp;&nbsp;&nbsp;&nbsp;90&nbsp;</div><div>2 &nbsp;&nbsp;&nbsp;&nbsp;b &nbsp;&nbsp;&nbsp;&nbsp;98&nbsp;</div><div>3 &nbsp;&nbsp;&nbsp;&nbsp;c &nbsp;&nbsp;&nbsp;&nbsp;95&nbsp;</div><div>4 &nbsp;&nbsp;&nbsp;&nbsp;d&nbsp;</div></div><div><div>1 &nbsp;&nbsp;&nbsp;&nbsp;a &nbsp;&nbsp;&nbsp;&nbsp;90&nbsp;</div><div>2 &nbsp;&nbsp;&nbsp;&nbsp;b &nbsp;&nbsp;&nbsp;&nbsp;98&nbsp;</div><div>3 &nbsp;&nbsp;&nbsp;&nbsp;c &nbsp;&nbsp;&nbsp;&nbsp;95&nbsp;</div><div>4 &nbsp;&nbsp;&nbsp;&nbsp;d&nbsp;</div></div></div><img src ="http://www.blogjava.net/kangdy/aggbug/365223.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kangdy/" target="_blank">AK47</a> 2011-11-30 17:24 <a href="http://www.blogjava.net/kangdy/archive/2011/11/30/365223.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转贴)数据库三范式经典实例解析</title><link>http://www.blogjava.net/kangdy/archive/2011/02/21/344760.html</link><dc:creator>AK47</dc:creator><author>AK47</author><pubDate>Mon, 21 Feb 2011 06:45:00 GMT</pubDate><guid>http://www.blogjava.net/kangdy/archive/2011/02/21/344760.html</guid><wfw:comment>http://www.blogjava.net/kangdy/comments/344760.html</wfw:comment><comments>http://www.blogjava.net/kangdy/archive/2011/02/21/344760.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kangdy/comments/commentRss/344760.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kangdy/services/trackbacks/344760.html</trackback:ping><description><![CDATA[<p>数据库的设计范式是数据库设计所需要满足的规范，满足这些规范的数据库是简洁的、结构明晰的，同时，不会发生插入（insert）、删除（delete）和更新（update）操作异常。反之则是乱七八糟，不仅给数据库的编程人员制造麻烦，而且面目可憎，可能存储了大量不需要的冗余信息。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 设计范式是不是很难懂呢？非也，大学教材上给我们一堆数学公式我们当然看不懂，也记不住。所以我们很多人就根本不按照范式来设计数据库。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 实质上，设计范式用很形象、很简洁的话语就能说清楚，道明白。本文将对范式进行通俗地说明，并以笔者曾经设计的一个简单论坛的数据库为例来讲解怎样将这些范式应用于实际工程。<br />
<strong></strong></p>
<p><strong>范式说明</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp; 第一范式（1NF）：数据库表中的字段都是单一属性的，不可再分。这个单一属性由基本类型构成，包括整型、实数、字符型、逻辑型、日期型等。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 例如，如下的数据库表是符合第一范式： </p>
<p>
<table align="center" border="1" cellpadding="2" cellspacing="0" width="90%">
    <tbody>
        <tr>
            <td>字段1 </td>
            <td>字段2 </td>
            <td>字段3 </td>
            <td>字段4 </td>
        </tr>
        <tr>
            <td>? </td>
            <td>? </td>
            <td>? </td>
            <td>?</td>
        </tr>
    </tbody>
</table>
&nbsp;而这样的数据库表是不符合第一范式的：
<table align="center" border="1" cellpadding="2" cellspacing="0" width="90%">
    <tbody>
        <tr>
            <td>字段1 </td>
            <td>字段2 </td>
            <td colspan="2">字段3 </td>
            <td>字段4 </td>
        </tr>
        <tr>
            <td>? </td>
            <td>? </td>
            <td>字段3.1 </td>
            <td>字段3.2 </td>
            <td>?</td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;很显然，在当前的任何关系数据库管理系统（DBMS）中，傻瓜也不可能做出不符合第一范式的数据库，因为这些DBMS不允许你把数据库表的一列再分成二列或多列。因此，你想在现有的DBMS中设计出不符合第一范式的数据库都是不可能的。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 第二范式（2NF）：数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖（部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况），也即所有非关键字段都完全依赖于任意一组候选关键字。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 假定选课关系表为SelectCourse(学号, 姓名, 年龄, 课程名称, 成绩, 学分)，关键字为组合关键字(学号, 课程名称)，因为存在如下决定关系：<br />
&nbsp;&nbsp;&nbsp;&nbsp; (学号, 课程名称) &#8594; (姓名, 年龄, 成绩, 学分)<br />
&nbsp;&nbsp;&nbsp;&nbsp; 这个数据库表不满足第二范式，因为存在如下决定关系：<br />
&nbsp;&nbsp;&nbsp;&nbsp; (课程名称) &#8594; (学分)<br />
&nbsp;&nbsp;&nbsp;&nbsp; (学号) &#8594; (姓名, 年龄)<br />
即存在组合关键字中的字段决定非关键字的情况。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 由于不符合2NF，这个选课关系表会存在如下问题：<br />
&nbsp;&nbsp;&nbsp;&nbsp; (1) 数据冗余：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 同一门课程由n个学生选修，"学分"就重复n-1次；同一个学生选修了m门课程，姓名和年龄就重复了m-1次。<br />
&nbsp;&nbsp;&nbsp;&nbsp; (2) 更新异常：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 若调整了某门课程的学分，数据表中所有行的"学分"值都要更新，否则会出现同一门课程学分不同的情况。<br />
&nbsp;&nbsp;&nbsp;&nbsp; (3) 插入异常：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 假设要开设一门新的课程，暂时还没有人选修。这样，由于还没有"学号"关键字，课程名称和学分也无法记录入数据库。<br />
&nbsp;&nbsp;&nbsp;&nbsp; (4) 删除异常：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 假设一批学生已经完成课程的选修，这些选修记录就应该从数据库表中删除。但是，与此同时，课程名称和学分信息也被删除了。很显然，这也会导致插入异常。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 把选课关系表SelectCourse改为如下三个表：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 学生：Student(学号, 姓名, 年龄)；<br />
&nbsp;&nbsp;&nbsp;&nbsp; 课程：Course(课程名称, 学分)；<br />
&nbsp;&nbsp;&nbsp;&nbsp; 选课关系：SelectCourse(学号, 课程名称, 成绩)。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 这样的数据库表是符合第二范式的，消除了数据冗余、更新异常、插入异常和删除异常。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 另外，所有单关键字的数据库表都符合第二范式，因为不可能存在组合关键字。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 第三范式（3NF）：在第二范式的基础上，数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。所谓传递函数依赖，指的是如果存在"A &#8594; B &#8594; C"的决定关系，则C传递函数依赖于A。因此，满足第三范式的数据库表应该不存在如下依赖关系：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 关键字段 &#8594; 非关键字段x &#8594; 非关键字段y<br />
&nbsp;&nbsp;&nbsp;&nbsp; 假定学生关系表为Student(学号, 姓名, 年龄, 所在学院, 学院地点, 学院电话)，关键字为单一关键字"学号"，因为存在如下决定关系：<br />
&nbsp;&nbsp;&nbsp;&nbsp; (学号) &#8594; (姓名, 年龄, 所在学院, 学院地点, 学院电话)<br />
这个数据库是符合2NF的，但是不符合3NF，因为存在如下决定关系：<br />
&nbsp;&nbsp;&nbsp;&nbsp; (学号) &#8594; (所在学院) &#8594; (学院地点, 学院电话)<br />
即存在非关键字段"学院地点"、"学院电话"对关键字段"学号"的传递函数依赖。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 它也会存在数据冗余、更新异常、插入异常和删除异常的情况，读者可自行分析得知。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 把学生关系表分为如下两个表：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 学生：(学号, 姓名, 年龄, 所在学院)；<br />
&nbsp;&nbsp;&nbsp;&nbsp; 学院：(学院, 地点, 电话)。<br />
这样的数据库表是符合第三范式的，消除了数据冗余、更新异常、插入异常和删除异常。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 鲍依斯-科得范式（BCNF）：在第三范式的基础上，数据库表中如果不存在任何字段对任一候选关键字段的传递函数依赖则符合第三范式。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 假设仓库管理关系表为StorehouseManage(仓库ID, 存储物品ID, 管理员ID, 数量)，且有一个管理员只在一个仓库工作；一个仓库可以存储多种物品。这个数据库表中存在如下决定关系：<br />
&nbsp;&nbsp;&nbsp; &nbsp;(仓库ID, 存储物品ID) &#8594;(管理员ID, 数量)<br />
&nbsp;&nbsp;&nbsp;&nbsp; (管理员ID, 存储物品ID) &#8594; (仓库ID, 数量)<br />
&nbsp;&nbsp;&nbsp;&nbsp; 所以，(仓库ID, 存储物品ID)和(管理员ID, 存储物品ID)都是StorehouseManage的候选关键字，表中的唯一非关键字段为数量，它是符合第三范式的。但是，由于存在如下决定关系：<br />
&nbsp;&nbsp;&nbsp;&nbsp; (仓库ID) &#8594; (管理员ID)<br />
&nbsp;&nbsp;&nbsp;&nbsp; (管理员ID) &#8594; (仓库ID)<br />
即存在关键字段决定关键字段的情况，所以其不符合 BCNF范式。它会出现如下异常情况：<br />
&nbsp;&nbsp;&nbsp;&nbsp; (1) 删除异常：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 当仓库被清空后，所有"存储物品ID"和"数量"信息被删除的同时，"仓库ID"和"管理员ID"信息也被删除了。<br />
&nbsp;&nbsp;&nbsp;&nbsp; (2) 插入异常：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 当仓库没有存储任何物品时，无法给仓库分配管理员。<br />
&nbsp;&nbsp;&nbsp;&nbsp; (3) 更新异常：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 如果仓库换了管理员，则表中所有行的管理员ID都要修改。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 把仓库管理关系表分解为二个关系表：<br />
&nbsp;&nbsp;&nbsp;&nbsp; 仓库管理：StorehouseManage(仓库ID, 管理员ID)；<br />
&nbsp;&nbsp;&nbsp;&nbsp; 仓库：Storehouse(仓库ID, 存储物品ID, 数量)。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 这样的数据库表是符合BCNF范式的，消除了删除异常、插入异常和更新异常。<br />
<br />
<br />
原帖地址： <a href="http://www.cublog.cn/u/23975/showart.php?id=391210">http://www.cublog.cn/u/23975/showart.php?id=391210</a></p><img src ="http://www.blogjava.net/kangdy/aggbug/344760.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kangdy/" target="_blank">AK47</a> 2011-02-21 14:45 <a href="http://www.blogjava.net/kangdy/archive/2011/02/21/344760.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据库事务简介</title><link>http://www.blogjava.net/kangdy/archive/2009/11/11/301981.html</link><dc:creator>AK47</dc:creator><author>AK47</author><pubDate>Wed, 11 Nov 2009 09:23:00 GMT</pubDate><guid>http://www.blogjava.net/kangdy/archive/2009/11/11/301981.html</guid><wfw:comment>http://www.blogjava.net/kangdy/comments/301981.html</wfw:comment><comments>http://www.blogjava.net/kangdy/archive/2009/11/11/301981.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kangdy/comments/commentRss/301981.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kangdy/services/trackbacks/301981.html</trackback:ping><description><![CDATA[<p>事务就是一系列的操作,这些操作完成一项任务.只要这些操作里有一个操作没有成功,事务就操作失败,发生回滚事件.即撤消前面的操作,这样可以保证数据的一致性.而且可以把操作暂时放在缓存里,等所有操作都成功有提交数据库,这样保证费时的操作都是有效操作. <br />
如果没有特殊声明，事务就是指数据库事务简单的讲就是对数据库表的添加、删除、修改和查询操作。<br />
从编程的角度来说事务可由程序员来设置,（何时开启，何时提交，何时回滚）如果没有设置则按数据库默认自动划分事务。而事务最终在数据库上执行.所以要求数据库支持事务。</p>
<p>事务具有四个特征：原子性（ Atomicity ）、一致性（ Consistency ）、隔离性（ Isolation ）和持续性（ Durability ）。这四个特性简称为 ACID 特性。<br />
1 、原子性<br />
&nbsp;&nbsp;&nbsp; 事务是数据库的逻辑工作单位，事务中包含的各操作要么都做，要么都不做<br />
2 、一致性&nbsp; <br />
&nbsp;&nbsp;&nbsp; 事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时，就说数据库处于一致性状态。如果数据库系统 运行中发生故障，有些事务尚未完成就被迫中断，这些未完成事务对数据库所做的修改有一部分已写入物理数据库，这时数据库就处于一种不正确的状态，或者说是 不一致的状态。&nbsp; <br />
3 、隔离性<br />
&nbsp;&nbsp;&nbsp; 一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的，并发执行的各个事务之间不能互相干扰。<br />
4 、持续性<br />
&nbsp;&nbsp; 也称永久性，指一个事务一旦提交，它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。<br />
&nbsp;&nbsp; <br />
数据库系统是允许多个用户共享数据库资源，尤其是多个用户可以同时存取相同数据。（多用户同时对一个表操作也就是并发）<br />
我们主观上虽不想这么做，可是这种情况是存在的，没有原因。而并发会破坏事务ACID特性 （隔离性，一致性）。</p>
<p>并发会带来下列问题：<br />
&nbsp;脏读：一个事务读取了未提交的事务<br />
&nbsp;不可重复读：同一个事务中多次读取同一个数据返回的结果不同<br />
&nbsp;幻读：一个事务读取到了另一个事务已提交的insert数据。<br />
&nbsp;<br />
如果应用程序使用完全隔离的事务，那么同时执行多个事务的效果将与串行执行（一个接一个的顺序执行）完全等效。为解决事务之间的并发带来的个问题，必须在事务之间建立隔离关系（使用隔离级别）。</p>
<p>事务的隔离级别：就是对事务并发控制的等级，ANSI/ISO SQL将其分为串行化（SERIALIZABLE）、可重复读（REPEATABLE READ）、读已提交（READ COMMITED）、读未提交（READ UNCOMMITED）四个等级<br />
&nbsp;&nbsp;&nbsp; 1 Serializable：最严格的级别，事务串行执行，资源消耗最大；<br />
&nbsp;&nbsp;&nbsp; 2 REPEATABLE READ：读取数据的事务允许其他事务继续访问该行数据，但是未提交的写事务将会禁止其他事务访问该行。避免了&#8220;脏读取&#8221;和&#8220;不可重复读取&#8221;的情况，但是带来了更多的性能损失。<br />
&nbsp;&nbsp;&nbsp; 3 READ COMMITTED:大多数主流数据库的默认事务等级，保证了一个事务不会读到另一个并行事务已修改但未提交的数据，避免了&#8220;脏读取&#8221;。该级别适用于大多数系统。<br />
&nbsp;&nbsp;&nbsp; 4 Read Uncommitted：最低的事务隔离级别,保证了读取过程中不会读取到非法数据。<br />
<br />
<table width="500" border="0" cellpadding="2" cellspacing="2">
    <tbody>
        <tr>
            <td>&nbsp;&nbsp;&nbsp;&nbsp; 隔离级别</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;脏读</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不可重复读</td>
            <td>&nbsp;&nbsp;&nbsp; 幻读 </td>
        </tr>
        <tr>
            <td>&nbsp;&nbsp;&nbsp;&nbsp; Serializable</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;不会</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不会</td>
            <td>&nbsp;&nbsp; &nbsp;不会</td>
        </tr>
        <tr>
            <td>&nbsp;&nbsp;&nbsp;&nbsp; REPEATABLE READ</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;不会</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不会</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 会</td>
        </tr>
        <tr>
            <td>&nbsp;&nbsp;&nbsp;&nbsp; READ COMMITTED</td>
            <td>&nbsp;&nbsp;&nbsp; 不会</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 会</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;会</td>
        </tr>
        <tr>
            <td>&nbsp;&nbsp;&nbsp;&nbsp; Read Uncommitted</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 会</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 会</td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;会</td>
        </tr>
    </tbody>
</table>
&nbsp;&nbsp; <br />
数据库采用锁机制来实现事务的隔离性。</p>
<p>&nbsp;共享锁：共享锁用于读取数据操作，它允许其他事务同时读取某锁定的资源，但不允许其他事务更新它。<br />
&nbsp;排他锁：排它锁用于修改数据的场合。它锁定的资源，其他事务不能读取也不能修改。<br />
&nbsp;更新锁：更新锁在更新操作的初始化阶段用来锁定可能要被修改的资源，从而避免使用共享锁造成的死锁现象</p>
<p>常见的并发控制锁</p>
<p>http://hahalzb.blogbus.com/logs/19150842.html&nbsp;&nbsp; 心晴怡然</p>
<fieldset><legend>引用：</legend>
<p><br />
乐观锁</p>
<p>处理并发更新的一种方式是使用乐观锁（optimistic locking）。乐观锁的工作原理是让应用程序检查它即将更新的数据是否已被另一个事务修改（自该数据上次读取以来）。实现乐观锁的一种常见做法是在每个表里添加一个版本字段，每次应用程序更新数据表记录时就增加这个版本字段。每个UPDATE语句中的WHERE子句会根据上次读取的值来判断这个版本号是否改变。通过查看PreparedStatement.executeUpdate()返回的记录数，应用程序可以判断UPDATE语句是否成功。如果这条记录已被另一个事务更新或删除，应用程序可以回滚这个事务，并重新开始。<br />
在直接执行SQL语句的应用程序中，乐观锁机制的实现非常容易。不过，使用诸如JDO和Hibernate的持久层构架时，实现更为容易，因为它们已将乐观锁作为配置选项提供。一旦启用该配置选项，持久层框架会自动生成SQL UPDATE语句，执行版本检查。第12章将分析乐观锁的使用时机及其缺点，并向你展示怎样在iBATIS、JDO和Hibernate中使用乐观锁。<br />
乐观锁的名称源自如下假定情况，即并发更新的几率极小，此外应用程序并不阻止并发更新，而是检测并发更新，并从并发更新中恢复过来。另一种方式是使用悲观锁（pessimistic locking），它假定并发更新将会发生，因此必须预先阻止。</p>
<p>悲观锁</p>
<p>不同于乐观锁的另一种方式是使用悲观锁。当读取某些记录时，事务先锁住这些记录，这样可以防止其他事务访问这些数据记录。具体细节要视数据库而定，不过糟糕的是，并非所有数据库都支持悲观锁。如果数据库支持悲观锁，在直接执行SQL语句的应用程序中，实现悲观锁非常<br />
容易。然而，正如你所预料的，在JDO或Hibernate应用程序中使用悲观锁更为容易。JDO以配置选项的方式提供悲观锁，而Hibernate则提供一个简单实用的API，来锁定对象。同样，在第12章，你将学习何时使用悲观锁，分析其缺点，并看看怎样在iBATIS、JDO和Hibernate中使用悲观锁。<br />
</p>
</fieldset>
<img src ="http://www.blogjava.net/kangdy/aggbug/301981.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kangdy/" target="_blank">AK47</a> 2009-11-11 17:23 <a href="http://www.blogjava.net/kangdy/archive/2009/11/11/301981.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>