以下代码有效,但不能防止其他用户插入行并因此创建重复的ID。
自动更新并分配表的ID。在下面的代码中,我执行以下操作:
获取下一个可用的ID(nextID)
将每个实体的ID设置为nextID ++
批量插入
如何锁定表,以使其他用户无法在上述三个任务运行时插入?我看到过类似的问题,建议设置ISOLATIONLEVEL READCOMMITTED
,但是我认为在获取nextID时不会锁定表。
public void BulkInsertEntities(List<Entity> entities)
{
if (entities == null)
throw new ArgumentNullException(nameof(entities));
string tableName = "Entities";
// -----------------------------------------------------------------
// Prevent other users from inserting (but not reading) here
// -----------------------------------------------------------------
long lastID = GetLastID(tableName);
entities.ForEach(x => x.ID = lastID++);
using (SqlConnection con = new SqlConnection(db.Database.GetDbConnection().ConnectionString))
{
con.Open();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(con.ConnectionString, SqlBulkCopyOptions.KeepIdentity))
{
bulkCopy.DestinationTableName = tableName;
DataTable tbl = DataUtil.ToDataTable<Entity>(entities);
foreach (DataColumn col in tbl.Columns)
bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
bulkCopy.WriteToServer(tbl);
}
}
// ---------------------------
// Allow other users to insert
// ---------------------------
}
protected long GetLastID(string tableName)
{
long lastID = 0;
using (var command = db.Database.GetDbConnection().CreateCommand())
{
command.CommandText = $"SELECT IDENT_CURRENT('{tableName}') + IDENT_INCR('{tableName}')";
db.Database.OpenConnection();
lastID = Convert.ToInt64(command.ExecuteScalar());
}
return lastID;
}
答案 0 :(得分:0)
对于具有可变性的类似于身份的功能,可以创建一个命名序列:
create sequence dbo.MySequence as int
...并且在表上具有默认约束:default(next value for dbo.MySequence)
。
关于这一点的妙处是,您可以“烧录” ID并将其发送给客户端,以便他们拥有可以放入其数据中的密钥...然后,当数据预先填充时,没有危害,没有犯规。它比身份字段花费更多的工作,但这并不可怕。 “刻录”是指您可以随时通过在任何喜欢的地方调用next value for dbo.MySequence
来获得新的ID。如果您坚持使用该值,则您将知道不会分配给该表。该表将获得您之后的下一个值。然后,您可以在闲暇时插入具有并保留的值的行...知道这是一个合法密钥。
SQL Server调用应用程序锁中有一项功能。我很少看到它使用过,但是您的示例可能是合适的。基本上,您的想法是将触发器放在要测试出色的app_lock的表上:
if ( applock_test( 'public', 'MyLock', 'Exclusive' ) = 1 )
begin
raiserror( ... )
return
--> or wait and retry
end
...并且无法中断的长时间运行的过程从一开始就获得了应用锁,并在结束时释放了该锁:
exec @rc = get_applock @dbPrincipal='public', @resource='MyLock', @lockMode='Exclusive'
if ( @rc = 0 )
begin
--> got the lock, do the damage...
--> and then, after carefully handling the edge cases,
--> and making sure we dont skip the release...
exec release_applock @resource='MyLock' @dbPrincipal='public'
end
有很多变化。基于会话的锁,可以在会话结束(当心连接池),超时,多种锁模式(共享,互斥等)和作用域锁(可能不适用于特权数据库用户)时自动释放。 / p>