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

时间:2014-06-02 18:50:09

标签: java jsf jpa java-ee-7

您好我创建了一个简单的JSF + JPA应用程序。我的网络应用包含EntityManagedBean和部分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 facelet:

...
<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>

3 个答案:

答案 0 :(得分:2)

仅针对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 :(得分:0)

查看了代码段。我认为这是一个设计问题,而不是技术问题。我建议你应该考虑如下构建你的应用程序: 1.数据库层 - MySql。 2.实体包 - 包含直接映射到数据库表的实体对象。 3.数据访问对象包 - 包含EJB(例如@Singleton,@ Stateless,@ Stateful)。 4. Controller Package - 包含表示层通过EL访问的servlet和/或托管bean(例如@ Natamed,@ ContextScoped,@ ManagedBean等) 5.表示层 - JSF页面(例如index.xhtml等)

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

答案 2 :(得分:0)

除非您的操作是从数据库中读取,否则您需要的只有一件事是&#34; @Transactional&#34;方法上方的注释。您也可以在课程上方定义它。 但它不是合适的架构。至少你必须创建另一个类并将其注入你的bean。

如果您使用的是JavaEE,则应使用EJB。这很简单,您不必担心交易。容器可以控制整个事物。