У вас, похоже, есть еще несколько фундаментальных проблем с архитектурой базы данных и программной архитектуры.
Вместо того, чтобы устанавливать какое-то поле «с истекшим сроком» через определенное время, просто сохраните фактическое время истечения. Затем, когда пользователь выполняет действие, просто проверьте время истечения срока действия на текущее время, чтобы узнать, истекло ли приглашение. Таким образом, он всегда работает, и вам не нужно планировать таймеры или управлять долговременными транзакциями или что-то в этом роде. Он также неявно устойчив к перезагрузке/сбоям в работе программы (для текущего подхода, основанного на тайме, потребуются усилия, чтобы он не забывал истечь ожидающих приглашений, если программа завершается во время работы таймера).
Если вы хотите получать уведомления об истечении срока действия, добавьте к приглашению поле «пользователь было уведомлено» (например). Затем создайте одну повторяющуюся фоновую задачу (для этого может быть полезен таймер или ScheduledExecutorService
), который периодически захватывает список всех истекших неопубликованных приглашений в одном запросе критерия. Выключите уведомления, установите оповещенные флаги, промойте, повторите. Вы можете отправлять уведомления в очереди пула потоков ExecutorService
, если вы хотите, если уведомления требуют много времени (например, отправка сообщений электронной почты).
Закрытие (или их приближение) - не совсем правильный инструмент для этой работы.
Но, если вы должны делать в заданное время вещи флага, установить спящий режим для сеанса объект-в-нити режима (на самом деле, я думаю, что может быть даже режим по умолчанию), а затем использовать пул потоков ExecutorService (см. «Исполнители»), чтобы запланировать задачу, открывающую транзакцию, приглашение к запросам, ожидание (без таймера), затем делает это и закрывает транзакцию. Затем вся ваша транзакция находится в одном фоновом потоке, и ни одна из странных проблем управления транзакциями, в которой вы работаете, больше не существует.
Даже лучше не останавливаться на этом в одной длительной транзакции (например, что, если пользователь хочет удалить приглашение во время работы вашего таймера?). Откройте транзакцию, затем запросите приглашение, затем закройте его. Затем установите свой таймер (или используйте ScheduledExecutorService
) и таймер откройте транзакцию, запросите приглашение, истечет приглашение и закройте его. Вероятно, вы не хотите, чтобы соединение db и/или транзакция были открыты для всего интервала MAX_TIME
, нет причин для этого.
Что касается окончательной вещи, nonfinal переменного не может быть передан в анонимных внутренних классах, потому что вы не всегда можете гарантировать, что их значения не изменятся до кода анонимного класса запуска (компилятор не , и, как правило, не могут пройти проверку на то, как анонимный класс используется для обеспечения этой гарантии). Поэтому требуется final
.
Просто объявить окончательный пригласить:
final Invite invite = ...;
И вы можете использовать его в анонимном классе.
Подсказка под капотом объяснения может быть найдена here.
И да, вы можете изменить поля invite
. Вы просто не можете назначить приглашение новому объекту. Но, как я уже сказал, ваш подход напуган, и поэтому вы сталкиваетесь с проблемами.
Я нахожусь на своем телефоне или я выкопаю соответствующую часть JLS для финального материала. Вы можете посмотреть его там для получения дополнительной информации.
try 'final Пригласить пригласить = (Пригласить) критерии.uniqueResult();'? – Gosu
Просто перейдите на Java 8 или сделайте это ^. –
@Gosu, поэтому, если 'приглашение' является окончательным, я все равно могу изменить его свойства с помощью' setExpired() '? – gwg