<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_兰斌专栏</title><subtitle type="text">Be the change you want to see in the world.Things are always as hard as you think but always as easy as you do.</subtitle><id>http://feed.cnblogs.com/blog/u/15696/rss</id><updated>2012-02-01T01:20:10Z</updated><author><name> 小笨笨</name><uri>http://www.cnblogs.com/fxb248/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fxb248/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/15696/rss"/><entry><id>http://www.cnblogs.com/fxb248/archive/2012/01/06/2314696.html</id><title type="text">数据库隔离等级</title><summary type="text">介绍SQL SERVER的隔离等级</summary><published>2012-01-06T07:36:00Z</published><updated>2012-01-06T07:36:00Z</updated><author><name> 小笨笨</name><uri>http://www.cnblogs.com/fxb248/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fxb248/archive/2012/01/06/2314696.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fxb248/archive/2012/01/06/2314696.html"/><content type="html">&lt;p&gt;数据库隔离等级决定并发时用户读和写的行为，非常重要。用户用SELECT读取数据时会默认使用共享锁（shared lock ），修改数据时会使用排他锁（exclusive lock）。我们不能控制写数据时请求的锁和锁数据持续的时间，但是幸运的是，我们可以控制读数据时的行为，从而来影响写数据的行为。&lt;/p&gt;&#xD;
&lt;p&gt;从SQL SERVER 2005开始，有6个隔离等级，分别是READ UNCOMMITTED, READ COMMITTED (default), REPEATABLE READ, SERIALIZABLE, SNAPSHOT和READ COMMITTED SNAPSHOT，其中，最后两个是2005新增的隔离等级。&lt;/p&gt;&#xD;
&lt;p&gt;设置隔离等级的语法大致如下：&lt;/p&gt;&#xD;
&lt;p&gt;SET TRANSACTION ISOLATION LEVEL &amp;lt;isolation name&amp;gt;。&lt;/p&gt;&#xD;
&lt;p&gt;SELECT ... FROM &amp;lt;table&amp;gt; WITH (&amp;lt;isolationname&amp;gt;);&lt;/p&gt;&#xD;
&lt;p&gt;第二种语法注意是不能有空格的，比如WITH (REPEATABLEREAD)，还有特定于这种语法使用的：NOLOCK=READUNCOMMITTED; HOLDLOCK=REPEATABLEREAD。&lt;/p&gt;&#xD;
&lt;p&gt;所有隔离等级从本质上来说是通过控制共享锁来达到各自的目的。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;READ UNCOMMITTED&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;最低的一个隔离等级。在读取数据时不会请求共享锁。这样，就可以直接读取被排他锁锁住的数据，并发性最好。&lt;/p&gt;&#xD;
&lt;p&gt;这个等级会造成脏读，举例如下：&lt;/p&gt;&#xD;
&lt;p&gt;输入下面的脚本：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;BEGIN&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;TRAN&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;UPDATE&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SET&lt;/span&gt;&amp;nbsp;unitprice&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;unitprice&amp;nbsp;&lt;span style="color: #808080"&gt;+&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;1.00&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;productid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;&amp;nbsp;productid,&amp;nbsp;unitprice&lt;br /&gt;&lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;productid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;如上所示，事物还未关闭，unitprice已经被更新为20，这时再打开一个连接，输入下面的脚本：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;SET&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;TRANSACTION&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;ISOLATION&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;LEVEL&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;READ&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;UNCOMMITTED&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;&amp;nbsp;productid,&amp;nbsp;unitprice&lt;br /&gt;&lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;productid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;首先把隔离等级设为READ UNCOMMITTED，然后查询数据，查出来的值为20。&lt;/p&gt;&#xD;
&lt;p&gt;这时，假如对第一个连接中的事务进行回滚：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;ROLLBACK&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;TRAN&lt;/span&gt;;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;更新动作被取消，数据库中的实际值还是19，连接2里面读到的值就是脏读的结果。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;READ COMMITTED&lt;/strong&gt; &lt;/p&gt;&#xD;
&lt;p&gt;避免脏读的最低隔离等级，也是SQL SERVER数据库的默认隔离等级。&lt;/p&gt;&#xD;
&lt;p&gt;在这个等级中，只会读取事务已提交的数据，不会读取未提交的数据。在读取数据时会先请求在数据上加共享锁，如果有操作在更新这些数据，那么这些数据上已经有排它锁，读取必须等待排它锁释放后才能加共享锁，这样就达到了避免脏读的目的。&lt;/p&gt;&#xD;
&lt;p&gt;输入下面的脚本： &lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;BEGIN&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;TRAN&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;UPDATE&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SET&lt;/span&gt;&amp;nbsp;unitprice&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;unitprice&amp;nbsp;&lt;span style="color: #808080"&gt;+&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;1.00&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;productid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;&amp;nbsp;productid,&amp;nbsp;unitprice&lt;br /&gt;&lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;productid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;在另一个连接中输入：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;SET&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;TRANSACTION&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;ISOLATION&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;LEVEL&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;READ&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;COMMITTED&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;&amp;nbsp;productid,&amp;nbsp;unitprice&lt;br /&gt;&lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;productid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;由于第一个连接的事物还未提交或回滚，所以第二个连接必须等待，直到排它锁释放。&lt;/p&gt;&#xD;
&lt;p&gt;SELECT语句在数据上加共享锁，查完数据后就会释放锁，即使在一个事务未提交或回滚的情况下，也是如此。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;REPEATABLE READ&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;这个隔离等级可以解决不可重复读的问题。&lt;/p&gt;&#xD;
&lt;p&gt;可重复读可以考虑这样的场景，在一个事务中，从数据库读取了一个值，用于后续的判断，但是在判断之前，别的事务就把这个数据给更新成别的值，这样第一个事务中的值就不能在重复读取到了。&lt;/p&gt;&#xD;
&lt;p&gt;解决的本质是在一个事务中，当读取了数据后，并不立马释放共享锁，直到事务结束，这样可以阻止不是本事务的操作来影响数据。&lt;/p&gt;&#xD;
&lt;p&gt;输入脚本如下：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;SET&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;TRANSACTION&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;ISOLATION&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;LEVEL&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;REPEATABLE&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;READ&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;BEGIN&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;TRAN&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;&amp;nbsp;productid,&amp;nbsp;unitprice&lt;br /&gt;&lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;productid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;首先将隔离等级设为REPEATABLE READ，然后开启事务，读取了一个值。接着，在另一个连接中：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;UPDATE&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SET&lt;/span&gt;&amp;nbsp;unitprice&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;unitprice&amp;nbsp;&lt;span style="color: #808080"&gt;+&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;1.00&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;productid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;会发现，第二个连接的UPDATE动作被阻塞，因为第一个连接在数据上加的共享锁还未解除。　　　　　　　　　　　　　　　　　　&lt;/p&gt;&#xD;
&lt;p&gt;另外能避免的一个问题是丢失更新。场景是当两个事务都需要读取同一个值，然后经过业务计算来更新值。在REPEATABLE READ之下的隔离等级，最后完成的事务会赢得这场胜利。在REPEATABLE READ下，这种场景将导致死锁，从而避免了丢失更新的问题，当然，死锁也是我们要设法避免的。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;SERIALIZABLE&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;堪称堡垒级别的隔离。&lt;/p&gt;&#xD;
&lt;p&gt;REPEATABLE READ不能避免的是幻读（phantom）。因为只会在查询的数据上加锁，如果这是有别的事务INSERT了一条新的记录，这样，在事务中做第二次读取时就会读到这个新的行。&lt;/p&gt;&#xD;
&lt;p&gt;SERIALIZABLE在REPEATABLE READ保留共享锁到事务结束的基础上，还会锁定读取的结果集，从而达到避免幻读的目的。&lt;/p&gt;&#xD;
&lt;p&gt;举例：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;SET&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;TRANSACTION&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;ISOLATION&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;LEVEL&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;SERIALIZABLE&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;BEGIN&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;TRAN&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;&amp;nbsp;productid,&amp;nbsp;productname,&amp;nbsp;categoryid,&amp;nbsp;unitprice&lt;br /&gt;&lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;categoryid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;1&lt;/span&gt;;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;第二个连接：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;INSERT&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;INTO&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;(productname,&amp;nbsp;supplierid,&amp;nbsp;categoryid,&lt;br /&gt;unitprice,&amp;nbsp;discontinued)&lt;br /&gt;&lt;span style="color: #0000ff"&gt;VALUES&lt;/span&gt;(&lt;span style="color: #ff0000"&gt;'&lt;/span&gt;&lt;span style="color: #ff0000"&gt;Product&amp;nbsp;ABCDE&lt;/span&gt;&lt;span style="color: #ff0000"&gt;'&lt;/span&gt;,&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;1&lt;/span&gt;,&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;1&lt;/span&gt;,&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;20.00&lt;/span&gt;,&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;0&lt;/span&gt;);&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;可以看到，第二个连接执行的INSERT被阻塞，直到第一个连接中的事务完成才能新增数据。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;SNAPSHOT&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;SQL SERVER 2005引进了把事务提交前的数据版本保存到tempdb的能力。基于这个能力，新增了两个隔离等级。&lt;/p&gt;&#xD;
&lt;p&gt;要开启这个，需要执行下面的语句：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;ALTER&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;DATABASE&lt;/span&gt;&amp;nbsp;XXX&amp;nbsp;&lt;span style="color: #0000ff"&gt;SET&lt;/span&gt;&amp;nbsp;ALLOW_SNAPSHOT_ISOLATION&amp;nbsp;&lt;span style="color: #0000ff"&gt;ON&lt;/span&gt;;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;第一个连接：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;BEGIN&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;TRAN&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;UPDATE&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SET&lt;/span&gt;&amp;nbsp;unitprice&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;unitprice&amp;nbsp;&lt;span style="color: #808080"&gt;+&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;1.00&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;productid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;&amp;nbsp;productid,&amp;nbsp;unitprice&lt;br /&gt;&lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;productid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;第二个连接：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;SET&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;TRANSACTION&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;ISOLATION&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;LEVEL&lt;/span&gt;&amp;nbsp;SNAPSHOT;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;BEGIN&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;TRAN&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;&amp;nbsp;productid,&amp;nbsp;unitprice&lt;br /&gt;&lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;productid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;第二个连接都到的值就是已提交的最后一个版本，也就是19。即使第一个连接中的事务提交，只要第二个连接中还是这个事务中去做查询，读到的值始终是19，而不会是20。如果在第二个连接中开启一个新的事务，那么读到的值才是20。原来tempdb中的19也就不再需要了，会有一个一分钟启动一次的清理线程从tempdb中清理掉这个过时版本。&lt;/p&gt;&#xD;
&lt;p&gt;SNAPSHOT能避免更新冲突，比如在第一个连接中取unitprice的值，是19，然后更新unitprice为20，如果没有别的事务来搀和，这个是成功的。现在假设在第一个连接读取了unitprice值后，由另外一个连接对unitprice做了更新，然后第一个连接去更新unitprice值，报：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;Msg&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;3960&lt;/span&gt;,&amp;nbsp;&lt;span style="color: #0000ff"&gt;Level&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;16&lt;/span&gt;,&amp;nbsp;State&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;,&amp;nbsp;Line&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;1&lt;/span&gt;&lt;br /&gt;Snapshot&amp;nbsp;&lt;span style="color: #0000ff"&gt;isolation&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;transaction&lt;/span&gt;&amp;nbsp;aborted&amp;nbsp;due&amp;nbsp;&lt;span style="color: #0000ff"&gt;to&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;update&lt;/span&gt;&amp;nbsp;conflict.&amp;nbsp;You&amp;nbsp;cannot&amp;nbsp;&lt;span style="color: #0000ff"&gt;use&lt;/span&gt;&amp;nbsp;snapshot&lt;br /&gt;&lt;span style="color: #0000ff"&gt;isolation&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;to&lt;/span&gt;&amp;nbsp;access&amp;nbsp;&lt;span style="color: #0000ff"&gt;table&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff0000"&gt;'&lt;/span&gt;&lt;span style="color: #ff0000"&gt;Production.Products&lt;/span&gt;&lt;span style="color: #ff0000"&gt;'&lt;/span&gt;&amp;nbsp;directly&amp;nbsp;&lt;span style="color: #808080"&gt;or&lt;/span&gt;&amp;nbsp;indirectly&amp;nbsp;&lt;span style="color: #808080"&gt;in&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;database&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff0000"&gt;'&lt;/span&gt;&lt;span style="color: #ff0000"&gt;TSQLFundamentals2008&lt;/span&gt;&lt;span style="color: #ff0000"&gt;'&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;to&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;update&lt;/span&gt;,&amp;nbsp;&lt;span style="color: #0000ff"&gt;delete&lt;/span&gt;,&amp;nbsp;&lt;span style="color: #808080"&gt;or&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;insert&lt;/span&gt;&amp;nbsp;the&amp;nbsp;row&amp;nbsp;that&amp;nbsp;has&amp;nbsp;been&amp;nbsp;modified&amp;nbsp;&lt;span style="color: #808080"&gt;or&lt;/span&gt;&lt;br /&gt;deleted&amp;nbsp;&lt;span style="color: #0000ff"&gt;by&lt;/span&gt;&amp;nbsp;another&amp;nbsp;&lt;span style="color: #0000ff"&gt;transaction&lt;/span&gt;.&amp;nbsp;Retry&amp;nbsp;the&amp;nbsp;&lt;span style="color: #0000ff"&gt;transaction&lt;/span&gt;&amp;nbsp;&lt;span style="color: #808080"&gt;or&lt;/span&gt;&amp;nbsp;change&amp;nbsp;the&amp;nbsp;&lt;span style="color: #0000ff"&gt;isolation&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;level&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;for&lt;/span&gt;&amp;nbsp;the&lt;br /&gt;&lt;span style="color: #0000ff"&gt;update&lt;/span&gt;&lt;span style="color: #808080"&gt;/&lt;/span&gt;&lt;span style="color: #0000ff"&gt;delete&lt;/span&gt;&amp;nbsp;statement.&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;br /&gt;　　&lt;strong&gt;READ COMMITTED SNAPSHOT &lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;也是基于数据版本。和上面一种的区别是，它会取到最后提交的版本。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;ALTER&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;DATABASE&lt;/span&gt;&amp;nbsp;XXX&amp;nbsp;&lt;span style="color: #0000ff"&gt;SET&lt;/span&gt;&amp;nbsp;READ_COMMITTED_SNAPSHOT&amp;nbsp;&lt;span style="color: #0000ff"&gt;ON&lt;/span&gt;;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;这个标志开启后，数据库默认的隔离等级就是READ_COMMITTED_SNAPSHOT。&lt;/p&gt;&#xD;
&lt;p&gt;第一个连接：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;div&gt;&lt;span style="color: #0000ff"&gt;BEGIN&lt;/span&gt;&amp;nbsp;&lt;span style="color: #0000ff"&gt;TRAN&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;UPDATE&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SET&lt;/span&gt;&amp;nbsp;unitprice&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;unitprice&amp;nbsp;&lt;span style="color: #808080"&gt;+&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;1.00&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;productid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;&amp;nbsp;productid,&amp;nbsp;unitprice&lt;br /&gt;&lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt;&amp;nbsp;Production.Products&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt;&amp;nbsp;productid&amp;nbsp;&lt;span style="color: #808080"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="font-weight: bold; color: #800000"&gt;2&lt;/span&gt;;&lt;/div&gt;&lt;/div&gt;&#xD;
&lt;p&gt;在这个连接中，值为20，但是如果开启第二个连接，查询unitprice的值，还是19。&lt;/p&gt;&#xD;
&lt;p&gt;这时我们把第一个连接的事务做COMMIT，接着在第二个连接中再次查询unitprice的值，这就是和SNAPSHOT的区别了，是20。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;最后是一张总图：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;table cellspacing="0" cellpadding="5" rules="groups" frame="hsides"&gt;&#xD;
&lt;caption&gt;&lt;strong&gt;&lt;font size="2"&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/caption&gt;&#xD;
&lt;colgroup span="7" align="left"&gt;&#xD;
&lt;col width="40"&gt;&#xD;
&lt;col width="30"&gt;&#xD;
&lt;col width="35"&gt;&#xD;
&lt;col width="60"&gt;&#xD;
&lt;col width="50"&gt;&#xD;
&lt;col width="45"&gt;&#xD;
&lt;col width="75"&gt;&lt;/colgroup&gt;&#xD;
&lt;thead&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;th  style="text-align: left" valign="top" scope="col" align="left"&gt;Isolation Level&lt;/th&gt;&#xD;
&lt;th  style="text-align: left" valign="top" scope="col" align="left"&gt;Uncommitted Reads?&lt;/th&gt;&#xD;
&lt;th  style="text-align: left" valign="top" scope="col" align="left"&gt;Non Repeatable Reads?&lt;/th&gt;&#xD;
&lt;th  style="text-align: left" valign="top" scope="col" align="left"&gt;Lost Updates?&lt;/th&gt;&#xD;
&lt;th  style="text-align: left" valign="top" scope="col" align="left"&gt;Phantom Reads?&lt;/th&gt;&#xD;
&lt;th  style="text-align: left" valign="top" scope="col" align="left"&gt;Detects Update Conflicts?&lt;/th&gt;&#xD;
&lt;th  style="text-align: left" valign="top" scope="col" align="left"&gt;Uses Row Versioning?&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&#xD;
&lt;tbody&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td  valign="top" align="left"&gt;READ UNCOMMITTED&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td  valign="top" align="left"&gt;READ COMMITTED&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td  valign="top" align="left"&gt;READ COMMITTED SNAPSHOT&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td  valign="top" align="left"&gt;REPEATABLE READ&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td  valign="top" align="left"&gt;SERIALIZABLE&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td  valign="top" align="left"&gt;SNAPSHOT&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;No&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&#xD;
&lt;td  valign="top" align="left"&gt;Yes&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/fxb248/aggbug/2314696.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fxb248/archive/2012/01/06/2314696.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/fxb248/archive/2011/01/10/1932396.html</id><title type="text">数据库连接池</title><summary type="text">数据库连接池能使应用程序重用池中的连接。如果没有连接池，每次请求连接就需要耗费额外的性能开销来打开一个新的连接。 连接池是和连接字符串精确匹配的，对名称和值之间的空格也十分敏感。如果一个连接字符串没有匹配到现有的池，那么就会创建一个新的池。 每次请求一个连接时，都会到池中查找是否有可用的连接，如果没有，就创建一个新的连接，使用后通过Dispose或Close将连接池化。如果池中的连接达到了最大值，那么请求就必须排队等待。 如果连接生存期已过，或者连接池管理程序检测到和数据库的连接已经断了，连接池管理程序将从池中移除连接。</summary><published>2011-01-10T14:29:00Z</published><updated>2011-01-10T14:29:00Z</updated><author><name> 小笨笨</name><uri>http://www.cnblogs.com/fxb248/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fxb248/archive/2011/01/10/1932396.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fxb248/archive/2011/01/10/1932396.html"/><content type="html">&lt;p&gt;数据库连接池能使应用程序重用池中的连接。如果没有连接池，每次请求连接就需要耗费额外的性能开销来打开一个新的连接。&lt;/p&gt;&#xD;
&lt;p&gt;连接池是和连接字符串精确匹配的，对名称和值之间的空格也十分敏感。如果一个连接字符串没有匹配到现有的池，那么就会创建一个新的池。&lt;/p&gt;&#xD;
&lt;p&gt;每次请求一个连接时，都会到池中查找是否有可用的连接，如果没有，就创建一个新的连接，使用后通过Dispose或Close将连接池化。如果池中的连接达到了最大值，那么请求就必须排队等待。&lt;/p&gt;&#xD;
&lt;p&gt;如果连接生存期已过，或者连接池管理程序检测到和数据库的连接已经断了，连接池管理程序将从池中移除连接。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/fxb248/aggbug/1932396.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fxb248/archive/2011/01/10/1932396.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/fxb248/archive/2010/07/22/1783007.html</id><title type="text">转载：数据库sharding（scale up to scale out）</title><summary type="text">数据库sharding</summary><published>2010-07-22T05:54:00Z</published><updated>2010-07-22T05:54:00Z</updated><author><name> 小笨笨</name><uri>http://www.cnblogs.com/fxb248/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fxb248/archive/2010/07/22/1783007.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fxb248/archive/2010/07/22/1783007.html"/><content type="html">&amp;nbsp;&amp;nbsp;&amp;nbsp; sharding是将一个大数据库按照一定规则拆分成多个小数据库的一门技术. &#xD;
&lt;p&gt;当我们的应用数据量越来越多，访问量越来越大的时候，我们会作何选择？继续提升数据库服务器的性能还是采用一项技术让数据库平滑扩展？虽然伴随着服务器的更新换代，性能越来越好，更换更加豪华的服务器能暂时解决这个问题，但是无论是从花费和可控都无法让人满意。这时数据库sharding是一个更加可行的方案。&lt;em&gt;&lt;/em&gt; &lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;常用的sharding方案有以下几种，&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;1。按功能划分（垂直切分）&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;将不同功能相关的表放到不同的数据库中，譬如将用户管理相关表放到shard 1上，将blog相关表放到shard 2上。。。这样做的好处是非常直观，当需要用户列表时，我就到shard 1上获取。。。。这样也有一个问题，当某一部分的功能其数据量或性能要求超出了可控的范围，我们就需要继续对其进行深入的sharding。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;2。按表中某一字段值的范围划分（水平切分）&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;当伴随着某一个表的数据量越来越大，以至于不能承受的时候，就需要对她进行进一步的切分。一种选择是根据key的范围来做切分，譬如userID为1-10000的放到shard 10上，userID为10000到20000的放到shanrd 11上。。。这样的扩展就是可预见的。另一种是根据某一字段值得来划分，譬如根据用户名的首字母，如果是a-d，就属于shard 20，e-h就属于shard 21。。。这样做也存在不均衡性，当某个范围超出了shard所能承受的范围就需要继续切分。还有按日期切分等等，&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;3。基于hash的切分&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;类似于memcached的key hash算法，一开始确定切分数据库的个数，通过hash取模来决定使用哪台shard。这种方法能够平均的来分配数据，但是伴随着数据量的增大，需要进行扩展的时候，这种方式无法做到在线扩容。每增加节点的时候，就需要对hash算法重新运算，数据需要重新割接。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;4。基于路由表的切分&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;前面的几种方式都是跟据应用的数据来决定操作的shard，基于路由表的切分是一种更加松散的方法。它单独维护一张路由表，根据用户的某一属性来查找路由表决定使用哪个shard，这种方式是一种更加通用的方案。譬如我们在系统中维护一张表-（用户所属省-〉shard），这样每个用户我们知道是哪个省的，去路由表查找，就知道它所在的shard。因为每次数据操作的时候都需要进行路由的查找，所以将这些内容存储到一台独立cache上是一个非常好的方式，譬如memcached。这种切分的方式同时也带来了另一个好处，当需要增加shard的时候，可以在不影响在线应用的情况下来执行，当然这也跟应用程序的架构设计相关，你的设计必须适用这种增加。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;虽然应用sharding会带来显而易见的好处，但是它也有一些固有的问题需要我们了解，这些问题大致分成以下几类，&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;1。shard的扩容&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;当当前的shard已经不能适用当前的应用需求时，就需要对shard数据库进行扩容，增加shard意味着需要对原有的shard数据进行迁移，这个过程是非常复杂，而且可能会导致数据的不一致（一边写、一边迁移）或者其他应用问题，因此扩容一般选择在凌晨等时间进行。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;2。联合多个shard的表数据查询&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;这个是shard固有的问题，当遇到这样的问题时，你需要获取各个shard的数据，然后对这些数据进行汇总，很多时候因为现在的网络速度比较发达这个问题可以几乎被忽略掉。但是如果要进行数据的分析或挖掘，shard就会存在问题，通常面对这种对于数据要求不是那么实时的情况下，可以采用将shard数据同步到汇总数据库的方案，olap可以在这台汇总数据库上进行，这就需要在每台shard上进行数据的定时同步，这增加了程序的复杂性；如果要求实时的情况下，采用sharding方案会是一个毁灭性打击。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;3。其他&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;我们现在做的系统就是采用的按照路由表切分的sharding方案，而且我们需要要求不是那么实时的汇总数据以提供数据的分析和挖掘，同时我们的基础数据都是在汇总数据库中进行管理，通过oracle的高级复制到shard节点上。在shard数据库向汇总数据库同步数据的时候，我们是通过oracle数据库的存储过程实现的，这种架构方式导致了数据库非常的复杂，同时还存在了一些其他问题，譬如同步会无缘无故的断掉。。。这就需要采用一些其他手段来维持数据的延迟一致性。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;我们的sharding还在改进，我们的shard还在增加，我们还需要不断努力使我们的应用更加高效。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;有时候觉得我们的社会就像一个巨大的多层sharding方案，中央、省（自治区）、市。。。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;-------------------------------------------------------------&lt;/p&gt;&#xD;
&lt;p&gt;还有一种数据库方案是master-slave，一台master主要负责数据的更新，然后通过高级复制等手段将数据复制到各个slave节点，slave节点负责查询。这种结构是不管master和slave都拥有全部的数据，master到slave的数据存在一定的延迟。可以跟sharding方案结合使用。&lt;/p&gt; &lt;img src="http://www.cnblogs.com/fxb248/aggbug/1783007.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/fxb248/archive/2010/07/22/1783007.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/fxb248/archive/2007/02/13/649630.html</id><title type="text">关于VS2005内置web服务器和IIS的区别问题(讨论,收集)</title><summary type="text">关于使用VS2005内置服务器和IIS的问题</summary><published>2007-02-13T09:51:00Z</published><updated>2007-02-13T09:51:00Z</updated><author><name> 小笨笨</name><uri>http://www.cnblogs.com/fxb248/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fxb248/archive/2007/02/13/649630.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fxb248/archive/2007/02/13/649630.html"/></entry><entry><id>http://www.cnblogs.com/fxb248/archive/2006/10/17/531079.html</id><title type="text">用SQLDMO掌握你的数据库信息</title><summary type="text">SQLDMO,一个随SQL SERVER一起发布的COM对象，你能用它执行丰富的数据库功能！</summary><published>2006-10-17T02:10:00Z</published><updated>2006-10-17T02:10:00Z</updated><author><name> 小笨笨</name><uri>http://www.cnblogs.com/fxb248/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fxb248/archive/2006/10/17/531079.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fxb248/archive/2006/10/17/531079.html"/></entry><entry><id>http://www.cnblogs.com/fxb248/archive/2006/07/26/459987.html</id><title type="text">在Linux中使用C#</title><summary type="text">让.NET在Linux上起舞</summary><published>2006-07-26T04:20:00Z</published><updated>2006-07-26T04:20:00Z</updated><author><name> 小笨笨</name><uri>http://www.cnblogs.com/fxb248/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fxb248/archive/2006/07/26/459987.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fxb248/archive/2006/07/26/459987.html"/></entry><entry><id>http://www.cnblogs.com/fxb248/archive/2006/07/20/455560.html</id><title type="text">方便你的测试（TestDriven.NET）</title><summary type="text">TestDriven.NET和NCover，NCover，NCoverExplorer的介绍和应用</summary><published>2006-07-20T06:54:00Z</published><updated>2006-07-20T06:54:00Z</updated><author><name> 小笨笨</name><uri>http://www.cnblogs.com/fxb248/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fxb248/archive/2006/07/20/455560.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fxb248/archive/2006/07/20/455560.html"/></entry><entry><id>http://www.cnblogs.com/fxb248/archive/2006/07/14/450703.html</id><title type="text">你期待已久的ASP.NET Atlas(一)[翻]</title><summary type="text">原文地址：http://msdn.microsoft.com/msdnmag/issues/06/07/AtlasAtLast/ 近来开始看Atlas，体验了一下感觉挺不错的，先翻篇文章奉上，有翻的不好甚至有误的地方请大家指正，共同提高！这篇文章讨论以下几个方面：1.ASP.NET "Atlas"的介绍2.Atlas的体系结构3.客户端和服务器端的控件4.Atlas和Web服务 在2005年9月的...</summary><published>2006-07-14T05:39:00Z</published><updated>2006-07-14T05:39:00Z</updated><author><name> 小笨笨</name><uri>http://www.cnblogs.com/fxb248/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fxb248/archive/2006/07/14/450703.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fxb248/archive/2006/07/14/450703.html"/></entry><entry><id>http://www.cnblogs.com/fxb248/archive/2006/06/23/433634.html</id><title type="text">单元测试－－爱你不容易</title><summary type="text">学习敏捷开发的时候接触到了单元测试。当时感觉这种方法真是太好了，测试功能代码是否如你想象的那样工作，可以减少以后的调试，也能给重构带来很多的方便。但现在我发现，在复杂的系统中，要做单元测试并不是那么容易的。这里我要声明一点，目前我为之写测试代码的系统基本已经开发了很久了，现在是想为方便以后的修改或重构而引入单元测试的。 我这里主要要说的是系统的耦合度一旦比较高，写测试代码让我感觉相当困难。比如我们...</summary><published>2006-06-23T03:57:00Z</published><updated>2006-06-23T03:57:00Z</updated><author><name> 小笨笨</name><uri>http://www.cnblogs.com/fxb248/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fxb248/archive/2006/06/23/433634.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fxb248/archive/2006/06/23/433634.html"/></entry><entry><id>http://www.cnblogs.com/fxb248/archive/2006/05/25/408780.html</id><title type="text">Ajax底层代码简析（可直接用的框架）</title><summary type="text">近来忙毕业设计，又很长时间没写blog了。  学ajax也有段时间了，理论是看了不少，也对MagicAjax框架做了下了解，当然要吃透它还是有很长的路要走。 一直觉得对Ajax底层的代码应该总结一下。其实很底层的代码是比较简洁明了的，但功能却比较简单。一般我们都用Send(null).以前我一直在想我怎么来控制当异步传送Http请求时要调用的后台的指定的（我想用的）代码，现在终于明白了（唉，对自己...</summary><published>2006-05-25T03:42:00Z</published><updated>2006-05-25T03:42:00Z</updated><author><name> 小笨笨</name><uri>http://www.cnblogs.com/fxb248/</uri></author><link rel="alternate" href="http://www.cnblogs.com/fxb248/archive/2006/05/25/408780.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/fxb248/archive/2006/05/25/408780.html"/></entry></feed>
