让查询在提交之前读取数据 - Sql 服务器
Let a query read data before is committed - Sql Server
我有一个 Table 名为 ProjectActivity
使用主键:ProjectCode 和 ActivityId 以及 ProjectCode 上的索引
我们的网站在此 table 上生成查询(不涉及其他 table)并且始终请求具有相同 ProjectCode
的行
有时我们在 c# 中启动一个作业,删除具有特定 ProjectCode 的每一行,并在事务中为该特定 ProjectCode 插入新行。
using (var dbContextTransaction = db.Database.BeginTransaction())
{
try
{
db.Database.ExecuteSqlCommand("delete FROM [TS_Repository].[dbo].[ProjectActivities] where ProjectCode = {0} ", project.Code);
LogManager.WriteRequestLog("Deleted Existing Project Activities");
if (ProjectActivities.Count > 0)
{
db.Set<ProjectActivity>().AddRange(ProjectActivities);
db.SaveChanges();
}
dbContextTransaction.Commit();
LogManager.WriteRequestLog("Refresh ProjectActivities succesfully for " + project.Title);
}
catch (Exception exc)
{
dbContextTransaction.Rollback();
throw exc;
}
}
我们的问题是,在处理此事务(3/4 分钟)时,我们的网站无法执行任何查询(整个 table 已锁定)。
我们应该得到这个场景:
在提交交易之前,网站应该查询 "old" 数据。这个场景可以实现吗?我可以弄清楚我们必须用锁和隔离级别来欺骗。
提前感谢您的任何提示。
是的,您可以使用特定的 隔离级别 执行查询,该级别可以在 table 或行被锁定时读取数据。我不会参与有关读取未提交数据的风险的讨论,我想您已经知道了,@iamdave 对此分享了一个很好的 link。
当你想读取未提交的数据时,EF
有一些方法可以做到这一点,但一种简单明了的方法是使用事务。在 TransactionScope
构造函数中,您可以设置 IsolationLevel
,如下所示:
using (new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadUncommitted
}))
{
// here you put your code
}
这是另一个关于 EF
和隔离级别的好读物:entity-framework-and-transaction-isolation-level
你向我指出了正确的方向,但我想我需要 SNAPSHOT 隔离级别,因为我已经指定我需要阅读旧行版本。可能是我没解释的那么好...
所以,我已经决定使用 SNASPHOT:
using (var dbContextTransaction = db.Database.BeginTransaction(System.Data.IsolationLevel.Snapshot))
{
try
{
db.Database.ExecuteSqlCommand("delete FROM [TS_Repository].[dbo].[ProjectActivities] where ProjectCode = {0} ", project.Code);
LogManager.WriteRequestLog("Deleted Existing Project Activities");
if (ProjectActivities.Count > 0)
{
db.Set<ProjectActivity>().AddRange(ProjectActivities);
db.SaveChanges();
}
dbContextTransaction.Commit();
LogManager.WriteRequestLog("Refresh ProjectActivities succesfully for " + project.Title);
}
catch (Exception exc)
{
dbContextTransaction.Rollback();
throw exc;
}
}
我有一个 Table 名为 ProjectActivity 使用主键:ProjectCode 和 ActivityId 以及 ProjectCode 上的索引 我们的网站在此 table 上生成查询(不涉及其他 table)并且始终请求具有相同 ProjectCode
的行有时我们在 c# 中启动一个作业,删除具有特定 ProjectCode 的每一行,并在事务中为该特定 ProjectCode 插入新行。
using (var dbContextTransaction = db.Database.BeginTransaction())
{
try
{
db.Database.ExecuteSqlCommand("delete FROM [TS_Repository].[dbo].[ProjectActivities] where ProjectCode = {0} ", project.Code);
LogManager.WriteRequestLog("Deleted Existing Project Activities");
if (ProjectActivities.Count > 0)
{
db.Set<ProjectActivity>().AddRange(ProjectActivities);
db.SaveChanges();
}
dbContextTransaction.Commit();
LogManager.WriteRequestLog("Refresh ProjectActivities succesfully for " + project.Title);
}
catch (Exception exc)
{
dbContextTransaction.Rollback();
throw exc;
}
}
我们的问题是,在处理此事务(3/4 分钟)时,我们的网站无法执行任何查询(整个 table 已锁定)。 我们应该得到这个场景: 在提交交易之前,网站应该查询 "old" 数据。这个场景可以实现吗?我可以弄清楚我们必须用锁和隔离级别来欺骗。
提前感谢您的任何提示。
是的,您可以使用特定的 隔离级别 执行查询,该级别可以在 table 或行被锁定时读取数据。我不会参与有关读取未提交数据的风险的讨论,我想您已经知道了,@iamdave 对此分享了一个很好的 link。
当你想读取未提交的数据时,EF
有一些方法可以做到这一点,但一种简单明了的方法是使用事务。在 TransactionScope
构造函数中,您可以设置 IsolationLevel
,如下所示:
using (new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadUncommitted
}))
{
// here you put your code
}
这是另一个关于 EF
和隔离级别的好读物:entity-framework-and-transaction-isolation-level
你向我指出了正确的方向,但我想我需要 SNAPSHOT 隔离级别,因为我已经指定我需要阅读旧行版本。可能是我没解释的那么好...
所以,我已经决定使用 SNASPHOT:
using (var dbContextTransaction = db.Database.BeginTransaction(System.Data.IsolationLevel.Snapshot))
{
try
{
db.Database.ExecuteSqlCommand("delete FROM [TS_Repository].[dbo].[ProjectActivities] where ProjectCode = {0} ", project.Code);
LogManager.WriteRequestLog("Deleted Existing Project Activities");
if (ProjectActivities.Count > 0)
{
db.Set<ProjectActivity>().AddRange(ProjectActivities);
db.SaveChanges();
}
dbContextTransaction.Commit();
LogManager.WriteRequestLog("Refresh ProjectActivities succesfully for " + project.Title);
}
catch (Exception exc)
{
dbContextTransaction.Rollback();
throw exc;
}
}