【问题标题】:How to make a RestController transactional?如何使 RestController 具有事务性?
【发布时间】:2019-10-27 10:31:44
【问题描述】:

我知道使控制器具有事务性并不是最佳实践,但我想尝试here 讨论的解决方案

根据Spring MVC documentation 17.3.2

在使用需要为控制器对象创建代理的功能(例如 @Transactional 方法)时,使用带注释的控制器类时会发生一个常见的陷阱。通常您会为控制器引入一个接口,以便使用 JDK 动态代理。要完成这项工作,您必须将@RequestMapping 注释以及任何其他类型和方法级别的注释(例如@ModelAttribute、@InitBinder)移动到接口以及映射机制只能“看到”由代理。

如果我“将所有方法注释移至其接口”,我应该能够使 RestController 方法具有事务性吗?

在这种假设下,我编写了以下代码,但仍然没有给我一个事务性的 doSth() 方法:

public interface SomeController{
   @Transactional
   @RequestMapping(...)
   void doSth()
}

@RestController
public class SomeControllerImpl implements SomeController{
   @Override
   public void doSth(){...}
}

web.xml
    <servlet>
        <servlet-name>someServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>...</init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>someServlet</servlet-name>
        <url-pattern>...</url-pattern>
    </servlet-mapping>

context.spring.xml
    <jee:jndi-lookup id="dataSource" jndi-name="jdbc/project" resource-ref="true" />
    <tx:annotation-driven />
    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

有人可以帮助解释为什么这不起作用吗?有没有办法让 RestController 中的方法具有事务性?

【问题讨论】:

  • 好奇:你为什么称你的控制器为Service?是否应该命名为SomeWebController
  • 该代码无法编译,因为 doSth 在类中必须是 public。 --- 无论如何,你怎么知道它没有给你一个事务性的doSth() 方法?你没有具体说明你是怎么知道的,所以据我们所知,你错了,它确实使它成为事务性的。
  • 嘿 Andreas,我在 SomeWebServiceImpl 中自动编写了一个 SessionFactory 并用它来 getCurrentSession().getTransaction() 并且没有事务
  • 你配置了 TransactionManager bean 吗?
  • 具体来说,我在 doSth() 中调用了 SomeService.transactionalMethod() (传播类型为Required)两次,发现这两个调用使用不同的事务,如果 doSth 则不会这样() 已经是事务性的

标签: java spring rest transactions


【解决方案1】:

尝试将@Transactional 注解放在SomeControllerImpl 类上,而不是在接口上。

@Transactional 如果您使用基于接口的代理,注释将在接口上正常工作。注释未被继承的事实意味着如果您使用基于类的代理,则基于类的代理将无法识别事务设置。

此外,Spring 团队的 建议您只使用 @Transactional 注释来注释具体类,而不是注释接口。
Spring Docummentation

【讨论】:

  • 谢谢@Ilya 我确实首先尝试了正常的方式 - 将“@Transactional”注释放在类 SomeControllerImpl 而不是接口上,但它没有给我一个事务方法。我想这是因为“映射机制只能'看到'代理暴露的接口”?这就是为什么我采用我的问题中提到的方式
  • @wayne 如果你关于@RequestMapping 那么它也可以放在一个具体的类上。关于事务,我没有注意到您正在使用 JTA 事务管理器。那么我有几个问题:你想在你的rest控制器中获得XA事务吗?您使用哪种 Java EE 服务器?
【解决方案2】:

要启用基于注释的事务行为,您需要在 tx:annotation-driven 中提及 transactionManager。

例如: &lt;tx:annotation-driven transaction-manager="transactionManager"/&gt;

这应该可以解决您的问题。如果您觉得这有帮助,请告诉我。

【讨论】:

  • 感谢@venkat。我把事务管理器放进去,但没有帮助。我没有这样做,因为正如 Spring Doc 第 15.6.5 节中提到的“如果要连接的 PlatformTransactionManager 的 bean 名称,您可以省略 标记中的 transaction-manager 属性名称为 transactionManager。"
  • @wayne,您可以共享日志吗?你能分享服务器启动日志和你发起事务调用时的日志吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-19
  • 1970-01-01
  • 1970-01-01
  • 2011-10-26
  • 2017-04-07
  • 1970-01-01
相关资源
最近更新 更多