在Linq to Sql中管理并发更新时的冲突(1):预备知识

2024-04-17 01:08

本文主要是介绍在Linq to Sql中管理并发更新时的冲突(1):预备知识,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

来源: 老赵点滴 http://www.cnblogs.com/JeffreyZhao/archive/2007/10/30/943504.html
  • 在Linq to Sql中管理并发更新时的冲突(2):引发更新冲突
  • 在Linq to Sql中管理并发更新时的冲突(3):使用记录的时间戳进行检测
无论与目前的ORM框架相比有没有优势,Linq to Sql在语言和平台的级别上为我们提供了一种新的操作对象和数据的方式,在一定程度上为我们解决了Object != Data的问题。在实际应用中,对于数据库的操作往往有着天生的并发性,因此在更新数据时可能会产生冲突。有些时候,如果没有合理的解决冲突问题,轻则让用户摸不着头脑,重则让系统数据处于一种不一致的状态。Linq to Sql自然考虑到了这一点,本系列讨论的内容,就是在使用Linq to Sql时,如何管理并发更新时产生的冲突。
本文为这个系列的第一篇,将讨论一些预备知识,它们是进行后续研究的基础。
一些定义:
首先,我们来看一些定义:
  • 并发(Concurrency):两个或更多的用户尝试同时更新数据库的同一条记录。
  • 并发冲突(Concurrency Confilct):两个或更多的用户尝试同时向同一条记录的一个或多个字段提交冲突的值。
  • 并发控制(Concurrency Control):解决并发冲突的技术。
  • 乐观并发控制(Optimistic Concurrency Control):在提交当前事务之前,首先查看即将更新的记录是否被别的事务所改变的一种技术。
  • 悲观并发控制(Pessimistic Concurrency Control):为纪录加锁以阻止其他事务访问某些记录,以避免产生并发冲突的一种技术。
Linq to Sql的对象模型使用乐观并发控制的方式来发现和解决冲突问题。很显然,它假设冲突发生的可能性并不大。如果您需要使用悲观并发控制来解决冲突问题,则可以使用其他方法(例如自定义存储过程供程序调用)。
调试方法:
Linq to Sql的相当部分由编译器来实现,而语言中的Linq语句最终会被转化为Sql,因此如果要理解Linq to Sql的工作,一定要将操作中所执行的Sql语句给挖掘出来。一般来说,要挖掘出操作中所使用的Sql语句,可以使用以下几种方法(以下将使用Sql Server 2005自带的AdventureWorks数据库来作为示例):
1、获取Query所对应的SqlCommand对象:
在开发过程中,我们可以通过Query获得对应的Sql Command对象。请看如下代码:
AdventureWorksDataContext db = new AdventureWorksDataContext();
var products = from p in db.Products
               where p.ProductID == 3
               select new { p.ProductID, p.Name };
foreach (var p in products)
{
    Console.WriteLine(p);
}
 
DbCommand cmd = db.GetCommand(products);
 
Console .WriteLine("------------");
Console .WriteLine("Command Text: /n{0}", cmd.CommandText);
 
Console .WriteLine("------------");
Console .WriteLine("Command Type: /n{0}", cmd.CommandType);
 
Console .WriteLine("------------");
Console .WriteLine("Command Parameters:");
foreach (DbParameter p in cmd.Parameters)
{
    Console.WriteLine("{0}: {1}", p.ParameterName, p.Value);
}
 
Console .ReadLine();
输出结果如下:
Command Text:
SELECT [t0].[ProductID], [t0].[Name]
FROM [Production].[Product] AS [t0]
WHERE [t0].[ProductID] = @p0
------------
Command Type:
Text
------------
Command Parameters:
@p0: 3
可以看到,无论是Sql语句或是参数都被打印了出来。事实上,由于我们得到了完整的SqlCommand对象,我们可以获取的信息并不止上述这些。
2、使用LINQ to SQL Debug Visualizer:
使用LINQ to SQL Debug Visiualizer,我们可以在调试程序时直观地获得Query所对应的Sql语句以及参数,而不必获得SqlCommand对象并打印信息。具体使用方法详见 Scott Gu的这篇 博文。
3、使用DataContext的Log功能:
DataContext自带的Log属性为一个TextWriter类型的对象,如果我们设置了这个属性,则DataContext所有的操作将会通过这个TextWriter对象输出。与比上述两种方法相比,这个方法的优势在于DataContext所执行的所有语句,无论SELECT、INSERT、UPDATE或者是DELETE都会被输出;而上面的两种做法只能得到Query的信息,也就是SQL语句的SELECT操作。
请看如下代码,下面的代码将AdventureWorksDataContext对象的所有操作输出至Console:
AdventureWorksDataContext db = new AdventureWorksDataContext();
db.Log = Console.Out;
 
