Я использую JAX-RS для предоставления HTTP-интерфейса для управления моделью данных. Модель данных хранится в базе данных и взаимодействует с ней через JPA.
Это позволяет мне модифицировать интерфейс к модели данных в соответствии с требованиями клиентов REST и в большинстве случаев кажется, что он работает достаточно хорошо. Однако я не уверен, как справиться со сценарием, в котором метод, предоставленный ресурсом JAX-RS, требует транзакции, которая влияет на шаблон получения, обновления JPA, commit-on-tx-end, поскольку существует только перенос транзакции. операция get, поэтому обновление никогда не фиксируется. Я вижу, как возникает та же проблема, если для одной операции REST требуется несколько операций JPA.
Поскольку я использую поддержку транзакций Spring, очевидным является применение @Transactional
к этим методам в ресурсах JAX-RS. Однако для того, чтобы это работало, Spring должен управлять жизненным циклом ресурсов JAX-RS, и примеры использования, о которых я знаю, имеют ресурсы, создаваемые через «new», когда это необходимо, что в любом случае меня немного нервирует.
Я могу придумать следующие решения:
- обновить мои методы JPA, чтобы обеспечить управляемую транзакцией версию всего, что я хочу сделать, из моего интерфейса REST атомарно. Должно работать, хранит транзакции вне уровня JAX-RS, но предотвращает шаблон get, update, commit-on-tx-end и означает, что мне нужно создать очень детализированный интерфейс JPA.
- Inject Resource объекты; но они, как правило, хранят состояние, по крайней мере, с идентификатором объекта, с которым взаимодействует
- Распределите иерархию ресурсов и внедрите большие суперресурсы без состояния в корне, которые управляют всей иерархией из этого корня; несвязные, большие услуги
- Иерархия внедренных, поддерживающих транзакции вспомогательных объектов, не поддерживающих состояние, которые скрывают реальные ресурсы; ресурсы создаются и содержат это состояние, но делегируют вызовы методов вспомогательным объектам
Кто-нибудь получил какие-либо предложения? Вполне возможно, что я где-то упустил какой-то ключевой момент.
Обновление - чтобы обойти отсутствие транзакции в потоке get, update, commit-on-tx-close, я могу открыть метод слияния (объект) EntityManager и вызвать его вручную. Не аккуратный и не решает большую проблему, хотя.
Обновление 2 @skaffman
Пример кода:
В JPA сервисном слое внедренные аннотации работают
public class MyEntityJPAService {
...
@Transactional(readOnly=true) // do in transaction
public MyEntity getMyEntity(final String id) {
return em.find(MyEntity.class, id);
}
В ресурсе JAX-RS, созданном новыми, транзакции отсутствуют
public class MyEntityResource {
...
private MyEntityJPAService jpa;
...
@Transactional // not injected so not effective
public void updateMyEntity(final String id, final MyEntityRepresentation rep) {
MyEntity entity = jpa.getMyEntity(id);
MyEntity.setSomeField(rep.getSomeField());
// no transaction commit, change not saved...
}