EF成功写入后有时可以重试吗?

时间:2016-12-13 09:59:54

标签: c# .net sql-server entity-framework asp.net-web-api

我对数据库表有UNIQUE约束,在编写新记录时偶尔会抛出异常。约束包括三个字段 - 其中一个是DATETIMEOFFSET(7)。当命中webapi端点时,该字段的值被设置为当前时间。

我无法想到多个webapi请求会插入完全重复时间的任何原因 - 鉴于时间字段的准确性,这似乎不太可能。

不幸的是,我无法重现异常,我们偶尔会在日志中看到它。

我唯一能想到的是,如果在同一个请求中,实体框架在认为数据库写入失败后会以某种方式重试数据库写入,而不会导致异常。我们正在使用SqlAzureExecutionStrategy,在对其ShouldRetryOn方法进行反编译后,它看起来像是在重试以下错误代码...

  

40613:数据库目前无法使用       41301:发生事务依赖性故障,并且当前事务无法再提交。       41302:当前事务尝试更新自此事务启动以来已更新的记录。交易中止。       41305:由于可重复的读取验证失败,当前事务无法提交。       41325:由于可序列化验证失败,当前事务无法提交。       10928:资源ID:%d。数据库的%ls限制为%d且已达到。请参阅' http://go.microsoft.com/fwlink/?LinkId=267637'寻求帮助。       10929:资源ID:%d。 %ls最小保证是%d,最大限制是%d,数据库的当前使用率是%d。但是,服务器当前太忙,无法支持此数据库的%ls大于%d。见' http://go.microsoft.com/fwlink/?LinkId=26       40197:服务处理您的请求时遇到错误。请再试一次。错误代码%d。       40501:服务当前正忙。 10秒后重试请求。事件ID:%ls。代码:%d       233:列'%。* ls'在表格中'%。* ls'不能为空。       10053:由于符号不匹配或溢出以外的原因,无法转换数据值。       10054:一个或多个列的数据值溢出提供者使用的类型。       10060:连接错误       20:?       64:与服务器成功建立连接,但在登录前握手期间发生错误

我原本以为它只会在没有写入的情况下重试。是否有可能写入记录,但实体框架可能会感到困惑,无论如何都要再试一次?

更新

以下是例外......

System.Data.Entity.Infrastructure.RetryLimitExceededException: Maximum number of retries (5) exceeded while executing database operations with 'MyExecutionStrategy'.
See inner exception for the most recent failure. ---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries.
See the inner exception for details. ---> System.Data.SqlClient.SqlException: Violation of UNIQUE KEY constraint 'UQ_SessionLog'. Cannot insert duplicate key in object 'dbo.SessionLog'. The duplicate key value is (f6aeb1b8-c747-4f0b-9053-bf95a5630662, 2016-07-12 11:42:32.7077612  01:00, 0).
The statement has been terminated.
  at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
  at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
  at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
  at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean%26 dataReady)
  at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
  at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task%26 task, Boolean asyncWrite, SqlDataReader ds)
  at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task%26 task, Boolean asyncWrite)
  at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
  at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
  at StackExchange.Profiling.Data.ProfiledDbCommand.ExecuteNonQuery() in d:\Files\GitHub\miniprofiler\dotnet\StackExchange.Profiling\Data\ProfiledDbCommand.cs:line 264
  at System.Data.Common.DbCommand.ExecuteNonQueryAsync(CancellationToken cancellationToken)

1 个答案:

答案 0 :(得分:4)

DateTime的精度不会超过毫秒数字会让您相信的数字。您很可能会在多线程环境中获得重复

试图找到一个权威的答案,确切地说它是多么精确: https://msdn.microsoft.com/EN-US/library/system.datetime.utcnow.aspx

"此属性的分辨率取决于系统计时器。"

您不是第一个遇到此问题的人

C# DateTime.Now precision

DateTime precision vs accuracy?

https://manski.net/2014/07/high-resolution-clock-in-csharp/

等等