получение javax.persistence.TransactionRequiredException в управляемом контейнером Entity Manager

StackOverflow https://stackoverflow.com//questions/24001269

  •  20-12-2019
  •  | 
  •  

Вопрос

Привет, я создал простой JSF + JPA приложение.мое веб-приложение состоит из Entity, а ManagedBean и немного JSF страницы.Его цель — создать и сохранить объект в базе данных MySQL.я получил javax.persistence.TransactionRequiredException каждый раз, когда я хочу сохранить объект в PersistenceContxt.Однако при введении UserTransaction в класс контроллера все работает без проблем, но я не могу понять, почему?Потому что предполагается, что не нужно добавлять UserTransaction потому что он управляется контейнером.Я ошибаюсь или что?или в моих кодах есть другие проблемы?

Вот мой код ManagedBean:

@ManagedBean
@SessionScoped
public class Controller {
    @PersistenceContext
    private EntityManager em;
    private Book book;
    public Controller() {}

    public Book getBook() {
        return book;
    } 

    public void setBook(Book book) {
        this.book = book;
    }

    public String createBook() {
        book = new Book();
        return "create";
    }

    public String showResponse() {
        em.persist(book);
        return "response";
    }
}

Здесь create.xhtml фейслет:

...
<h:form>
    <h:panelGrid columns="2">
        <h:outputText>Title</h:outputText>
        <h:inputText value="#{controller.book.title}" />
    </h:panelGrid>
</h:commandButton action="#{controller.showResponse()}" value="Response" />
...

и это Persistence.xml содержание:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="JPATestPU" transaction-type="JTA">
    <jta-data-source>jdbc/mysql</jta-data-source>
    <properties>
      <property name="javax.persistence.schema-generation.database.action" value="create"/>
    </properties>
  </persistence-unit>
</persistence>
Это было полезно?

Решение

Транзакция автоматически создается только для методов в EJB, а не для управляемых компонентов.Если вы находитесь в контейнере JEE7, вы можете попытаться добавить @Transactional в управляемый компонент контроллера, в противном случае вам придется использовать UserTransation для управления транзакцией.

Вот фрагмент кода, который я использовал:

@Transactional
public class PersonService {
    @PersistenceContext 
    private EntityManager em;

    public void savePerson(Person person) {
    em.persist(person);
}

И я вызываю это из сервлета:

 @WebServlet("/MyServlet")
 public class MyServlet extends HttpServlet {
    @Inject
    PersonService service;
  ....
  service.savePerson(p);
  System.out.println("Person saved");

В базе данных я вижу, что он был сохранен, а в журналах вижу следующие сообщения:

INFO: Managed bean with Transactional annotation and TxType of REQUIRED called outside a transaction context.  Beginning a transaction...
INFO: Person saved

Итак, как вы можете видеть, создается новая транзакция и объект сохраняется.

Другие советы

Посмотрев фрагмент кода.Я думаю, что это скорее вопрос дизайна, чем технической проблемы.Я предлагаю вам рассмотреть возможность структурирования вашего приложения следующим образом:1.Уровень базы данных — MySql.2.Пакет Entities — содержит объекты сущностей, которые напрямую сопоставляются с таблицами вашей базы данных.3.Пакет объектов доступа к данным — содержит EJB (например,@Singleton, @Stateless, @Stateful).4.Пакет контроллера — содержит сервлет и/или управляемые компоненты, доступ к которым осуществляется на уровне представления через EL (например,@Named, @conversionscoped, @managedbean и т. Д.) 5.Уровень представления — страницы JSF (например,index.xhtml и т. д.)

Важно структурировать свой код таким образом, поскольку транзакции, безопасность и другие службы автоматически предоставляются для EJB, и именно здесь должно выполняться сохранение.То есть ссылка на EntityManager (через @PersistenceContext) должна быть сделана в EJB, а не в объектах Managed Beans.Объекты в контроллере должны использовать аннотации @Inject (@EJB) для вводить зависимости.

Если ваша операция не заключается в чтении из базы данных, вам нужна только одна вещь — аннотация «@Transactional» над вашим методом.Также вы можете определить его над своим классом.Но это не правильная архитектура.По крайней мере, вам нужно создать еще один класс и внедрить его в свой компонент.

Если вы используете JavaEE, вам следует использовать EJB.Это легко, и вам не нужно беспокоиться о транзакции.Контейнер может контролировать все.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top