Обработка max (ID) в параллельной среде - PullRequest
4 голосов
/ 24 сентября 2011

Я новичок в программировании веб-приложений и обработке параллелизма с использованием СУБД, такой как SQL Server.Я использую SQL Server 2005 Express Edition.

Я генерирую код сотрудника, в котором последние четыре цифры взяты из этого запроса:

SELECT max(ID) FROM employees WHERE district = "XYZ";

Я не следую, как решать проблемы, которые могутвозникают из-за одновременных соединений.Многие пользователи могут выбрать один и тот же максимальный (ID), и хотя один пользователь нажимает «Сохранить запись», идентификатор может быть уже занят другим пользователем.

Как решить эту проблему?

Ответы [ 3 ]

2 голосов
/ 25 сентября 2011

Вот два способа сделать то, что вы хотите. Тот факт, что у вас может возникнуть уникальное нарушение ограничений на EmpCode, оставлю вас беспокоиться:).

1. Используйте scope_identity() для получения последнего введенного идентификатора и используйте его для вычисления 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
)

Добавить одну строку в список сотрудников. Должно быть сделано в транзакции, чтобы быть уверенным, что вы не останетесь со случайным значением по умолчанию от 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 вычисляемый столбец .

Определение таблицы:

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')
2 голосов
/ 25 сентября 2011

Использование MAX - плохая идея, поскольку при правильном механизме блокировки вы не сможете вставлять строки в несколько потоков для одного района.Если для вас нормально, что вы можете создавать только одного пользователя за раз, и если ваши тесты показывают, что MAX расширяется даже при большом количестве пользователей в каждом районе, возможно, будет правильным его использовать.Короче говоря, имея дело с идентичностями, насколько это возможно, вы должны полагаться на IDENTITY.Действительно.

Но если это невозможно, одним из решений является обработка идентификаторов в отдельной таблице.

Create Table DistrictID (
    DistrictCode char(2),
    LastID Int,
    Constraint PK_DistrictCode Primary Key Clustered (DistrictCode)
);

Затем вы увеличиваете счетчик LastID.Важно, чтобы инкрементные идентификаторы были транзакцией, отделенной от транзакции создания пользователя, если вы хотите создать много пользователей в параллельных потоках.Вы можете ограничить генерацию идентификатора в последовательности.

Код может выглядеть следующим образом:

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 ключевые слова - это минимум, который вам нужен, чтобы избежать двух потоков, чтобы получить одинаковый идентификатор.Если в таблице не все районы, вам нужно изменить Повторяемое чтение на Сериализуемый и раскошелиться на Обновление с Вставить .

1 голос
/ 24 сентября 2011

Это можно сделать через Уровни изоляции транзакции . Например, если вы укажете SERIALIZABLE в качестве уровня, другие транзакции будут заблокированы, чтобы вы не столкнулись с этой проблемой.

Если я не правильно понял ваш вопрос, пожалуйста, дайте мне знать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...