2012-03-07 56 views
6

我正在使用JAX-RS提供基于HTTP的接口来管理数据模型。数据模型存储在数据库中,并通过JPA进行交互。如何使用JAX-RS,Spring和JPA管理事务

这让我修改界面,数据模型,以适应REST客户端,大多似乎运作得非常好。但是,我不确定如何处理由JAX-RS资源提供的方法需要事务的场景,这会影响JPA获取,更新,提交on-tx-end模式,因为只有事务包装get操作,所以更新从不提交。如果单个REST操作需要多个JPA操作,我可以看到发生同样的问题。

由于我使用Spring的事务支持,很明显的事情是应用@Transactional在JAX-RS资源,这些方法。然而,为了实现这个目标,Spring需要管理JAX-RS资源的生命周期,我知道的用例中有资源是在需要时通过`new'创建的,这使我有点紧张。

我能想到以下解决方案:

  1. 更新我的JPA的方法来提供我想要的一切,从我的REST接口做原子的交易管理版本。应该工作,将事务保留在JAX-RS层之外,但是阻止获取,更新,提交on-tx-end模式,并且意味着我需要创建非常精细的JPA接口。
  2. 注入资源对象;但它们通常是有状态的,至少保存着正在与之交互的对象的ID
  3. 放弃资源的层次结构,并在管理根的整个层次结构的根处注入大而无状态的超级资源;没有凝聚力,大的服务
  4. 有一个注入的,无状态的,支持事务的帮助对象的层次结构,它能“隐藏”实际的资源;资源被实例化并保存状态,但委托方法调用到帮助对象

任何人有任何建议吗?我很可能错过了某个关键点。


更新 - 解决了周围没有获取,更新交易的,提交-ON-TX-密切流动,我可以公开了EntityManager合并(对象)的方法和手动调用它。不够整齐,但并没有解决更大的问题。


更新2 @skaffman 代码示例: 在JPA服务层,注入,注释工作

public class MyEntityJPAService { 
... 
@Transactional(readOnly=true) // do in transaction 
public MyEntity getMyEntity(final String id) { 
    return em.find(MyEntity.class, id); 
} 

在JAX-RS资源,通过新的,没有交易产生

public class MyEntityResource { 
... 
private MyEntityJPAService jpa; 
... 
@Transactional // not injected so not effective 
public void updateMyEntity(final String id, final MyEntityRepresentation rep) { 
    MyEntity entity = jpa.getMyEntity(id); 
    MyEntity.setSomeField(rep.getSomeField()); 
    // no transaction commit, change not saved... 
} 

回答

4

我有几点建议

  1. 在JPA和JAX-RS图层之间引入一个图层。该层将由Spring管理的@Transactional bean组成,并且将从其组件JPA调用中组成各种业务级操作。这与你的(1)有些相似,但保持JPA层简单。

  2. 包装在事务代理的JAX-RS对象使用TransactionProxyFactorybean与Spring-MVC,它提供了相同(或类似)功能,包括@PathVariable@ResponseBody

  3. 编程方式替换JAX-RS。这会检测到您的@Transactional注释并生成一个代理来表彰他们。

  4. 使用@Configurable和AspectJ LTW,即使您使用`new创建对象,Spring也可以兑现@Transactional。请参阅8.8.1 Using AspectJ to dependency inject domain objects with Spring

+0

这些建议是按照首选顺序排列的吗? – brainOverflow 2013-04-19 17:19:08

相关问题