Ich verwende Wildfly 10.0.0 Final, Java EE7, Maven und JPA 2.1. Wenn ich meine Datenbank nach Datensätzen abfrage, funktioniert es einwandfrei und listet die Mitarbeiter auf. Wenn ich jedoch versuche, einen neuen Mitarbeiter beizubehalten, gibt es die folgende Ausnahme:
javax.servlet.ServletException: WFLYJPA0060: Transaction is required to perform this operation (either use a transaction or extended persistence context)
javax.faces.webapp.FacesServlet.service(FacesServlet.Java:671)
io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.Java:85)
io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.Java:62)
io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.Java:36)
org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.Java:78)
io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.Java:43)
io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.Java:131)
...
Ich versuche dies mit JSF und CDI-Beans zu implementieren. Ich habe eine JTA-Datenquelle, die ich in meiner Datei persistence.xml konfiguriert habe:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
<persistence-unit name="MyPersistenceUnit">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>Java:/EmployeesDS</jta-data-source>
<class>com.home.entity.Employee</class>
<properties>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hbm2ddl.auto" value="update"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
</properties>
</persistence-unit>
</persistence>
Die CDI-Bean ist unten zu sehen. Es ist relativ einfach, es gibt eine Methode, um 25 Mitarbeiter aufzulisten, und eine andere, die einen bestimmten Mitarbeiter beibehalten soll:
@Named
@RequestScoped
public class DataFetchBean {
@PersistenceContext
EntityManager em;
public List getEmployees() {
Query query = em.createNamedQuery("findEmployees");
query.setMaxResults(25);
return query.getResultList();
}
public String getEmployeeNameById(final int id) {
addEmployee();
Query query = em.createNamedQuery("findEmployeeNameById");
query.setParameter("empno", id);
Employee employee = (Employee) query.getSingleResult();
return employee.getFirstName() + " " + employee.getLastName();
}
public void addEmployee() {
em.persist(new Employee(500000, new Date(335077446), "Josh", "Carribean", 'm', new Date(335077446)));
}
}
Die Mitarbeiter-Entitätsklasse finden Sie unten:
@NamedQueries({
@NamedQuery(
name = "findEmployees",
query = "select e from Employee e"
),
@NamedQuery(
name = "findEmployeeNameById",
query = "select e from Employee e where e.empNo = :empno"
)
})
@Table(name = "employees")
public class Employee {
@Id
@Column(name = "emp_no")
private int empNo;
@Basic
@Column(name = "birth_date")
private Date birthDate;
@Basic
@Column(name = "first_name")
private String firstName;
@Basic
@Column(name = "last_name")
private String lastName;
@Basic
@Column(name = "gender")
private char gender;
@Basic
@Column(name = "hire_date")
private Date hireDate;
public Employee() { }
public int getEmpNo() {
return empNo;
}
public void setEmpNo(int empNo) {
this.empNo = empNo;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public Date getHireDate() {
return hireDate;
}
public void setHireDate(Date hireDate) {
this.hireDate = hireDate;
}
public Employee(int empNo, Date birthDate, String firstName, String lastName, char gender, Date hireDate) {
this.empNo = empNo;
this.birthDate = birthDate;
this.firstName = firstName;
this.lastName = lastName;
this.gender = gender;
this.hireDate = hireDate;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
if (empNo != employee.empNo) return false;
if (gender != employee.gender) return false;
if (birthDate != null ? !birthDate.equals(employee.birthDate) : employee.birthDate != null) return false;
if (firstName != null ? !firstName.equals(employee.firstName) : employee.firstName != null) return false;
if (lastName != null ? !lastName.equals(employee.lastName) : employee.lastName != null) return false;
if (hireDate != null ? !hireDate.equals(employee.hireDate) : employee.hireDate != null) return false;
return true;
}
@Override
public int hashCode() {
int result = empNo;
result = 31 * result + (birthDate != null ? birthDate.hashCode() : 0);
result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
result = 31 * result + (int) gender;
result = 31 * result + (hireDate != null ? hireDate.hashCode() : 0);
return result;
}
}
Danke im Voraus!
Grundsätzlich ist ein Container-verwalteter JTA-fähiger Persistenzkontext mit Bean-verwalteten Transaktionen (BMT) vorhanden.
Daher sollten Sie neben Ihrer EntityManager
auch Ihre DataFetchBean
in Ihre UserTransaction
einfügen, um eine Transaktion zu starten, festzuschreiben oder zurückzusetzen.
@Named
@RequestScoped
public class DataFetchBean {
@PersistenceContext
EntityManager em;
@Resource
private UserTransaction userTransaction;
...
}
Anschließend müssen Sie in Ihrer addEmployee
-Methode Ihre Transaktion starten und anschließend festschreiben, damit Ihre Änderungen an Ihrer Mitarbeiterentität in die Datenbank übernommen werden können.
public void addEmployee() throws Exception {
Employee employee = new Employee(500000, new Date(335077446), "Josh", "Carribean", 'm', new Date(335077446));
userTransaction.beginTransaction();
em.persist(employee);
userTransaction.commit();
}
Trotzdem sollten Sie überlegen, die Datenbankaktionen in eine EJB zu migrieren, sie in Ihre JSF-Bean zu injizieren und somit die Verantwortung für die Verwaltung der Transaktionen, d. H. Die Verwendung von CMT, auf den Container zu delegieren, anstatt sie manuell zu verarbeiten.
Eine alternative Möglichkeit, dies zu handhaben, besteht darin, die Annotation @Transactional
für die Methode DataFetchBean
Ihrer addEmployee
zu verwenden. Dann brauchen Sie die UserTransaction
nicht und können die Transaktion mit AOP verwalten.
Dies war eine neue Funktion in JTA 1.2.
[.________.] Container-verwaltete Transaktionen JEE6
use Transaction Attributes
based on your application
füge @Transactional Annotation zu deiner Methode hinzu, um sie "transaktional" zu machen.