атомарный выдерживают сравнение и загружают базу данных

Я предполагаю, что немного прагматизма было бы хорошо здесь. Отображения между объектами и таблицами всегда имеют немного странности тут и там. Вот то, что я делаю:

я использую Ibatis, чтобы говорить с моей базой данных (Java к Oracle). Каждый раз, когда у меня есть структура наследования, где я хочу, чтобы подкласс был сохранен в базе данных, я использую "различитель". Это - прием, где Вы имеете одну таблицу для всех Классов (Типы) и имеете все поля, которые Вы могли возможно хотеть сохранить. Существует один дополнительный столбец в таблице, содержа строку, которая используется Ibatis для наблюдения, какой тип объекта это должно возвратить.

Это выглядит забавным в базе данных и иногда может получать Вас в проблему с отношениями к полям, которые не находятся во всех Классах, но 80% времени, это - хорошее решение.

Относительно Вашего отношения между категорией и продуктом, я добавил бы categoryId столбец к продукту, потому что это сделает жизнь действительно легкой, и SQL мудрый и Отображающийся мудрый. Если Вы действительно застреваете при выполнении "теоретически корректной вещи", можно рассмотреть дополнительную таблицу, которая имеет только 2 colums, соединяя Категории и их продукты. Это будет работать, но обычно эта конструкция только используется при необходимости в many-many отношениях.

Попытка сохранить его максимально простым. Наличие "академического решения" хорошо, но обычно означает немного излишества и более трудно осуществить рефакторинг, потому что это слишком абстрактно (как сокрытие отношений между Категорией и продуктом).

я надеюсь, что это помогает.

8
задан JMarsch 1 October 2009 в 23:04
поделиться

4 ответа

Является ли PK первичным ключом? Тогда это не проблема, если вы уже знаете первичный ключ, нет никакого спорта. Если pk является первичным ключом, тогда возникает очевидный вопрос как узнать pk элемента для удаления из очереди ...

Проблема в том, если вы не знают первичный ключ и хотят исключить из очереди следующий «доступный» (например, status = y) и пометить его как исключенный (удалить или установить status = z).

Правильный способ сделать это заключается в использовании одного оператора. К сожалению, синтаксис Oracle и SQL Server отличается. Синтаксис SQL Server следующий:

update top (1) [<table>]
set status = z 
output DELETED.*
where  status = y;

Я недостаточно знаком с предложением RETURNING Oracle, чтобы привести пример, аналогичный OUTPUT в SQL.

Другие решения SQL Server требуют, чтобы подсказки блокировки для SELECT (с UPDLOCK) были правильными. В Oracle предпочтительным способом является использование FOR UPDATE, но это не работает в SQL Server, поскольку FOR UPDATE должен использоваться вместе с курсорами в SQL.

В любом случае поведение, которое вы указали в исходном сообщении, неверно . Несколько сеансов могут выбрать одну и ту же строку (и) и даже все обновить ее, возвращая один и тот же исключенный из очереди элемент (ы) нескольким читателям.

7
ответ дан 5 December 2019 в 14:04
поделиться

У меня есть приложения, работающие по аналогичной схеме. Есть такая же таблица, как ваша, которая представляет очередь работы. В таблице есть два дополнительных столбца: thread_id и thread_date. Когда приложение запрашивает работу в очереди, оно отправляет идентификатор потока. Затем один оператор обновления обновляет все применимые строки столбцом идентификатора потока с отправленным идентификатором и столбцом даты потока с текущим временем. После этого обновления он выбирает все строки с этим идентификатором потока. Таким образом, вам не нужно объявлять явную транзакцию. «Блокировка» происходит при первоначальном обновлении.

Столбец thread_date используется, чтобы гарантировать, что вы не получите потерянные рабочие элементы. Что произойдет, если элементы будут извлечены из очереди, а затем ваше приложение выйдет из строя? У вас должна быть возможность снова попробовать эти рабочие элементы. Таким образом, вы можете взять из очереди все элементы, которые не были отмечены как завершенные, но были назначены потоку с датой потока в далеком прошлом. Определение «дальний» зависит от вас.

2
ответ дан 5 December 2019 в 14:04
поделиться

Как правило, чтобы выполнить операцию, подобную этой атомарной, вам необходимо убедиться, что вы установили эксклюзивную (или обновленную) блокировку при выполнении выбора, чтобы никакая другая транзакция не могла читать строка перед обновлением.

Типичный синтаксис для этого примерно такой:

 select * from table where pk = x and status = y for update

, но вам нужно его найти, чтобы быть уверенным.

2
ответ дан 5 December 2019 в 14:04
поделиться

Попробовать. Проверка выполняется в операторе UPDATE.

Код

IF EXISTS (SELECT * FROM sys.tables WHERE name = 't1')
    DROP TABLE dbo.t1
GO
CREATE TABLE dbo.t1 (
    ColID       int         IDENTITY,
    [Status]    varchar(20)
)
GO

DECLARE @id             int
DECLARE @initialValue   varchar(20)
DECLARE @newValue       varchar(20)

SET @initialValue = 'Initial Value'

INSERT INTO dbo.t1 (Status) VALUES (@initialValue)
SELECT @id = SCOPE_IDENTITY()

SET @newValue = 'Updated Value'

BEGIN TRAN

UPDATE dbo.t1
SET
    @initialValue = [Status],
    [Status]      = @newValue
WHERE ColID    = @id
  AND [Status] = @initialValue

SELECT ColID, [Status] FROM dbo.t1

COMMIT TRAN

SELECT @initialValue AS '@initialValue', @newValue AS '@newValue'

Результаты

ColID Status
----- -------------
    1 Updated Value

@initialValue @newValue
------------- -------------
Initial Value Updated Value
1
ответ дан 5 December 2019 в 14:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: