Добрый день всем жителям! В процессе обучения Java EE на курсах, столкнулся с такой проблемой:
необходимо сделать обработку транзакций в service layer чтоб сделать операцию атомарной для пользователя backenda. Используется hibernate. spring для транзакций использовать пока запрещено, и я смотрю . читаю, ищу способы кто как реализовывал и какая реализация может быть адекватной.. есть одна мысль но я хочу узнать совета, может кто подскажет - правильно ли так делать.
Приложение - Администрирование заказов в автосервисе
У меня есть 3 DAO (в них только crud, транзакций нет, идет работа через Session). Есть сервис, WorkShopService, в котором описана логика работы с данными.
Вот, к примеру, фрагмент кода из сервиса (весь приводить не буду - он длинный довольно)
public class WorkShopServiceImpl implements WorkShopService {
@ConfigProperty(propName = "orderDAO", type = OrderDAO.class)
private OrderDAO orderDAO;
// дао для рабочих-мастеров
@ConfigProperty(propName = "masterDAO", type = MasterDAO.class)
private MasterDAO masterDAO;
// дао для рабочий мест-гаражей (у меня может быть их несколько)
@ConfigProperty(propName = "workplaceDAO", type = WorkPlaceDAO.class)
private WorkPlaceDAO workplaceDAO;
// методы....
public List<WorkPlace> countFreeWorkPlace(Date date) {
// метод выводит список свободных рабочих мест на указанную дату
// исходя из количества мастеров, заказов
}
// методы....
}
Мне нужно сделать метод , чтоб он работал в рамках одной транзакции (может неудачный пример для метода, потому что в нем не происходит обновление данных).
Нашел на зарубежном сайте описание работы с транзакциями через прокси-сервис. То есть вот этот мой WorkShopServiceImpl мы оборачиваем в другой сервис. дублируем методы и в нем в каждом продублированном методе сначала начинаем транзакцию, потом вызываем метод из WorkShopServiceImpl , и после commit или rollback.
Пример кода
public class TransactionalWorkShopService implements WorkShopService {
@ConfigProperty(propName = "service", type = WorkShopService.class)
private WorkShopService service;
@ConfigProperty(propName = "sessionProvider", type = SessionProvider.class)
private SessionProvider sessionProvider;
private Transaction tx;
public TransactionalWorkShopService() {
}
// какие то методы ...
//...
public List<WorkPlace> freeWorkPlace(Date date) {
try {
tx = sessionProvider.getSession().startTransaction();
List<WorkPlace> res = service.freeWorkPlace(date);
tx.commit();
return res;
} catch(HibernateException e) {
handleException(e);
throw e;
}
}
// какие то методы ...
//...
private void handleException(Exception e) {
try {
if(tx != null) tx.rollback();
} catch(Exception e1) {
log.error("Cannot rollback transaction",e1);
}
log.error(e);
}
}
В итоге у нас получается еще один сервис-слой, который управляет чисто транзакциями, а бизнес-слой о них ничего не знает и чисто скоординирован на прикладных задачах. А пользователю backenda мы "подсовываем" реализацию TransactionalWorkShopService, и в таком случае все операции для него являются атомарными..
Такой подход имеет право на жизнь, если не прибегать к использованию средств декларативного управления транзакциями? Или так лучше не делать дабы не создавать новый слой, но в таком случае я пока не знаю, как можно еще сделать метод атомарным.. нагружать слой, который ответственнен только за прикладные задачи, информацией о работе с транзакциями.. это правильно ли будет так?