在容器管理的实体管理器中获取 javax.persistence.TransactionRequiredException
题
嗨我创建了一个简单的 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。这很简单,您无需担心交易。容器可以控制整个事情。