الحصول على javax.persistence.TransactionRequiredException في حاوية مدير الكيان المُدار
سؤال
مرحبا لقد خلقت بسيطة 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);
}
وأنا أسميها من 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.حزمة كائنات الوصول إلى البيانات - تحتوي على وحدات JBs (على سبيل المثال.@Singleton، @Stateless، @Stateful).4.حزمة وحدة التحكم - تحتوي على servlet و/أو الفاصوليا المُدارة التي يمكن الوصول إليها من خلال طبقة العرض التقديمي من خلال EL (على سبيل المثال.named ، conversionscoped ، managedbean ، إلخ) 5.طبقة العرض - صفحات JSF (على سبيل المثال.فهرس.xhtml، الخ)
من المهم هيكلة التعليمات البرمجية الخاصة بك بهذه الطريقة لأن المعاملات والأمن والخدمات الأخرى يتم توفيرها تلقائيًا لـ EJBs وهو المكان الذي يجب تنفيذ الثبات فيه.أي أنه يجب الإشارة إلى EntityManager (من خلال @PersistenceContext) في EJBs وليس في كائنات Managed Beans.يجب أن تستخدم الكائنات الموجودة في وحدة التحكم التعليقات التوضيحية @Inject (@EJB). حقن التبعيات.
ما لم تكن العملية الخاصة بك هي القراءة من قاعدة البيانات، فإن الشيء الوحيد الذي تحتاجه هو التعليق التوضيحي "@Transactional" أعلى طريقتك.كما يمكنك تحديده فوق صفك.لكنها ليست الهندسة المعمارية المناسبة.على الأقل عليك إنشاء فئة أخرى وحقنها في حبة الفول الخاصة بك.
إذا كنت تستخدم JavaEE، فيجب عليك استخدام EJB.إنه أمر سهل ولا داعي للقلق بشأن المعاملة.يمكن للحاوية التحكم في كل شيء.