在容器管理的实体管理器中获取 javax.persistence.TransactionRequiredException

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

  •  20-12-2019
  •  | 
  •  

嗨我创建了一个简单的 JSF + JPA 应用。我的网络应用程序由一个 Entity, , A 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 中的方法自动创建事务,而不为托管 Bean 自动创建事务。如果您在 JEE7 容器中,您可以尝试将 @Transactional 添加到您的 Controller 托管 bean 中,否则您需要使用 UserTransation 来管理事务。

这是我使用过的一段代码:

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

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

我从 servlet 中调用它:

 @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.实体包 - 包含直接映射到数据库表的实体对象。3.数据访问对象包 - 包含 EJB(例如@Singleton、@Stateless、@Stateful)。4.控制器包 - 包含由表示层通过 EL 访问的 servlet 和/或托管 bean(例如@Named,@conversionscoped,@managedBean等)5。表示层 - JSF 页面(例如索引.xhtml 等)

以这种方式构建代码非常重要,因为事务和安全性以及其他服务是自动为 EJB 提供的,而 EJB 正是应该执行持久性的地方。也就是说,对 EntityManager 的引用(通过 @PersistenceContext)应该在 EJB 中而不是在 Managed Beans 对象中进行。控制器中的对象应该使用@Inject(@EJB)注释 注入 依赖关系。

除非您的操作是从数据库读取,否则您只需要一件事就是方法上方的“@Transactional”注释。您也可以在班级上方定义它。但这不是正确的架构。至少您必须创建另一个类并将其注入到您的 bean 中。

如果您使用JavaEE,则应该使用EJB。这很简单,您无需担心交易。容器可以控制整个事情。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top