Предполагая, что вы настаиваете на сохранении его в своей базе данных (и игнорируете сторону Java):
Ты все делаешь неправильно. Прежде всего, помните, что SQL по определению неупорядочен . Это означает, что нет ни «верха», ни «низа» (это указывает на то, что это так, но это не совсем так).
Вам понадобится несколько таблиц:
Resource -- List of resource ids - this is how you limit the count.
============
id -- autoincrement int
allowed -- boolean flag if this resource is 'present'.
-- This is *not* the 'checkout' flag.
natural_key -- if necessary
Process -- When a 'thread' spools up, you need to register it.
-- This is to enable monitor jobs, to clean up/restart dead jobs.
============
id -- autoincrement int
process_natural_key -- What the process calls itself.
Checked_out
================
process_id -- fk to Process.id
resource_id -- fk to Resource.id
checked_out_at -- timestamp, useful for reporting, not otherwise necessary.
Checkin_History
===================
resource_id -- fk to Resource.id
checked_in_at -- timestamp, necessary
Вставьте ваш набор ресурсов в Resource
. Установите allowed
как необходимый - он есть в случае, если определенный ресурс вообще недоступен (скажем, сервер отключен).
Каждый раз, когда задание становится ненужным, зарегистрируйте его в Process
. Это отдельно от любой регистрации на стороне программы (например, ведение экземпляров в ExecutorPool
или что-то) - с одной стороны, это позволяет вам восстановить данные процесса, если они закодированы правильно.
Теперь вы можете «проверить» свой ресурс, сначала вставив запись, а затем запросив извлеченную запись для вашего процесса (или сразу, если ваша версия поддерживает «DATA CHANGED TABLE REFERENCE's»):
INSERT INTO Checked_out (process_id, resource_id, checked_out_at)
SELECT a.id, b.id, CURRENT_TIMESTAMP
FROM Process as a
JOIN (SELECT b.id, COALESCE(MAX(d.checked_in_at),
TIMESTAMP('0001-01-01 00:00:00') + b.id SECONDS) as stamp
FROM Resource as b
LEFT JOIN Checked_out as c
ON c.resource_id = b.id
LEFT JOIN Checkin_History as d
ON d.resource_id = c.resource_id
WHERE c.resource_id IS NULL
AND b.allowed = '1'
GROUP BY b.id) as b
ON 1 = 1
LEFT JOIN (SELECT b.id, COALESCE(MAX(d.checked_in_at),
TIMESTAMP('0001-01-01 00:00:00') + b.id SECONDS) as stamp
FROM Resource as b
LEFT JOIN Checked_out as c
ON c.resource_id = b.id
LEFT JOIN Checkin_History as d
ON d.resource_id = c.resource_id
WHERE c.resource_id IS NULL
AND b.allowed = '1'
GROUP BY b.id) as c
ON c.stamp > b.stamp
WHERE a.process_natural_key = @programInput
AND c.id IS NULL
LIMIT 1
Это было проверено и работает на экземпляре DB2 (хотя и не под нагрузкой).
Оператор также можно изменить на , а не вставить строку, если у процесса уже есть строка извлечения.