@Stateless vs @RequestScoped

我正在学习使用JAX-RS进行一些宁静的api开发,并且对我的资源类有一个问题。

我的理解是我的资源类应该是RequestScoped,但是,当它是RequestScoped时,我调用实体管理器的persist方法会抛出TransactionRequiredException。

如果我将我的资源类更改为无状态,那么一切都很好,实体管理器可以保持没有任何问题。

我仍然是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(); } } 

马蒂亚斯就是现场。

@Stateless带注释的bean是一个EJB,它默认提供Container-Managed-Transactions 。 如果EJB的客户端没有提供新事务,CMT将默认创建一个新事务。

必需属性如果客户端在事务中运行并调用企业bean的方法,则该方法在客户端的事务中执行。 如果客户端未与事务关联,则容器在运行该方法之前启动新事务。

Required属性是使用容器管理的事务划分运行的所有企业bean方法的隐式事务属性。 除非需要覆盖其他事务属性,否则通常不会设置Required属性。 由于事务属性是声明性的,因此您可以在以后轻松更改它们。

在jax-rs最近的java-ee-7 tuturial中 ,Oracle有使用EJB的例子(@Stateless)。

… EJB的@javax.ejb.Asynchronous批注和@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; @Resuorce private transient UserTransaction ut; @Context private transient UriInfo uriInfo; }