`
bolutes
  • 浏览: 874853 次
文章分类
社区版块
存档分类
最新评论

N层研习记录01:试图通过Boolean参数控制并发冲突的检查方式(LINQ to SQL)

 
阅读更多

作者:光脚丫思考
版权所有,转载请注明出处!^_^

此研习用到的测试代码可通过以下两个地址下载,如果不能下载,请留言通知我。
下载地址01:http://download.csdn.net/source/2747401
下载地址02:http://u.115.com/file/f26716bcc2

如果你只想快速的查看测试代码的主题部分,或者想更具体的了解测试的详细记录,则可以参看另一篇名为《 N层研习中的测试代码01 》的博文,地址是:
http://blog.csdn.net/GJYSK/archive/2010/10/11/5933279.aspx

微软MSDN带来的困惑
微软的MSDN确实是个好东西,其中提供的技术资料,只要你善于去学习,必定是会受益匪浅的。毕竟,技术是微软的,它所提供的资料多多少少还是占据着一些优势的。这是值得称赞的地方。然而,MSDN也并非就是一个完美无瑕的东西,有一些不足之处某种情况下足可以让你疯狂,至少所带来的困惑足可以让你茶不思饭不想的了。呵呵,前提是你对困惑有着极强的解决欲望,否则也只能是无动于衷了!^_^
这几天我就一直被《关于如何在N层体系架构中使用LINQ to SQL进行开放式并发检查》的问题困惑着。实际上,微软在这方面所作出的说明是颇为详细的,将其中的前因后果道的是一清二楚。然而,关于如何具体的实现这些方案,MSDN所提供的代码是那么的一带而过。虽然具有高度的总结性,但当你自己想要去具体的实现这些方案的时候,便会发现事实上并非是如此的简单。没错!我的承认,微软的说明是够详细的了,但是,相对于我在测试过程中产生的接二连三的疑惑,有些确实应该披露的信息真的是没有披露出一丝一毫,于是,剩下的事情就该你自己去慢慢的琢磨思考,如果幸运的话,最终你会找到问题的答案,揭开那个困惑你的谜团。好了,现在让我们回到正题……

两种并发冲突检查方式
在N层体系架构中,LINQ to SQL提供了两种进行并发冲突检查的方式:一种是基于时间戳的方式,另一种就是基于原始值的方式。
所谓基于时间戳的方式,实际上就是在试图对数据进行更新和删除操作的时候,首先会判断所删除的那行记录的时间戳列的值是否已经发生改变。这个改变自然是相对于当前用户读取数据时的时间戳列值了。如果,在用户读取数据并进行修改,但还没有提交到数据库的这段时间里,有其他的用户对数据进行了任何的修改操作,那么,数据库都会自动更新时间戳列的值,于是,当前用户尝试用原始的时间戳值和数据库修改后的时间戳值进行比较是,自然就不会匹配,这样,就可以判断已经发生了并发冲突。如此说,可能有些晦涩,不如看看下面的这个SQL命令,此命令是LINQ to SQL所生成的。
以上的SQL代码所需要注意的是那个WHERE子句。其实,添加上这个WHERE子句,你就可以这样理解:当试图更新数据的时候,会判断CustomerID和Version的值是否和读取时是相同的。CustomerID的值自然是不会被改变的,因为它是主键列成员,在LINQ to SQL中是不允许对其进行修改的。因此,CustomerID的值保持不变。而Version的值我们当然也不会去修改。也就是说继续保留读取时的原始值。可是,这说的是在内存中的对象,而并非数据库中的时间戳列的值。如果别的用户更新了这条数据,此行数据的时间戳值必定发生改变。这样一来上面的SQL语句就不会被成功执行,因为LINQ to SQL找不到要更新的行了。于是,LINQ to SQL就认为这种情况是发生了并发冲突。
而基于原始值的方式进行并发冲突检查,则稍微要显得复杂一些,这具体可体现到所生成的SQL命令和实际的编码中。所谓的基于原始值的方式,等于是在更新和删除数据之前,几乎是对每一列的原始值和数据库当前值进行比较,如果被检查的任何一列的数据当前值和原始值是不匹配的,LINQ to SQL就认为发生了并发冲突。下面是基于原始值的方式进行并发冲突检查时,LINQ to SQL生成的SQL命令。

再看看这个WHERE子句,你就不得不佩服了。是不是几乎对每一个列都进行了比对呢?那只是一个列的数据和原始值不相同了,这个SQL语句肯定找不到要更新的行。于是乎,LINQ to SQL就认为又一次的产生了并发冲突。
以上是我对LINQ to SQL两种检查并发冲突的方式的简单说明,只是个人的理解而已。如果有什么不对的地方,还请各位给予指正!谢谢!

困惑的开始
一开始我就说过,MSDN在N层体系架构中使用LINQ to SQL进行并发冲突检查的所给出的示例代码太少。虽然你会看见有几段的代码,但太过于概括了,很多的信息都没有说明清楚。我摘录其中的一段:
删除操作涉及到开放式并发检查,并且必须首先将要删除的对象附加到新的数据上下文。在此示例中,Boolean参数设置为false,以指示该对象没有时间戳(RowVersion)。如果数据库表确实为每个记录生成了时间戳,则并发检查会简单得多(特别是对客户端而言)。 只需传入原始对象或已修改的对象,并将Boolean参数设置为true。
上面这段话是直接从MSDN上复制过来。下面是它所提供的示例代码,我稍微做了一点修改,但基本上和他原来的情况是一致的。

结合上面这段示例代码,我对从MSDN复制的那段中提到的那个Boolean参数做一些说明。实际上,它所指的就是代码中的那个Attach()方法的一个参数,这是其中的一个重载方法。不晓得,各位看到前面那个说明的时候,会是怎样理解的呢?我说说我自己的理解,大家看看,我的理解是否正确的。
如果对象有没有时间戳,就将Boolean参数设置为false,如果有的话,就设置为true。但事实上,如果你查看Attach()方法对这个参数所做的注释便会发现,此参数的重要意义并不是用来指示实体类是否有版本列成员,而是用来表示所附加的对象是否被修改。如果附加的是没有被修改的对象,那么就将其设置为false;反之,则设置为true。
我尝试着去理解是什么原因产生了这种细微的描述差异呢。幸运的是我想我知道为什么会有这样的区别。而正是因为了有这个幸运,接着就带来了一系列的困惑。先说说为什么会有这种细微的差异呢?
就以前面的示例代码做说明吧。当我们调用上面用到的的Attach()重载方法时,将对象附加给数据上下文的时候,如果Boolean参数设置为true的话,其实就是告诉数据上下文,此对象已经被修改过了。不管我们采用什么样的方式附加对象,LINQ to SQL在将修改提交到数据库的时候,都是要进行开放式并发检查的。不晓得有没有什么参数可以取消这个开放式并发检查呢?目前为止我还不知道。既然它非要进行开放式并发检查,而进行这种检查的方式,无非就只有两种:基于时间戳的方式和基于原始值的方式。这样一来如果我们照着前面的做法将对象作为已修改对象附加给数据上下文的话,肯定是没法再为其提供原始值了。即使你通过其他的方式将原始值提供给数据上下文的话,LINQ to SQL也会认为在你将对象附加的时候,有些修改它是没有跟踪到的。因为,一附加给数据上下文的时候就指示对象已被修改。因此它就会一股脑的认为对象已经被修改,且没有可跟踪的原始值。这样一来,想要使用基于原始值的方式自然是不可行了。也许LINQ to SQL正是在这种无可奈何的情况下不得不使用基于时间戳的方式。
这种推测正确吗?无论是当时,还是现在我都认为这种推测应该是合情合理的。不过也只仅限于我对MSDN的那段话的理解,事实是否如此呢?咱们后面再说。
有了上面的推测,让我自然而然地认为,到底LINQ to SQL是使用哪种方式进行开放式并发冲突检查,完全可以通过这个Boolean参数来进行控制。于是我专门编写了一个测试项目来验证自己的推测。测试的结果确实让我大大地跌破了眼镜。虽然我是不带眼镜的!^_^

测试的说明
测试用到的数据库是我自行定义的,其中的数据表都给添加了时间戳列。然后在VS中使用对象关系设计器基于这个有时间戳列的数据库生成了对象模型。在测试代码中,我就尝试着通过对Boolean参数的修改,然后跟踪LINQ to SQL所生成SQL语句来看看到底是使用了哪种方式进行开放式并发检查的。这其中分别对删除和更新这两个操作进行了测试。至于检索和增加数据则不存在开放式并发检查,因此相对而言要简单了许多。
另外,是使用WCF来做这个测试的。为了方便起见将服务端和客户端做成了两个项目,再运行客户端之前,请务必先将服务端程序启动,否则自然是无法测试的了。
测试的结果如何呢?想着当初我抓耳挠腮的情形,此时此刻我心平气和的告诉你,无论我怎么设置Boolean参数,LINQ to SQL都是一如既往的使用着基于时间戳的方式来进行开放式并发检查的。为了慎重起见,我将测试代码一遍又一遍的测试着,生怕自己在某些地方出现了纰漏,那样就直接影响我对这一问题的最终认识。然而事实却是,不行就是不行,LINQ to SQL似乎带着极度傲慢的态度告诉我:想通过设置Boolean参数就来控制我选择哪种开放式并发检查?没门!终于,我得承认,前面的推测是不成立的。于是乎,一系列困惑就开始接二连三的跑了出来。哎!过程就像是个噩梦,但结果却是让人欣喜若狂!这种感觉其实蛮好的。
至于测试的细节问题,可以从所提供的测试代码中查看,我做了详细的注释说明。测试代码可以从这里找到:
事情并没有到此结束,与之后事如何,且听下回分解!^_^咱们也学罗贯中拽一会!

分享到:
评论

相关推荐

    sql注入笔记

    SQL 注入是一种常见的 Web 应用程序漏洞,攻击者可以通过inject恶意 SQL 代码来访问、修改或控制数据库中的数据。本文将详细介绍 SQL 注入的基本概念、检测方法和防御策略。 什么是 SQL 注入? SQL 注入是一种攻击...

    检查网址URL中字符串类型及个数(ASP防注入)

    用于防范ASP非法注入 '一个用于检查网址URL中字符串类型及个数的函数,Write By Msdiy. ...'参数3: inSql SQL注入检查,boolean型; '参数4: allSame URL中必段包含查询参数名称一致性检查,boolean型。

    Boolean RT.zip

    BooleanRT, 实现2个物体间的布尔运算 The extension provides the following functions: 1- Real-time or per-click Boolean execution. 2- Material, UV and texture preservation. 3- Saving to prefab. 4- ...

    Access采用sql语句与sql的区别

    Access 采用 SQL 语句与 SQL 的区别 在讨论 Access 采用 SQL 语句与 SQL 的区别之前,我们需要了解 Access 和 SQL Server 的基本概念。Access 是一个桌面数据库管理系统,而 SQL Server 是一个关系数据库管理系统。...

    boolean2:Boolean2 是一个 Ruby 常量,它是 true 和 false 的祖先

    下次要定义全局Boolean类之前,请考虑改用这种基本方法。 设置 添加到您的Gemfile : gem 'boolean2' 用法 true . is_a? Boolean2 #=> true false . is_a? Boolean2 #=> true nil . is_a? Boolean2 #=> false ...

    On Reachability Analysis of Pushdown Systemswith Transductions: Application to Boolean Programs with Call-by-Reference

    On Reachability Analysis of Pushdown Systemswith Transductions: Application to Boolean Programs with Call-by-Reference

    Beginning Microsoft Visual CSharp 2008 Wiley Publishing(english)

    Grouping, Ordering, and Other Advanced Queries in LINQ to SQL 951 Displaying Generated SQL 954 Data Binding with LINQ to SQL 958 Updating Bound Data with LINQ to SQL 965 Summary 966 ...

    manipula:LINQ的实现

    LINQ的实现 实例 : boolean : boolean : boolean : number .distinct([比较器]) .distinctBy(keySelector,[比较器]) .elementAt(index) .elementAtOrDefault(索引) .except(第二个,[比较器...

    SQL、Hive SQL等SQL血缘解析工具

    String hql = "select id,name from (select id from table_1 where id={p0}) t1 inner join (select name --this is name\n from table_2) t2"; // 获取id字段的血缘 LineageNode idNode = Delegate.getDelegate...

    delphi通用函数单元一

    //▎============================================================▎// //▎================① 扩展的字符串操作函数 ===============... 参数: path:路径,filter:文件扩展名过滤,FileList:文件列表, ContainSubDir...

    Boolean RT资源包

    Boolean RT资源包,可用于Unity 几何体布尔运算

    isndarray:返回boolean参数是否为ndarray

    返回boolean参数是否为 。 例子 var isnd = require ( 'isndarray' ) var ndarray = require ( 'ndarray' ) true === isnd ( ndarray ( new Int8Array ( 32 * 32 ) , [ 32 , 32 ] ) ) true === isnd ( ndarray ( ...

    iBatis SQL Maps开发指南.pdf

    SQL Maps (comibatissqlmap*) SQL Map的概念 SQL Map如何工作? 安装SQL Maps JAR文件和依赖性 从1x版本升级 是否应该升级 转换XML配置文件(从1x到20) 使用新的JAR文件 SQL Map XML配置文件 元素 元素 元素 元素 ...

    SQL语言艺术

    本书分为12章,每一章包含许多原则或准则,并通过举例的方式对原则 进行解释说明。这些例子大多来自于实际案例,对九种SQL经典查询场景以 及其性能影响讨论,非常便于实践,为你的实际工作提出了具体建议。本书 适合...

    Introduction to Boolean Algebras.pdf

    Introduction to Boolean Algebras.pdf Introduction to Boolean Algebras.pdf

    PL/SQL 基础.doc

    PL/SQL 基础,一个不错的 PL/SQL 参考手册。内容预览: ---- 第一章 PL/SQL 简介 ---- 1. Oracle应用编辑方法概览 1) Pro*C/C++/... : C语言和数据库打交道的方法,比OCI更常用; 2) ODBC 3) OCI: C语言和...

    数据分析软件之FineReport教程:[5]参数界面JS(全)

    在用报表工具设计报表时,使用参数控件时,有时我们希望部分参数控件在没满足条件时不显示,满足条件后再显示,接下来我就来教教大家怎么做! 表格软件如何根据条件控制参数控件是否显示 一:问题描述 在使用参数...

    指定的参数已超出有效值的范围参数名: utcDate

    指定的参数已超出有效值的范围参数名: utcDate 说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。 异常详细信息: System....

    SQLServer常用字段类型

    本资料是一些SQLServer中常用字段类型

    Delphi最新三层源码

    随便说说最近项目中的三层架构吧。讲点实际的东西。我最讨厌空讲道理。网上讲道理的太多了,不喜欢举例子。 大多数文章中都或多或少的讲到了三层架构。表示层,业务层,数据层。又把业务层再细分,分为外观服务层,...

Global site tag (gtag.js) - Google Analytics