服务@Transactional异常翻译

时间:2015-05-08 20:23:23

标签: web-services cxf aop spring-transactions

我的网络服务的操作类似于

public Result checkout(String id) throws LockException;

实施为:

@Transactional
public Result checkout(String id) throws LockException {
    someDao.acquireLock(id); // ConstraintViolationException might be thrown on commit
    Data data = otherDao.find(id);
    return convert(data);
}

我的问题是锁定只能在我的服务方法之外发生的事务提交时失败,所以我没有机会将ConstraintViolationException翻译成我的自定义LockException

选项1

建议的一个选项是将服务委托给另一个@Transactional的方法。 E.g。

public Result checkout(String id) throws LockException {
    try {
        return someInternalService.checkout(id);
    }
    catch (ConstraintViolationException ex) {
        throw new LockException();
    }
}

...

public class SomeInternalService {
    @Transactional
    public Result checkout(String id) {
        someDao.acquireLock(id);
        Data data = otherDao.find(id);
        return convert(data);
    }
}

我的问题是:

  • 外部服务尚未使用的内部服务没有合理的名称,因为它们基本上是在做同样的事情。这似乎是设计糟糕的一个指标。
  • 如果我想在另一个地方重用someInternalService.checkout,那么它的合同是错误的,因为无论使用它都可以获得ConstraintViolationException。

选项2

我想过可能会使用AOP来围绕翻译异常的服务提出建议。这似乎对我来说是错误的,因为checkout需要声明它会为客户端抛出LockException,但是实际的服务永远不会抛出它,它会被建议抛出。没有什么可以防止将来从界面中删除throws LockException,因为它似乎不正确。

此外,这种方式更难测试。我无法编写一个JUnit测试来验证抛出异常而不创建弹簧上下文并在测试期间使用AOP。

选项3

checkout中使用手动交易管理?我不是很喜欢这个,因为应用程序中的其他所有内容都使用了声明式样式。

有谁知道处理这种情况的正确方法?

1 个答案:

答案 0 :(得分:0)

没有一种正确的方法。

为您提供更多选择:

  1. 制作DAO事务 - 这不是很好,但可以工作
  2. 创建一个包装服务 - 名为Facade - 其工作是对您提到的事务服务进行异常处理/包装 - 这是一个明确的关注点分离,可以与真正的低级服务共享方法名称< / LI>