我是Web应用程序编程的新手,并且使用像SQL Server这样的RDBMS处理并发。我正在使用SQL Server 2005 Express Edition。
我正在生成员工代码,其中最后四位数来自此查询:
SELECT max(ID) FROM employees WHERE district = "XYZ";
我没有关注如何处理因并发连接而可能出现的问题。许多用户可以选择相同的最大值(ID),当一个用户点击“保存记录”时,该ID可能已被其他用户占用。
如何处理这个问题?
答案 0 :(得分:2)
这有两种方法可以做你想做的事。您最终可能会在EmpCode
上遇到唯一约束违规的事实我会让您担心:)。
1。使用scope_identity()
获取最后插入的ID并使用它来计算EmpCode
。
表格定义:
create table Employees
(
ID int identity primary key,
Created datetime not null default getdate(),
DistrictCode char(2) not null,
EmpCode char(10) not null default left(newid(), 10) unique
)
向Employees添加一行。应该在交易中完成,以确保您不会使用left(newid(), 10)
中EmpCode
的默认随机值:
declare @ID int
insert into Employees (DistrictCode) values ('AB')
set @ID = scope_identity()
update Employees
set EmpCode = cast(year(Created) as char(4))+DistrictCode+right(10000+@ID, 4)
where ID = @ID
2。让EmpCode
成为computed column。
表格定义:
create table Employees
(
ID int identity primary key,
Created datetime not null default getdate(),
DistrictCode char(2) not null,
EmpCode as cast(year(Created) as char(4))+DistrictCode+right(10000+ID, 4) unique
)
向员工添加一行:
insert into Employees (DistrictCode) values ('AB')
答案 1 :(得分:2)
使用MAX是一个坏主意,因为使用适当的锁定机制,您将无法在同一区域的多个线程中插入行。 如果您可以一次只创建一个用户,并且如果您的测试表明即使每个区域有大量用户,MAX也可以扩展,那么可以使用它。 长话短说,尽可能地处理身份,你应该依赖IDENTITY。真。
但如果不可能,一种解决方案是在单独的表中处理ID。
Create Table DistrictID (
DistrictCode char(2),
LastID Int,
Constraint PK_DistrictCode Primary Key Clustered (DistrictCode)
);
然后递增LastID计数器。如果要在并行线程中创建许多用户,则递增ID是一个与用户创建事务分离的事务,这一点很重要。您可以限制只按顺序生成ID。
代码可能如下所示:
Create Procedure usp_GetNewId(@DistrictCode char(2), @NewId Int Output)
As
Set NoCount On;
Set Transaction Isolation Level Repeatable Read;
Begin Tran;
Select @NewId = LastID From DistrictID With (XLock) Where DistrictCode = @DistrictCode;
Update DistrictID Set LastID = LastID + 1 Where DistrictCode = @DistrictCode;
Commit Tran;
可重复读取和 XLOCK 关键字是避免两个线程获取相同ID所需的最小值。 如果表格没有所有区域,则需要将可重复读取更改为可序列化,并将更新更改为插入强>
答案 2 :(得分:1)
这可以通过Transaction Isolation Levels来完成。例如,如果您将SERIALIZABLE指定为级别,那么将阻止其他事务,以便您不会遇到此问题。
如果我没有正确理解你的问题,请告诉我。