【问题标题】:Spring transaction managementSpring事务管理
【发布时间】:2015-07-16 15:58:50
【问题描述】:

我正在开发 spring4 mvc 以在我们的新 Web 应用程序中引入,目前我们正在使用 struts1.x 并希望使用新框架来支持 html5/ajax 请求尽可能简单,并希望使用 DI 和 spring 的力量网络流支持。

目前在我们的 struts1.x 应用程序中,数据库事务管理是在我们的自定义 GenericAction 中完成的,它是 Action 的子类,在 GenericAction 中,我们从数据源获取连接并切换到子类,然后引发任何异常然后捕获并回滚,否则提交使得数据库原子性(事务管理)在一个地方完成。所有模块操作类都应该扩展 GenericAction 以便数据库连接可用并执行与模块相关的内容,完成连接后将在 GenericAction 中回滚或提交,如上所述。

在 Spring 中,Transaction 的范围以 @Transactional 注释开始,然后以 Service Class 中的方法结束,因为服务类标记为 @Transactional。这对我来说不是可行的解决方案。在开始之前,我已经阅读了一些与 spring 交易相关的文件,以下是我的问题。 我使用 HibernateTransactionManager 作为事务管理器

  1. 在 Web 请求或任何类(在单元测试的情况下)的情况下,事务应该从拦截器开始。

  2. 事务应该以在 web 请求的情况下执行拦截器之后结束,或者在单元测试的情况下以任何类结束。

  3. 如果引发任何异常,我们的 HandlerExceptionResolverImpl 处理程序将执行,然后连接应该回滚。

任何解决方法或最佳实践将不胜感激。

谢谢 多莱拉杰

【问题讨论】:

  • 对于 q3,可能与以下问题有关:stackoverflow.com/questions/29955159
  • 为什么服务方法上的@Transactional 不可接受?这在问题中并不清楚......单元测试是拦截器中唯一关心的事务吗?
  • 对于您如何描述问题,在我看来@transactional 范式是一个很好的解决方案;它允许您指定需要回滚的异常类(第 3 点)并且默认满足第 1 点和第 2 点
  • @Gabor Bakos - 感谢您的回复,这正是我所做的
  • @Shiraaz。 M -- 就单元测试而言,不需要拦截器,当是 web/ajax 请求时需要拦截器。我通过在 struts 中复制现有实践来设计应用程序,最终所有开发人员都可以轻松开发

标签: java spring hibernate spring-mvc transactions


【解决方案1】:

在我看来,您可以通过遵循 Spring 在其 org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(Object, TransactionDefinition) 中所做的操作,对当前应用程序进行最小的更改来实现这一点。详细来说,我认为以下内容应该可行:

  1. 在 GenericAction 上,从数据源获取连接(正如您已经完成的那样)
  2. 通过其持有者将连接与当前数据源绑定: TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
  3. 最终,将事务提交为 org.springframework.jdbc.datasource.DataSourceTransactionManager.doCommit(DefaultTransactionStatus)。

无论如何,Spring 的http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/support/TransactionTemplate.html 可以帮助实现您想要的任何程序化事务场景。只需要确保正确的事务资源绑定到打开的事务。

希望这会有所帮助。

【讨论】:

  • @Dhorrairaajj:很高兴它有帮助。我认为您的代码中最后缺少的部分是优雅地关闭会话和底层资源。
【解决方案2】:

感谢您的回复。您的帖子/建议促使您执行以下操作

我编写了一个名为 TxtManager 的拦截器,下面是执行事务管理的方法。

public boolean preHandle(HttpServletRequest request,
    HttpServletResponse response, Object handler) throws Exception
{
    Session session = sessionFactory.openSession();
    SessionHolder hold = new SessionHolder(
        session);
    TransactionSynchronizationManager.bindResource(sessionFactory, hold);
    // passing null would accept the default transaction definition.
    status = transactionManager.getTransaction(null);

    return true;
}


public void afterCompletion(HttpServletRequest request,
    HttpServletResponse response, Object handler, Exception ex)
    throws Exception
{
    Exception hanlderEx = (Exception) request
        .getAttribute(HandlerExceptionResolverImpl.EXCEPTION_KEY);

    if (hanlderEx != null)
    {
        transactionManager.rollback(status);
    }
    else
    {
        transactionManager.commit(status);
    }
}

在负责处理异常的HandlerExceptionResolverImpl类中,将异常对象放入request中,并在拦截器的afterCompletion方法中读取相同的异常进行回滚或提交。

在(preHandler 和 afterCompletion)之间,我们将使用标准实践来执行与模块相关的内容,包括任何其他拦截器。可能不支持单元测试,我会检查单元测试的其他替代方案。

我们终于可以根据您的建议模拟现有的框架了,谢谢

任何改进这一点的建议将不胜感激!!..

谢谢 多莱拉杰

【讨论】:

    猜你喜欢
    • 2013-06-30
    • 2017-05-29
    • 2012-10-16
    • 2015-02-08
    • 2016-12-02
    • 1970-01-01
    • 2017-02-20
    相关资源
    最近更新 更多