仓酷云

标题: MSSQL网页编程之SQL Server 2000+ADO.NET完成并发把持... [打印本页]

作者: 老尸    时间: 2015-1-16 22:24
标题: MSSQL网页编程之SQL Server 2000+ADO.NET完成并发把持...
对于insert和delete,event中包含了插入/删除的记录的所有字段的值(太爽了。。)ado|server|把持1并发分歧性成绩

罕见并发并发分歧性成绩包含:丧失的修正、不成反复读、读脏数据、幻影读(幻影读在一些材料中常常与不成反复读回为一类)。
1.1丧失修正

上面我们先来看一个例子,申明并发操纵带来的数据的纷歧致性成绩。
思索飞机订票体系中的一个举动序列:
了局明显卖出两张机票,数据库中机票余额只削减1。
归结起来就是:两个事件T1和T2读进统一数据并修正,T2提交的了局损坏了T1提交的了局,招致T1的修正被丧失。前文(2.1.4数据删除与更新)中提到的成绩及办理举措常常是针对此类并提问题的。但仍旧有几类成绩经由过程下面的办法办理不了,那就是:
1.2不成反复读

不成反复读是指事件T1读取数据后,事件T2实行更新操纵,使T1没法再现前一次读取了局。详细地讲,不成反复读包含三种情形:
1.3读"脏"数据

读"脏"数据是指事件T1修正某一数据,并将其写回磁盘,事件T2读取统一数据后,T1因为某种缘故原由被取消,这时候T1已修正过的数据恢回复值,T2读到的数据就与数据库中的数据纷歧致,则T2读到的数据就为"脏"数据,即不准确的数据。
发生上述三类数据纷歧致性的次要缘故原由是并发操纵损坏了事件的断绝性。并发把持就是要用准确的体例调剂并发操纵,使一个用户事件的实行不受别的事件的搅扰,从而制止形成数据的纷歧致性。
2并发分歧性成绩的办理举措

2.2.2.1封闭(Locking)

封闭是完成并发把持的一个十分主要的手艺。所谓封闭就是事件T在对某个数据工具比方表、纪录等操纵之前,先向体系收回哀求,对其加锁。加锁后事件T就对该数据工具有了必定的把持,在事件T开释它的锁之前,别的的事件不克不及更新此数据工具。
基础的封闭范例有两种:排它锁(Exclusivelocks简记为X锁)和共享锁(Sharelocks简记为S锁)。
排它锁又称为写锁。若事件T对数据工具A加上X锁,则只同意T读取和修正A,别的任何事件都不克不及再对A加任何范例的锁,直到T开释A上的锁。这就包管了别的事件在T开释A上的锁之前不克不及再读取和修正A。
共享锁又称为读锁。若事件T对数据工具A加上S锁,则别的事件只能再对A加S锁,而不克不及加X锁,直到T开释A上的S锁。这就包管了别的事件能够读A,但在T开释A上的S锁之前不克不及对A做任何修正。
2.2.2.2封闭协定

在使用X锁和S锁这两种基础封闭,对数据工具加锁时,还必要商定一些划定规矩,比方应什么时候请求X锁或S锁、持锁工夫、什么时候开释等。我们称这些划定规矩为封闭协定(LockingProtocol)。对封闭体例划定分歧的划定规矩,就构成了各类分歧的封闭协定。上面先容三级封闭协定。三级封闭协定分离在分歧水平上办理了丧失的修正、不成反复读和读"脏"数据等纷歧致性成绩,为并发操纵的准确调剂供应必定的包管。上面只给出三级封闭协定的界说,不再做过量切磋。
1级封闭协定是:事件T在修正数据R之前必需先对其加X锁,直到事件停止才开释。事件停止包含一般停止(COMMIT)和非一般停止(ROLLBACK)。1级封闭协定可避免丧失修正,并包管事件T是可恢复的。在1级封闭协定中,假如仅仅是读数据不合错误其举行修正,是不必要加锁的,以是它不克不及包管可反复读和不读"脏"数据。
2级封闭协定是:1级封闭协定加上事件T在读取数据R之前必需先对其加S锁,读完后便可开释S锁。2级封闭协定除避免了丧失修正,还可进一步避免读"脏"数据。
3级封闭协定是:1级封闭协定加上事件T在读取数据R之前必需先对其加S锁,直到事件停止才开释。3级封闭协定除避免了丧失修正和不读脏数据外,还进一步避免了不成反复读。
2.3事件断绝级别

