@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();

    }
}

Ответ 1

Маттиас находится на месте.

A @Stateless annotated bean - это EJB, который по умолчанию предоставляет Контейнер-управляемые транзакции. CMT по умолчанию создаст новую транзакцию, если клиент EJB не предоставил ее.

Обязательный атрибут. Если клиент работает в транзакции и вызывает метод предприятия bean s, метод выполняется в пределах клиентов. Если клиент не связан с транзакции, контейнер запускает новую транзакцию перед запуском Метод.

Обязательный атрибут - это неявный атрибут транзакции для всех enterprise bean методы, выполняемые с транзакцией, управляемой контейнером демаркация. Обычно вы не устанавливаете атрибут Required, если вам необходимо переопределить другой атрибут транзакции. Потому как атрибуты транзакций являются декларативными, их можно легко изменить позже.

В недавнем java-ee-7 tuturial на jax-rs у Oracle есть пример использования EJB (@Stateless).

... комбинация EJB @javax.ejb.Асинхронная аннотация и @Suspended AsyncResponse позволяет асинхронное выполнение бизнес-логику с возможным уведомлением заинтересованного клиента. Любой корневой ресурс JAX-RS можно аннотировать с помощью @Stateless или @Singleton и может, по сути, функционировать как EJB..

Основное различие между @RequestScoped vs @Stateless в этом сценарии будет состоять в том, что контейнер может объединить EJB и избежать некоторых дорогостоящих операций построения/уничтожения, которые могут потребоваться для beans, которые в противном случае были бы построены для каждого запроса.

Ответ 2

Если вы не хотите, чтобы ваш корневой ресурс был 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;
}