@Stateless与@RequestScoped

2022-09-02 01:44:28

我正在学习使用 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();

    }
}

答案 1

马蒂亚斯就在眼前。

带注释的 bean @Stateless是一个 EJB,缺省情况下它提供容器管理的事务。缺省情况下,如果 EJB 的客户端未提供新事务,则 CMT 将创建新事务。

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

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

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

...EJB 的 @javax.ejb.Asynchronous 注释和 AsyncResponse @Suspended的组合使业务逻辑的异步执行以及最终通知感兴趣的客户端成为可能。任何 JAX-RS 根资源都可以使用@Stateless或@Singleton注释进行注释,并且实际上可以用作 EJB。

在此方案中,@RequestScoped与@Stateless之间的主要区别在于容器可以池化 EJB,并避免一些昂贵的构造/销毁操作,否则这些操作将在每个请求上构造。


答案 2

如果您不想将根资源作为 EJB(通过使用 对其进行注释),则可以使用 .@StatelessUserTransaction

@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;
}

推荐