Я пишу простую программу обмена сообщениями, где есть таблица сообщений, которая может быть заявлена пользователями и имеет материал, сделанный им этим пользователем. Не предопределено, какой пользователь будет требовать данное сообщение, и поэтому я хочу, чтобы запрос выбирал первый из всех доступных сообщений, которые у меня есть, а затем один, чтобы отметить это сообщение как принимающее, которое у меня также есть. Проблема в том, что я не хочу, чтобы два пользователя использовали его одновременно, чтобы требовать одно и то же сообщение, и поэтому я хочу последовательно запускать эти два оператора, не возвращаясь к программе, чтобы узнать, что делать дальше в между заявлениями. Я считаю, что могу запустить два последовательных оператора, разделив их на полуколоны, но я хочу использовать данные, возвращенные в первом запросе, как часть второго. Переменные были бы идеальными, но, насколько мне известно, они не существуют в SQL. Есть ли способ сохранить состояние между запросами?Последовательные операторы SQL с состоянием
ответ
Сделка хороший путь, как Ле dorfier говорит, но есть alernatives:
Вы могли бы сделать обновление первым, т.е. мечение сообщения с идентификатором пользователя или аналогичным. Вы не упоминаете, которые SQL вкус Youre использованием, но в MySQL, я думаю, было бы выглядеть примерно так:
UPDATE message
SET user_id = ...
WHERE user_id = 0 -- Ensures no two users gets the same message
LIMIT 1
В MS SQL, это было бы что-то вдоль линий:
WITH q AS (
SELECT TOP 1
FROM message m
WHERE user_id = 0
)
UPDATE q
SET user_id = 1
/B
Есть ли способ сохранить состояние между запросами?
№ SQL не является процедурным языком. Вы можете переписать свои два запроса как один запрос (не всегда возможно, часто не стоит, даже если это возможно), или склеить их вместе с процедурным языком. Многие SQL-серверы предоставляют встроенный язык для этого («хранимые процедуры»), или вы можете сделать это в своем приложении.
Проблема заключается в том, что я не хочу двух пользователей, использующих его в то же время утверждать то же самое сообщение
Используйте замки. Я не знаю, какой SQL-сервер вы используете, но с использованием SELECT ... FOR UPDATE
звучит так, как будто это будет именно то, что вы хотите, если оно доступно.
Это то, на что предназначены BEGIN TRAN и COMMIT TRAN. Поместите заявления, которые вы хотите защитить в рамках транзакции.
Возможно, вы можете использовать временную таблицу.
SQL сам по себе не имеет переменных, но (почти?) Все RDBMS SQL-расширения делают. Но я не уверен, как это решит вашу проблему.
Как уже упоминалось, сделка будет делать трюк - эффективно группировать ваши 2 несвязанных заявления вместе. Однако, уровень транзакции по умолчанию будет не работает. (Большинство?) Уровень транзакции по умолчанию для сервера РСУБД READ COMMITTED. Это не мешает пользователю 2 читать ту же строку, что и пользователь 1. Для этого вам нужно использовать REPEATABLE READ или SERIALIZABLE.
Это классическая проблема параллелизма. Как правило, два способа обработки - это пессимистическая блокировка или оптимистическая проверка.Операция REPEATABLE READ была бы пессимистичной (с учетом затрат на блокировку независимо от того, нужна она или нет), а проверка @@ ROWCOUNT оптимистична (если она работает, но делает что-то разумное, когда @@ ROWCOUNT = 0).
Обычно мы используем оптимистичный (блокировка стоит дорого) и либо используем метку времени, либо комбинацию прочитанных полей, чтобы убедиться, что мы меняем данные, которые мы думали. Итак, мое предложение состоит в том, чтобы включить поле rowversion или timestamp и передать его обратно в ваш оператор UPDATE. Затем проверьте @@ ROWCOUNT, чтобы узнать, обновлены ли вы записи. Если вы этого не сделали, вернитесь назад и выберите другое сообщение. В псевдокоде:
int messageId, byte[] rowVersion = DB.Select(
"SELECT TOP 1
MessageId, RowVersion
FROM Messages
WHERE
User IS NULL";
int rowsAffected = DB.Update(
"UPDATE Messages SET
User = @myUserId
WHERE
MessageId = @messageId
AND RowVersion = @rowVersion",
myUserId, messageId, rowVersion
);
if (rowsAffected = 0)
throw new ConcurrencyException("The message was taken by someone else");
В зависимости от конкретных заявлений, вы можете быть в состоянии уйти только с повторением «UserId IS NULL» ИНЕК в вашем UPDATE заявлении. Это похоже на решение Бримстедта - но вы все равно должны проверить @@ ROWCOUNT, чтобы увидеть, действительно ли строки были обновлены.
- 1. Последовательные операторы IF в javascript
- 2. Erlang - последовательные операторы получения с альтернативным сценарием
- 3. SQL - Последовательные «ON» Заявление
- 4. Преобразование в вещественные последовательные операторы if
- 5. SQL возвращают последовательные записи
- 6. подсчет SQL-последовательные строки
- 7. SQL Найти последовательные отказы
- 8. Выбирать операторы с помощью SQL
- 9. T-SQL присоединиться запрос с странным состоянием
- 10. SQL JOIN 2 ТАБЛИЦА С СОСТОЯНИЕМ (ДАТА)
- 11. SQL Pivot сумма с конкретным состоянием
- 12. Ошибка компилятора: «Последовательные операторы на строке должны быть разделены символом«;
- 13. Последовательные предложения WITH
- 14. Выполняет ли последовательные «новые» операторы смежную выделенную память?
- 15. Сводные операторы SQL
- 16. Последовательные идентификационные номера SQL/PHP
- 17. SQL скомпилированные операторы
- 18. SQL: Как искать последовательные события?
- 19. SKAction.customActionWithDuration Последовательные операторы строки должны быть разделены символом ';'
- 20. NSFetchedResultsController - Ошибка - последовательные операторы в строке должны быть разделены
- 21. sql вложенные операторы case
- 22. Операторы блокировки сервера sql
- 23. linq с нулевым состоянием
- 24. Последовательные записи в oracle SQL
- 25. Последовательные номера счетов SQL-сервер
- 26. Вложенные операторы IF SQL
- 27. Операторы набора SQL
- 28. Операторы case: SQL Server
- 29. Вложенные операторы sql
- 30. Исполнительные Динамические операторы SQL