具有远程服务调用的事务服务层

时间:2018-01-23 20:44:49

标签: database spring remote-server transactional

答案可以涵盖所有框架,但我对Spring MVC案例特别感兴趣。我正在重构一个访问内部数据库和远程服务的服务层。这些方法应该是事务性的,并且它们需要来自远程服务的数据。这是类似的虚拟代码:

@Service
public class MyService {
    @Autowired
    private SomeRepository repository1;

    @Autowired
    private OtherRepository repository2;

    @Autowired
    private RemoteGateway remoteGateway;

    @Transactional
    public void updateState(Long id) {
        Item item1 = repository1.get(id)
        item1.setSomeVal(remoteGateway.getValue());
        repository1.save();

        repository2.doSomethingElse(item1.getOtherVal());
    }
}

以这种方式实施起来更容易。但是有许多缺点,例如当远程服务调用失败时不必要地创建和回滚事务,由于远程服务调用而导致的事务更长,并且可能更多。我正在考虑将服务调用移动到单独的非事务性方法,并调用事务方法,就像在下面的代码片段中完成一样

@Service
public class MyService {
    @Autowired
    private SomeRepository repository1;

    @Autowired
    private OtherRepository repository2;

    @Autowired
    private RemoteGateway remoteGateway;

    public SomeType updateState(Long id) {
        SomeType valueFromRemote = remoteGateway.getValue();
        updateState(id, valueFromRemote);
    }

    @Transactional
    public void updateState(Long id, SomeType valueFromRemote) {
        Item item1 = repository1.get(id)
        item1.setSomeVal(valueFromRemote);
        repository1.save();

        repository2.doSomethingElse(item1.getOtherVal());
    }
}

假设remoteGateway具有缓存,适当的超时,断路器以便无法无限期挂起并且在缓存间隔中已经询问值时会更快,重构是否有意义?或者什么是更好的设计决策?

1 个答案:

答案 0 :(得分:1)

我认为如果事务的长度是一个问题并且在调用它之前你知道在事务方法中需要什么值,那么这是一个很好的重构。如果需要从远程服务获取许多值,可以考虑异步调用服务。

只有一个问题 - 如果您使用默认的"代理"如果你调用同一个bean的方法,它就不起作用了。在您的情况下,从updateState(id, valueFromRemote)调用updateState(Long id)将不会在事务中运行,因为不会执行代理代码(在调试事务方法时,您可以在调用堆栈中看到代理支持)。要解决它,你可以

  • 将事务方法移动到另一个bean
  • 或在aspectj模式下使用transactionManager。请参阅Spring doc
相关问题