@Transactional в методе контроллера не выполняет откат транзакций, но в методах обслуживания - PullRequest
1 голос
/ 02 марта 2020

Отказ от ответственности: Да, я знаю, что @Transactional в идеале следует ставить только на методы обслуживания.

Я поддерживаю старое и плохо спроектированное приложение, в котором все деловые логи c загроможден в методах Controller, и эти методы не являются транзакционными, поэтому ошибки не вызывают откат и данные повреждены.

Нашей команде необходимо быстрое исправление, чтобы включить откат ошибок для этого унаследованного приложения. , поэтому было решено поместить @Transactional в методы Controller (а не рефакторизовать приложение, которое потребовало бы значительных усилий).

Однако, когда я попробовал следующее для метода Controller, он не свернулся назад мое исключение:

@Controller
public class ReviewDetailsController extends BaseController{

@RequestMapping(value={"/testException"}, method = RequestMethod.POST)
@Transactional(readOnly = false, rollbackFor = Exception.class)
public void testException(@RequestParam(required = true) String planId) throws Exception {  

    // Simulate some simple DB change: we'll change a Date to a dummy value, 03:33:33
    Plans plan = planService.findById(new Integer(planId));
    PlanWorkflow pw = processService.getLatestWorkflow(plan);
    SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
    Date d = sdf.parse("12/06/2019 03:33:33");
    pw.setCreatedDate(d);

    // Save it
    processService.savePlanWorkflow(pw);

    // Exception test
    throw new Exception("EXCEPTION TEST");          

}

С другой стороны, когда поместили те же самые логики c в пример метода класса обслуживания, он успешно откатился.

Контроллер теперь вызывает метод Service, метод Service имеет @ Transactional

@RequestMapping(value={"/testException"}, method = RequestMethod.POST)
@Transactional(readOnly = false, rollbackFor = Exception.class)
public void testException(@RequestParam(required = true) String planId) throws Exception { 

    // Call a Service method with the exact same logic from the Controller
    processService.testException(planId);   
}

Service

@Component
public class ProcessServiceImpl implements ProcessService {

    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void testException(@RequestParam(required = true) String planId) throws Exception {  

        // Simulate some simple DB change: we'll change a Date to a dummy value, 03:33:33
        Plans plan = planService.findById(new Integer(planId));
        PlanWorkflow pw = processService.getLatestWorkflow(plan);
        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
        Date d = sdf.parse("12/06/2019 03:33:33");
        pw.setCreatedDate(d);

        // Save it
        processService.savePlanWorkflow(pw);

        // Exception test
        throw new Exception("EXCEPTION TEST");          

    }

Теоретически все говорят, что я должен быть Чтобы присоединить @Transactional к методам контроллера (хотя это не рекомендуется - но я все еще должен быть в состоянии сделать это). Так почему же методы Контроллера не подберут или не соблюдают его?

applicationContext:

<context:component-scan base-package="mypackage.myapp">
</context:component-scan>

<jpa:repositories base-package="mypackage.myapp.dao"/>

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="/META-INF/persistence.xml"/>
</bean>

<cache:annotation-driven/> 

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
      p:cache-manager-ref="ehcache"/>

<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
      p:config-location="/WEB-INF/ehcache.xml"/>


То, что я пробовал:
  1. Заставить контроллер реализовать интерфейс для включения «JDK Proxy». Теперь контроллер implements ControllerInterface, где были извлечены сигнатуры метода (Source -> Refactor -> Extract Interface в Eclipse).
  2. Добавьте <aop:aspectj-autoproxy proxy-target-class="true" />, чтобы включить «CGLIB Proxy».

Связанные темы, откуда я получил эти идеи: 1 , 2 .

Но ничего из этого не помогло. Данные по-прежнему не возвращаются с контроллера.

Аналогичный поток: 1 . Решение не предлагается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...