在JPA/JTA事务中调用HTTP服务 - 事务完整性

问题描述:

我有一个使用容器管理持久性的JSF/EJB/JPA应用程序。有一种情况是通过HTTP向外部服务发起呼叫,其中有一个费用,这个费用被分配回请求用户。在当前实现中,通过在后台定期运行 的EJB定时器方法执行进行HTTP请求的过程。在JPA/JTA事务中调用HTTP服务 - 事务完整性

计时器方法可能不得不在一次调用中处理多个请求,但每个请求需要独立处理,独立于将 成本分配给用户,也就是说。如果用户A没有足够的积分购买 书籍,则这阻止了用户B成功购买了书籍,导致其 余额因回滚而被扣除。

为了对每个 请求的独立处理提供对事务分界的控制,我对定时器方法 所在的类使用bean管理事务。这是什么,我现在已经有了一个Java的伪代码版本:

@Stateless 
@TransactionManagement(TransactionManagementType.BEAN) 
public class MessageTimer { 
    private void processMessages(UserMessage msg) { 
    tx.begin(); 
    em.joinTransaction(); 

    try { 
     userData = em.find(..., PESSIMISTIC_WRITE); 

     if(user has enough credit) { 
     debit cost from user; 

     status = make external http request to order book from supplier; 
     if(status == success) { 
      commit = true; 
     } 
     } 
    } catch(Exception) { 
     tx.rollback(); 
    } 

    if(commit) { 
     tx.commit(); 
    } 
    else { 
     tx.rollback(); 
    } 
    } 
} 

这样的想法是,我开始交易,假设成功和借记从 用户的成本,调用http服务和如果成功则返回,否则返回。

我有一种不安的感觉,我可能不会在任何地方大致正确附近这种 设计,尤其是具有内部 冗长的HTTP调用(使用JAX-RS实际完成)的pessimistic_write交易。我想知道是否可以首先在交易 借记用户(开始/借记/提交),进行http呼叫,然后在发生任何错误 时扣除用户,但没有交易完整性。

对我来说,这是一个新的领域,任何人都可以指出我正确的方向,有没有一个 做我想做的事情?

很多谢谢。

p.s.我正在使用Seam 3的glassfish 3.1堆栈

我不知道jax-rs通信层是如何的。如果通信是单线程的,那么你写的代码是一个长时间运行的事务。这可能会让你的应用程序变慢。

我不是一个技术大师,但我可以建议是 -

信用账户,使JAX-RS调用一个线程。在这种情况下,在将呼叫发送到远程节点之前,交易将被关闭。它不会是一个长时间运行的事务,所以应用程序会更快。

+0

嗨,我在EJB容器中运行,所以不能使用我认为的线程。我需要http调用的结果来确定是否发生了成本,所以我不确定我有什么选项。这是一个长期运行的交易,当然,但我没有看到它的方式。 – Oversteer 2011-05-28 11:37:49