只管数据库实际对并发分歧性成绩供应了完美的办理机制,但让程序员本人往把持怎样加锁和加锁、解锁的机会明显是很坚苦的事变。干脆尽年夜多半数据库和开辟工具都供应了事件断绝级别,让用户以一种更轻松的体例处置并发分歧性成绩。罕见的事件断绝级别包含:ReadUnCommitted、ReadCommitted、RepeatableRead和Serializable四种。分歧的断绝级别下对数据库的会见体例和数据库的前往了局有多是分歧的。我们将经由过程几个实行深切懂得事件断绝级别和SQLServer在背景是怎样将它们转换成锁的。
2.3.1ReadUnCommitted与ReadCommitted

ReadUnCommitted是最低的断绝级别,这个级其余断绝同意读进他人还没有提交的脏数据,除此以外,在这类事件断绝级别下还存在不成反复读的成绩。
ReadCommitted是很多数据库的缺省级别,这个断绝级别上,不会呈现读取未提交的数据成绩,但仍旧没法制止不成反复读(包含幻影读)的成绩。当你的体系对并发把持的请求十分严厉时,这类默许的断绝级别大概没法供应数占有效的回护,但关于决年夜多半使用来说,这类断绝级别就够用了。
我们利用上面的实行来举行测试:
起首设置SQLServer2000数据库,附加DBApp数据库。然后在VisualStudio.net中创建一办理把持台使用程序,增加需要的定名空间援用:
  1. usingSystem;usingSystem.Data;usingSystem.Data.SqlClient;usingSystem.Configuration;
复制代码
然后创建两个数据库链接,并分离接纳分歧的事件断绝级别:
  1. privatestaticSqlConnectionconn1;privatestaticSqlConnectionconn2;privatestaticSqlTransactiontx1;privatestaticSqlTransactiontx2;privatestaticvoidSetup(){conn1=newSqlConnection(connectionString);conn1.Open();tx1=conn1.BeginTransaction(IsolationLevel.ReadUncommitted);conn2=newSqlConnection(connectionString);conn2.Open();tx2=conn2.BeginTransaction(IsolationLevel.ReadCommitted);}
