Мне кажется, что ключ заключается в том, чтобы заблокировать строку с вашим текущим флагом, что по сути эквивалентно синхронизации с ним в терминах Java.Вы должны последовательно делать это в первую очередь до (или одновременно) чтения других данных.Можно использовать уровень изоляции с фиксацией для чтения.
Вы можете заблокировать строку, указав LockMode.UPGRADE
(или LockOptions.UPGRADE
Я думаю, что она изменена на 3.5) на Hibernate при получении строки из запроса или изсессия.Если вы используете собственный запрос SQL, вам придется использовать реализацию базы данных (обычно ... FOR UPDATE
).Например:
StatusData status = (StatusData) session.get(StatusData.class, id, LockOptions.UPGRADE);
, который Hibernate будет использовать для создания SELECT s_.id, ... FROM status_data s_ WHERE s_id = ? FOR UPDATE OF s_
или соответствующего эквивалента для вашего диалекта (например, with(updlock,rowlock)
)
Istr вы также указываете это в запросе, так что, вероятно,что-то вроде:
StatusData status = (StatusData)
session.getNamedQuery("Status.FindLatest")
.setLockMode("status", LockMode.UPGRADE)
.uniqueResult();
Как только эта строка окажется в этом режиме, любой другой код, пытающийся выполнить тот же запрос, будет блокироваться до тех пор, пока вы не завершите транзакцию, так что теперь вы можете вносить изменения в статус илиего зависимые коллекции.
Я полагаю, вы нашли документацию по использованию транзакций с Hibernate?http://docs.jboss.org/hibernate/core/3.3/reference/en/html/transactions.html
У меня был хороший опыт использования декларативных границ транзакций.Таким образом, DAO / EJB / что угодно для выполнения взаимодействия с базой данных, предоставляемое через интерфейс, и декоратор для автоматического запуска / принятия / отката всех вызовов через этот интерфейс.Контейнеры Spring и J2EE предоставляют инфраструктуру для этого, хотя это также легко сделать вручную.Это проясняет в коде, какие биты находятся внутри транзакции базы данных, а какие нет.Поэтому, если вы сделаете эквивалент:
void finishProcessing() {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
ThreadLocalSessionContext.bind(session);
boolean committed = false;
try {
underlying.finishProcessing();
tx.commit();
committed = true;
} finally {
if (!committed) tx.rollback();
session.close();
ThreadLocalSessionContext.unbind(sessionFactory);
}
}
В вашей базовой реализации finishProcessing()
вы можете просто получить строку состояния, внести другие изменения и вернуться: транзакция будет зафиксирована (что неявно сбрасываетсеанс) и сеанс закрыт на выходе.