【问题标题】:Spring transactions not working + JAX WS + JDBCSpring 事务不工作 + JAX WS + JDBC
【发布时间】:2019-01-10 06:59:11
【问题描述】:

我对这个问题有点恼火。让我们检查一下是否有人实现了类似的东西。

我有一个实现了 8 个 WS 的 java 8 Web 应用程序。其中一些 WS 通过 JDBCTemplate 进行插入和更新(由于性能需要,Hibernate 不是一种选择),如果执行因异常而崩溃,我需要它们回滚。

我在spring app上下文文件(Tomcat的server.xml/context.xml中的jndi资源)中有以下数据源和事务管理器的配置:

  <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/jdbc/source" />
  </bean>
  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
  </bean>

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

另一方面,我有一个对数据库 DBcontroller.class 的唯一访问点,它有一个用于插入、删除和更新的通用方法:

private NamedParameterJdbcTemplate jdbcTemplate;
private DataSource datasource;

@Autowired
public void setDataSource(DataSource dataSource) {
    this.datasource = dataSource;
    this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
@Override
public boolean queryForModifying(String query, SqlParameterSource parameters) {

  int modifiedRows= 0;
  try {
      modifiedRows= this.jdbcTemplate.update(query, parameters);
  } catch (Exception e) {
      e.printStackTrace();
      numRegistrosAfectados = 0;
  }
  return (modifiedRows> 0) ? true : false;
}

最后我有一个WS接口这样:

@WebService
public interface IService{

    @WebMethod
    public method(MethodRequestType request) throws IllegalArgumentException, IllegalAccessException;

}

及其实现:

@WebService(endpointInterface = "com.package.IService")
@HandlerChain(file = "handler-chain.xml")
public class Service implements IService{

    @Autowired
    IDBController dbController;

使用“事务”方法:

@Transactional
private boolean inserts(HashMap<String, Object> input, MethodRequestType request) {.....

它在非 WS 项目上应该可以正常工作,但是我发现没有那么简单的方法可以使这项工作。

起初我认为它没有回滚,但现在我很确定它不会创建事务。

stackoverflow 中有一些类似的帖子,但都没有解决我的问题。我用谷歌搜索了很多,建议的唯一方法是 WS-AtomicTransactions,我从未听说过。

我几乎尝试了 XML 配置文件中的所有内容,我什至尝试过以编程方式管理事务,但由于它是一个连接池,我无法将自动提交设置为 false,以便我可以强制回滚。

如果它对任何人都有用,我为每个 WS 实现了肥皂处理程序,看起来是这样的:

public class ServiceHandler implements SOAPHandler<SOAPMessageContext> {

    private SoapFaultHandler soapFaultHandler;

    @Override
    public boolean handleMessage(SOAPMessageContext context) {

        SOAPMessage message = context.getMessage();
        soapFaultHandler = new SoapFaultHandler(message);
        return SoapMessageHandler.handleMessage(context, "Service name", logger);
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        return soapFaultHandler.handleFault(context, logger, "ServiceName");

    }
    ...
}

【问题讨论】:

    标签: java spring jax-ws jdbctemplate spring-transactions


    【解决方案1】:

    在哪里调用带有@Transactional 注释的方法很重要。例如,如果您有:

    @Service
    public class Service1 {
    
        @Transactional
        public void method1() { ... }
    
        public void method2() {
            method1();
        }
    }
    
    @Service
    public class Service2 {
    
        @Autowired
        private Service1 service1;
    
        public void method1() {
            service1.method1();
        }
    
        public void method2() {
            service1.method2();
        }
    }
    
    • 调用service2.method2()不会创建交易。
    • 调用service2.method1() 将创建一个。

    因为 Spring 处理代理和 AOP 的方式。

    【讨论】:

      【解决方案2】:

      通过阅读spring documentation,您可以阅读以下内容(以粗体表示重要的句子)

      • 仅仅告诉您使用@Transactional 注释来注释您的类是不够的,将@EnableTransactionManagement 添加到您的配置中,然后期望您了解它是如何工作的。本节解释了 Spring Framework 的声明式事务基础架构在事务相关问题的情况下的内部工作原理。

      • 关于 Spring 框架的声明式事务支持,最重要的概念是通过 AOP 代理启用此支持,并且事务建议由元数据驱动(目前基于 XML 或注释的)。 AOP 与事务元数据的组合产生了一个 AOP 代理,该代理使用 TransactionInterceptor 和适当的 PlatformTransactionManager 实现来驱动围绕方法调用的事务。

      • 使用代理时,您应该仅将@Transactional 注释应用于具有公共可见性的方法。如果您使用 @Transactional 注释对受保护的、私有的或包可见的方法进行注释,则不会引发错误,但带注释的方法不会显示配置的事务设置。如果您需要注释非公共方法,请考虑使用 AspectJ(见下文)

      所以请尝试将“插入”方法的修饰符从私有更改为公共

      【讨论】:

      • 我已经试过了,事实上,这是使用公共方法的正确版本,但是当我发布这个时,由于我做了数千次尝试,它被改变了。还是谢谢
      【解决方案3】:

      我终于找到了方法! 我一直都很亲近:

      • 事务方法(如 Gavi 所说)必须是公开的(但这不是问题,因为我之前尝试过)。

      • 事务方法应该在其他类中,而不是在 Webservice 注释类中。

      • 这个类需要自动装配,以便它在 Spring 上下文中。

      • 在这个类中,我自动装配了一个 DbController 实例。

      这就是一切。

      我的主要问题是,我模拟了这个类并用“新”实例化了它,而不是让 Spring 发挥它的魔力。

      感谢回复,希望能帮到别人!

      【讨论】:

      • 您说:事务方法应该在其他类中,而不是在Webservice注解的类中。但是对于公共策略:通过使控制器层成为事务所有者并假设公共控制器方法在任何情况下都不应该调用另一个方法。我们对你的话感到矛盾,所以,我的问题。我们如何跨具有 WS 层的应用程序管理事务?提示:- Controller 层和 WebService 层始终是同一层。
      猜你喜欢
      • 1970-01-01
      • 2015-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-25
      • 2014-11-25
      相关资源
      最近更新 更多