Product product = (from p in db.Products
                   where p.ProductID == 1
                   select p).First();
 
product.Name = "Hello World";
db.SubmitChanges();
 
Console .ReadLine();
输出结果如下:
SELECT TOP (1) [t0].[ProductID], [t0].[Name], [t0].[ProductNumber], [t0].[MakeFl
...
edDate], [t0].[rowguid], [t0].[ModifiedDate]
FROM [Production].[Product] AS [t0]
WHERE [t0].[ProductID] = @p0
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21004.1

UPDATE [Production].[Product]
SET [Name] = @p11
WHERE ([ProductID] = @p0) AND ([Name] = @p1) AND ([ProductNumber] = @p2) AND (NO
...
NULL) AND ([rowguid] = @p9) AND ([ModifiedDate] = @p10)
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
...
-- @p11: Input NVarChar (Size = 11; Prec = 0; Scale = 0) [Hello World]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21004.1
在这里我省略了大部分的输出,不过从上面的片断中我们已经可以看到SELECT和UPDATE操作所使用的Sql语句以及参数都被打印了出来。这就是我们可以利用的调试信息。
4、使用Sql Server Profiler:
其实使用Sql Server Profile来监听数据库操作应该是最容易想到的方法。相信各位朋友对于Sql Server Profiler的简单操作也已经非常熟悉,我在这里就不赘述了。
那么第3中做法相比,使用Sql Server Profiler有什么又优点和缺点呢?使用Sql Server Profiler的优点可能就在于方便,我们不用写代码,也不用设法将Log信息输出至某个地方。缺点可能就在于Sql Server Profiler获取到的信息会比较多,而其中只有一小部分是我们需要的。而且,Sql Server Profiler的输出也不如DataContext的Log输出来的工整、易读。至于在开发过程中使用什么做法比较合适,我这里也无法推荐,因为这需要您根据实际情况进行选择了。
 

这篇关于在Linq to Sql中管理并发更新时的冲突(1):预备知识的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/910404

相关文章

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分

MySQL错误代码2058和2059的解决办法

《MySQL错误代码2058和2059的解决办法》:本文主要介绍MySQL错误代码2058和2059的解决办法,2058和2059的错误码核心都是你用的客户端工具和mysql版本的密码插件不匹配,... 目录1. 前置理解2.报错现象3.解决办法(敲重点!!!)1. php前置理解2058和2059的错误

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

MySQL INSERT语句实现当记录不存在时插入的几种方法

《MySQLINSERT语句实现当记录不存在时插入的几种方法》MySQL的INSERT语句是用于向数据库表中插入新记录的关键命令,下面:本文主要介绍MySQLINSERT语句实现当记录不存在时... 目录使用 INSERT IGNORE使用 ON DUPLICATE KEY UPDATE使用 REPLACE

MySQL Workbench 安装教程(保姆级)

《MySQLWorkbench安装教程(保姆级)》MySQLWorkbench是一款强大的数据库设计和管理工具,本文主要介绍了MySQLWorkbench安装教程,文中通过图文介绍的非常详细,对大... 目录前言:详细步骤:一、检查安装的数据库版本二、在官网下载对应的mysql Workbench版本,要是

mysql数据库重置表主键id的实现

《mysql数据库重置表主键id的实现》在我们的开发过程中,难免在做测试的时候会生成一些杂乱无章的SQL主键数据,本文主要介绍了mysql数据库重置表主键id的实现,具有一定的参考价值,感兴趣的可以了... 目录关键语法演示案例在我们的开发过程中,难免在做测试的时候会生成一些杂乱无章的SQL主键数据,当我们

浅谈mysql的sql_mode可能会限制你的查询

《浅谈mysql的sql_mode可能会限制你的查询》本文主要介绍了浅谈mysql的sql_mode可能会限制你的查询,这个问题主要说明的是,我们写的sql查询语句违背了聚合函数groupby的规则... 目录场景:问题描述原因分析:解决方案:第一种:修改后,只有当前生效,若是mysql服务重启,就会失效;

MySQL多列IN查询的实现

《MySQL多列IN查询的实现》多列IN查询是一种强大的筛选工具,它允许通过多字段组合快速过滤数据,本文主要介绍了MySQL多列IN查询的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录一、基础语法:多列 IN 的两种写法1. 直接值列表2. 子查询二、对比传统 OR 的写法三、性能分析与优化1.

MySQL新增字段后Java实体未更新的潜在问题与解决方案

《MySQL新增字段后Java实体未更新的潜在问题与解决方案》在Java+MySQL的开发中,我们通常使用ORM框架来映射数据库表与Java对象,但有时候,数据库表结构变更(如新增字段)后,开发人员可... 目录引言1. 问题背景:数据库与 Java 实体不同步1.1 常见场景1.2 示例代码2. 不同操作