我正在学习使用JAX-RS进行一些restful api开发,但我的资源类存在问题。
我的理解是,我的资源类应该是RequestScoped,但是,当它被RequestScoped时,我对实体管理器的持久方法的调用会抛出TransactionRequiredException。
如果我将资源类更改为Stateless,那么一切都很好,并且实体管理器可以在没有任何问题的情况下持续存在。
我还是JavaEE的新手,我想知道为什么会发生这种情况,以及@Stateless注释是如何允许持久性上下文正确注入的。我还想知道JAX-RS资源类是无状态的,而不是我看过的大多数教程中的RequestScoped,是否有任何问题。
我在下面包含了一些示例代码来进行说明。
@Path("Things")
//@Stateless //works just fine when em.persist() is called
@RequestScoped //throws transactionrequiredexception when em.persist() is called
public class ThingsResource{
@PersistenceContext(unitName = "persistenceUnitName")
EntityManager em;
public ThingsResource() { }
@POST
@Produces(MediaType.APPLICATION_JSON)
public Response postThing(ThingDTO thing){
ThingEntity newThing = new ThingEntity(thing);
em.persist(newThing);
em.flush();
return Response.created(new URI("/" + newThing.getId()).build();
}
}
Matthias在上
@Stateless注释bean是一个EJB,默认情况下它提供容器管理事务。如果EJB的客户端没有提供一个新事务,CMT将默认创建一个新的事务。
必需属性如果客户端在事务中运行,并且调用企业bean的方法,该方法在客户的交易。如果客户端未与事务,容器在运行方法
Required属性是所有使用容器管理事务运行的企业bean方法界线除非您需要覆盖另一个事务属性。因为事务属性是声明性的,您可以很容易地更改它们后来
在最近关于jax-rs的java-ee-7教程中,Oracle有使用EJB(@Stateless)的示例。
EJB的@javax.EJB.异步注释和@Suspended AsyncResponse允许异步执行业务逻辑,并最终通知感兴趣的客户端。任何JAX-RS根资源都可以用@Stateless或@Singleton注释,实际上可以充当EJB。。
在这种情况下,@RequestScoped和@Stateless之间的主要区别在于,容器可以池化EJB,并避免一些昂贵的构造/销毁操作,这些操作可能是在每个请求上构造的bean所需要的。
当您不想将根资源作为EJB(通过用@Stateless
对其进行注释)时,可以使用UserTransaction
。
@Path("/things")
@RequestScoped
public class ThingsResource{
@POST
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response create(final Thing thing){
utx.begin();
em.joinTransaction();
final ThingEntity thingEntity = new ThingEntity(thing);
em.persist(thing);
utx.commit();
final URI uri = uriInfo.getAbsolutePathBuilder()
.path(Long.toString(thingEntity.getId())).build();
return Response.created(uri).build();
}
@PersistenceContext(unitName = "somePU")
private transient EntityManager em;
@Resource
private transient UserTransaction ut;
@Context
private transient UriInfo uriInfo;
}