复制代码
个中事件1同意读进未提交的数据,而事件2只同意读进已提交数据。
在主程序中,我们摹拟两团体前后的分歧操纵,以发生并发分歧性成绩:
  1. publicstaticvoidMain(){Setup();try{ReadUnCommittedDataByTransaction1();UnCommittedUpdateByTransaction2();ReadUnCommittedDataByTransaction1();tx2.Rollback();Console.WriteLine("
  2. --Transaction2rollbacked!
  3. ");ReadUnCommittedDataByTransaction1();tx1.Rollback();}catch{……}}
复制代码
第一步,利用ReadUnCommittedDataByTransaction1办法使用事件1从数据库中读进id值为1的先生信息。此时的信息是数据库的初始信息。
第二步,挪用UnCommittedUpdateByTransaction2办法,从第2个事件中发送一UPDATE命令更新数据库,但还没有提交。
第三步,再次挪用ReadUnCommittedDataByTransaction1,处置务1中读取数据库数据,你会发明由事件2公布的还没有提交的更新被事件1读掏出来(ReadUnCommitted)。
第四步,事件2保持提交,回滚事件tx2.Rollback();。
第五步,再次挪用ReadUnCommittedDataByTransaction1();,读取数据库中的数据,此次是已回滚后的数据。
程序运转了局以下:
  1. --Readagefromdatabase:Age:20--Runanuncommittedcommand:UPDATEstudentSETage=30WHEREid=1--Readagefromdatabase:Age:30--Transaction2rollbacked!--Readagefromdatabase:Age:20
复制代码
关于ReadUnCommittedDataByTransaction1()与UnCommittedUpdateByTransaction2()的办法界说以下:
  1. privatestaticvoidUnCommittedUpdateByTransaction2(){stringcommand="UPDATEstudentSETage=30WHEREid=1";Console.WriteLine("
  2. --Runanuncommittedcommand:
  3. {0}
  4. ",command);SqlCommandcmd=newSqlCommand(command,conn2);cmd.Transaction=tx2;cmd.ExecuteNonQuery();}privatestaticvoidReadUnCommittedDataByTransaction1(){Console.WriteLine("--Readagefromdatabase:");SqlCommandcmd=newSqlCommand("SELECTageFROMstudentWHEREid=1",conn1);cmd.Transaction=tx1;try{intage=(int)cmd.ExecuteScalar();Console.WriteLine("Age:{0}",age);}catch(SqlExceptione){Console.WriteLine(e.Message);}}
复制代码
从下面的实行能够看出,在ReadUnCommitted断绝级别下,程序大概读进未提交的数据,但此断绝级别对数据库资本锁定起码。
本实行的完全代码能够从"SampleCodeChapter2Lab2-6"下找到。
让我们再来做一个实行(这个实行请求举措要快的,不然大概看不到预期效果)。起首修正下面代码中的Setup()办法代码,将
tx1=conn1.BeginTransaction(IsolationLevel.ReadUncommitted);
改成:
tx1=conn1.BeginTransaction(IsolationLevel.ReadCommitted);
再次运转代码,你会发明程序实行到第三步就不动了,假如你有充足的耐烦等下往的话,你会看到"超不时间已到。在操纵完成之前超不时间已过或服务器未呼应。"的一条提醒,这条提醒事实是甚么意义呢?让我们探察一下事实产生了甚么:
第一步,在做这个实行之前,先将SQLServer2000的企业办理器翻开,然后再将SQLServer事务探察器翻开并处于探察形态。
第二步,运转修改后的程序,程序实行到一半就停息了。此时敏捷切换到企业办理器界面,右击"办理"上面的"以后举动",选择"革新"(全部历程应在约莫15秒内完成便可,如-8所示),我们便失掉了数据库以后历程的一个快照。
MSSQL网页编程之SQL Server 2000+ADO.NET完成并发把持...
登录/注册后可看大图

-8利用企业办理器检察以后举动
我们发明此时历程呈现了堵塞,被堵塞者是52号历程,而堵塞者是53号历程。也就是说53号历程的事情妨害了52号历程持续事情。(分歧实行时历程号大概各不不异)
第三步,为了进一步查明缘故原由原形,我们切换到事务探察器窗口,看看这两个历程都是干甚么的。如-9所示,事务探察器显现了这两个历程的具体信息。从图中我们能够看出,52号历程对应我们的事件1,53号历程对应我们的事件2。事件2实行了UPDATE命令,但还没有提交,此时势务1往读还没有提交的数据便被堵塞住。从图中我们能够看出52号历程是被堵塞者。
此时假如事件2完成提交,52号历程即可以中断守候,失掉必要的了局。但是我们的程序没有提交数据,因而52号历程就要无穷等下往。所幸SQLServer2000检测到事件2的运转工夫太长(这就是下面的毛病提醒"超不时间已到。在操纵完成之前超不时间已过或服务器未呼应。"),以是将事件2回滚以开释占用的资本。资本被开释后,52号历程便得以实行。
MSSQL网页编程之SQL Server 2000+ADO.NET完成并发把持...
登录/注册后可看大图

-9事务探察器探察堵塞命令
第四步,懂得了下面产生的事变后,我们如今能够深切会商一下共享锁和排它锁的利用情形了。从头回到企业办理器界面,让我们检察一下两个历程各占用了甚么资本。从-10中我们能够看出,53号历程(事件2)在实行更新命令前对响应的键加上了排它锁(X锁),依照前文提到的1级封闭协定,该排它锁只要在事件2提交或回滚后才开释。如今52号历程(事件1)要往读统一行数据,依照2级封闭协定,它要起首对该行加共享锁,但是该行数据已被事件2加上了排它锁,因而事件1只能处于守候形态,守候排它锁被开释。因而我们就看到了后面的"堵塞"成绩。
MSSQL网页编程之SQL Server 2000+ADO.NET完成并发把持...
登录/注册后可看大图

-10历程实行写操纵前起首加了排它锁
MSSQL网页编程之SQL Server 2000+ADO.NET完成并发把持...
登录/注册后可看大图

-11历程读操纵前要加共享锁,但被堵塞
当事件1的事件断绝级别是ReadUnCommitted时,读数据是不加锁的,因而排它锁对ReadUnCommitted不起感化,历程也不会被堵塞,不外确读到了"脏"数据。
2.3.2RepeatableRead

RepeatableRead是指可反复读,它的断绝级别要比ReadCommitted级别高。它同意某事件实行反复读时数据坚持稳定,可是仍旧没法办理幻影读的成绩。为了更深切的懂得RepeatableRead所能办理的成绩,我们仍是利用上面的实行来加以印证:
第一步,事件1与事件2同时设置为ReadCommitted,并同时开启事件。
  1. privatestaticvoidSetup(){conn1=newSqlConnection(connectionString);conn1.Open();tx1=conn1.BeginTransaction(IsolationLevel.ReadCommitted);conn2=newSqlConnection(connectionString);conn2.Open();tx2=conn2.BeginTransaction(IsolationLevel.ReadCommitted);}
复制代码
第二步,事件1读取数据库中数据。注重此时并没有经由过程提交或回滚的体例停止事件1,事件1仍旧处于举动形态。
  1. privatestaticintReadAgeByTransaction1(){return(int)ExecuteScalar("SELECTageFROMstudentWHERE(id=1)");}privatestaticobjectExecuteScalar(stringcommand){Console.WriteLine("--Executecommand:{0}",command);SqlCommandcmd=newSqlCommand(command,conn1);cmd.Transaction=tx1;returncmd.ExecuteScalar();}
复制代码
第三步,事件2修正岁数数据并提交修正。
  1. privatestaticvoidModifyAgeByTransaction2(){stringcommand="UPDATEstudentSETage=30WHEREid=1";Console.WriteLine("--Modifyagebytransaction2,command:{0}",command);SqlCommandcmd=newSqlCommand(command,conn2);cmd.Transaction=tx2;try{cmd.ExecuteNonQuery();tx2.Commit();}catch(Exceptione){Console.WriteLine(e.Message);tx2.Rollback();}}
复制代码
第四步,事件1反复读取岁数数据,此时会发明读掏出来的数据是修正过的数据,与前次读取的数据纷歧样了!望文生义,不成反复读。主程序代码以下:
  1. publicstaticvoidMain(){Setup();try{intage1=ReadAgeByTransaction1();ModifyAgeByTransaction2();intage2=ReadAgeByTransaction1();Console.WriteLine("
  2. FirstRead:age={0}
  3. SecondRead:age={1}",age1,age2);}catch(Exceptione){Console.WriteLine("Gotanerror!"+e.Message);}finally{CleanUp();}}
复制代码
程序的运转了局以下:
  1. --Executecommand:SELECTageFROMstudentWHERE(id=1)--Modifyagebytransaction2,command:UPDATEstudentSETage=30WHEREid=1--Executecommand:SELECTageFROMstudentWHERE(id=1)FirstRead:age=20SecondRead:age=30
复制代码
之以是呈现了反复读时读取的数据与第一次读取的纷歧样,是由于事件1被设置成了ReadCommitted断绝范例,该断绝级别没法避免不成反复读的成绩。要想在一个事件中两次读取数据完整不异就必需利用RepeatableRead事件断绝级别。
让我们修正下面的Setup()办法中的代码,将事件1的断绝级别设置为RepeatableRead:
  1. tx1=conn1.BeginTransaction(IsolationLevel.RepeatableRead);
复制代码
再次运转该程序,你会发明程序实行到第二步就停息了,假如守候一段工夫后你就会看到"超不时间已到。在操纵完成之前超不时间已过或服务器未呼应。"的毛病提醒,此时,反复读的数据确和第一次读完整一样。程序实行了局以下:
  1. --Executecommand:SELECTageFROMstudentWHERE(id=1)--Modifyagebytransaction2,command:UPDATEstudentSETage=30WHEREid=1超不时间已到。在操纵完成之前超不时间已过或服务器未呼应。--Executecommand:SELECTageFROMstudentWHERE(id=1)FirstRead:age=20SecondRead:age=20
复制代码
为了探明缘故原由,仍是象上一个案例一样,再次实行该程序,当呈现停息时敏捷切换到企业办理器中检察以后举动的快照,并反省堵塞历程中数据锁定情形,你会发明如-12和-13所示的内容:
MSSQL网页编程之SQL Server 2000+ADO.NET完成并发把持...
登录/注册后可看大图

-12RepeatableRead在读数据时加S锁,直到事件停止才开释
MSSQL网页编程之SQL Server 2000+ADO.NET完成并发把持...
登录/注册后可看大图

-13修正数据请求加X锁,但被堵塞
依据3级封闭协定,事件T在读取数据之前必需先对其加S锁,直到事件停止才开释。因而,事件1在第一次读取数据时便对数据加上了共享锁,第一次数据读取完成后事件并未停止,因而该共享锁其实不会被开释,此时势务2试图修正该数据,依照2级封闭协定,在写之前要加排它锁,但数据上的共享锁还没有被开释,招致事件2不能不处于守候形态。当事件2守候工夫超时后,SQLServer就强迫将该事件回滚。只管事件2实行失利,但包管了事件1完成了可反复读级其余事件断绝。
RepeatableRead事件断绝级别同意事件内的反复读操纵,可是这其实不能制止呈现幻影读的成绩,假如您的程序中存在幻影读的潜伏成绩的话,就必需接纳最高的事件断绝级别:Serializable。
2.3.3Serializable

Serializable断绝级别是最高的事件断绝级别,在此断绝级别下,不会呈现读脏数据、不成反复读和幻影读的成绩。在具体申明为何之前起首让我们看看甚么是幻影读。
所谓幻影读是指:事件1按必定前提从数据库中读取某些数据纪录后,事件2拔出了一些切合事件1检索前提的新纪录,当事件1再次按不异前提读取数据时,发明多了一些纪录。让我们经由过程以下案例来重现幻影读的成绩:
第一步,将事件1和事件2均设为RepeatableRead断绝级别,并同时开启事件。
  1. privatestaticvoidSetup(){conn1=newSqlConnection(connectionString);conn1.Open();tx1=conn1.BeginTransaction(IsolationLevel.RepeatableRead);conn2=newSqlConnection(connectionString);conn2.Open();tx2=conn2.BeginTransaction(IsolationLevel.RepeatableRead);}
复制代码
第二步,事件1读取学号为1的先生的均匀成就和所学课程的门数。此时读到先生1学了3门课程,均匀成就为73.67。注重,此时势务1并未提交。
  1. privatestaticdoubleReadAverageMarksByTransaction1(){return(double)ExecuteScalar("SELECTAVG(mark)ASAvgMarkFROMSCWHERE(id=1)");}privatestaticintReadTotalCoursesByTransaction1(){return(int)ExecuteScalar("SELECTCOUNT(*)ASnumFROMSCWHERE(id=1)");}privatestaticobjectExecuteScalar(stringcommand){Console.WriteLine("--Executecommand:{0}",command);SqlCommandcmd=newSqlCommand(command,conn1);cmd.Transaction=tx1;returncmd.ExecuteScalar();}
复制代码
第三步,事件2向数据库拔出一条新纪录,让学号为1的同砚再学1门课程,成就是80。然后提交修正到数据库。
  1. privatestaticvoidInsertRecordByTransaction2(){stringcommand="INSERTINTOSCVALUES(1,5,80)";Console.WriteLine("--InserttotableSCbytransaction2");Console.WriteLine("--Command:{0}
  2. ",command);SqlCommandcmd=newSqlCommand(command,conn2);cmd.Transaction=tx2;try{cmd.ExecuteNonQuery();tx2.Commit();}catch(Exceptione){Console.WriteLine(e.Message);tx2.Rollback();}}
复制代码
第四步,事件1再次读取学号为1的先生的均匀成就和所学课程的门数。此时读到确是4门课程,均匀成就为75.25。与第一次读取的纷歧样!竟然多出了一门课程,多出的这门课程就像幻影一样呈现在我们的眼前。测试用主程序以下:
  1. publicstaticvoidMain(){Setup();try{Console.WriteLine(">>>>Step1");doubleavg=ReadAverageMarksByTransaction1();inttotal=ReadTotalCoursesByTransaction1();Console.WriteLine("avg={0,5:F2},total={1}
  2. ",avg,total);Console.WriteLine(">>>>Step2");InsertRecordByTransaction2();Console.WriteLine(">>>>Step3");avg=ReadAverageMarksByTransaction1();total=ReadTotalCoursesByTransaction1();Console.WriteLine("avg={0,5:F2},total={1}
  3. ",avg,total);}catch(Exceptione){Console.WriteLine("Gotanerror!"+e.Message);}finally{CleanUp();}}
复制代码
程序实行了局以下:
  1. >>>>Step1--Executecommand:SELECTAVG(mark)ASAvgMarkFROMSCWHERE(id=1)--Executecommand:SELECTCOUNT(*)ASnumFROMSCWHERE(id=1)avg=73.67,total=3>>>>Step2--InserttotableSCbytransaction2--Command:INSERTINTOSCVALUES(1,5,80)>>>>Step3--Executecommand:SELECTAVG(mark)ASAvgMarkFROMSCWHERE(id=1)--Executecommand:SELECTCOUNT(*)ASnumFROMSCWHERE(id=1)avg=75.25,total=4
复制代码
人人能够思索一下,为何RepeatableRead断绝形式其实不能使得两次读取的均匀值一样呢?(能够从锁的角度来注释这一征象)。
仍旧象后面的做法一样,我们看看事实产生了甚么事变。在探察之前,先将Setup办法中事件1的断绝级别设置为Serializable,再次运转程序,当发明程序运转停息时,检察数据库以后举动快照,你会发明如-14和-15所示的锁定成绩:
MSSQL网页编程之SQL Server 2000+ADO.NET完成并发把持...
登录/注册后可看大图

-14Serializable断绝形式对切合检索前提的数据增加了RangeS-S锁
MSSQL网页编程之SQL Server 2000+ADO.NET完成并发把持...
登录/注册后可看大图

-15当试图拔出切合RangeIn前提的纪录时,只能处于守候形态
从图中我们能够看出,在Serializalbe断绝形式下,数据库在检索数据时,对一切满意检索前提的纪录均加上了RangeS-S共享锁。事件2试图往拔出一满意RangeIn前提的纪录时,必需守候这些RangS-S锁开释,不然就只能处于守候形态。在守候超时后,事件2就会被SQLServer强迫回滚。
修正后的程序运转了局以下:
  1. >>>>Step1--Executecommand:SELECTAVG(mark)ASAvgMarkFROMSCWHERE(id=1)--Executecommand:SELECTCOUNT(*)ASnumFROMSCWHERE(id=1)avg=73.67,total=3>>>>Step2--InserttotableSCbytransaction2--Command:INSERTINTOSCVALUES(1,5,80)超不时间已到。在操纵完成之前超不时间已过或服务器未呼应。>>>>Step3--Executecommand:SELECTAVG(mark)ASAvgMarkFROMSCWHERE(id=1)--Executecommand:SELECTCOUNT(*)ASnumFROMSCWHERE(id=1)avg=73.67,total=3
复制代码
事件2的运转失利确保了事件1不会呈现幻影读的成绩。这里应该注重的是,1、2、3级封闭协定都不克不及包管无效办理幻影读的成绩。
2.3倡议

经由过程下面的几个例子,我们更深切的懂得了数据库在办理并发分歧性成绩时所接纳的措施。锁机制属于最底层的包管机制,但很难间接利用。我们能够经由过程分歧的事件断绝形式来直接使用锁定机制确保我们数据的完全分歧性。在利用分歧级其余断绝形式时,我们也应该注重以下一些成绩:
为了在某种程序上弥补这一缺陷,许多SQL命令都有一个DELAY_KEY_WRITE项。这个选项的作用是暂时制止MySQL在该命令每插入一条新记录和每修改一条现有之后立刻对索引进行刷新,对索引的刷新将等到全部记录插入/修改完毕之后再进行。
作者: 再见西城    时间: 2015-1-19 10:57
这是一个不错的新特性。虽然索引的附加字段没有索引键值效率高,但是相对映射到数据表中效率还是提高了很多。我做过试验,在我的实验环境中会比映射到表中提高30%左右的效率。
作者: 山那边是海    时间: 2015-1-25 14:47
一个是把SQL语句写到客户端,可以使用DataSet进行加工;
作者: 兰色精灵    时间: 2015-2-2 22:33
Mirror可以算是SQLServer的Dataguard了。但是能不能被大伙用起来就不知道了。
作者: 小女巫    时间: 2015-2-8 17:02
比如,MicrosoftSQLServer2008的某一个版本可以满足现在的这个业务的需要,而且价格还比Oracle11g要便宜,那么这一产品就是适合的。
作者: 分手快乐    时间: 2015-2-25 21:17
是要和操作系统进行Socket通讯的场景。否则建议慎重!
作者: 海妖    时间: 2015-3-8 05:00
同样会为索引视图等应用带来麻烦。看看行级和事务级的快照数据放在tempdb中,就能感觉到目前架构的尴尬。
作者: 活着的死人    时间: 2015-3-15 21:15
SP4包括用于以下SQLServer2000组件的程序包:Database组件(下载文件:SQL2000-KB884525-SP4-x86.EXE)更新SQLServer2000的32位Database组件,包括数据库引擎、复制、客户端连接组件及工具。有关其他信息,请参阅ReadmeSql2k32Sp4.htm。AnalysisServices组件(下载文件:SQL2000.AS-KB884525-SP4-x86.EXE)更新SQLServer2000的32位AnalysisServices。
作者: 若相依    时间: 2015-3-22 04:56
原理很简单,对要求长时间计算某一时间点的报表生成和防用户操作错误很有帮助。但是比起Oracle10g的闪回技术还是细粒度不够。可惜!




欢迎光临 仓酷云 (http://ckuyun.com/) Powered by Discuz! X3.2