Wie implementieren container-managed transaction (CMT)?
Wollte ich beibehalten eines Objekts(ReportBean
) in der Datenbank, aber ich bekam die Fehlermeldung:
javax.persistence.TransactionRequiredException: Transaction is required to perform this operation (either use a transaction or extended persistence context)
Hier ist ein wenig code:
Person
@Entity
@Table(name="t_report")
@Access(AccessType.FIELD)
public class ReportBean implements Serializable {
//fields (@Column, etc.)
//setters/getters methods
//toString , hashCode, equals methods
}
benutzerdefinierten annotation für die Ermöglichung der EntityManager Injektion (mit @Inject
)
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.*;
import java.lang.annotation.Target;
@Qualifier
@Target({TYPE, METHOD, FIELD, PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyEm {
}
EntityManager Anbieter
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
public class EntityManagerProvider {
private final String PERSISTENCE_UNIT = "MyPersistenceUnit";
@SuppressWarnings("unused")
@Produces
@MyEm
@PersistenceContext(unitName=PERSISTENCE_UNIT, type=PersistenceContextType.TRANSACTION)
private EntityManager em;
}
ValidateReportAction Klasse - eine Methode hat, um fortbestehen Bericht an die Datenbank.
Ich bin versucht zu halten mit den wichtigsten Einfuhren.
Wenn ich das EntityManager
um eine Abfrage zu erstellen (oder NamedQuery wie im Beispiel) funktioniert alles.
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.enterprise.context.SessionScoped;
@Named("validateReportAction")
@SessionScoped
@TransactionManagement(TransactionManagementType.CONTAINER)
public class ValidateReportAction extends ReportAction implements Serializable {
private static final long serialVersionUID = -2456544897212149335L;
@Inject @MyEm
private EntityManager em;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public synchronized String createReport() {
ReportBean report = new Report();
//set report properties
//em.createNamedQuery("queryName").getResultList(); ---- works
em.persist(report)
}
}
Q
: Hier in der createReport()
Methode bei der em.anhalten führt, wo der Fehler angezeigt. Ich dachte, dass die Transaktion verwaltet der container (CMT
), aber jetzt denke ich, ich bin falsch. Wo habe ich einen Fehler gemacht? Was ist der richtige Weg für die Implementierung von CMT?
Hier ist auch mein persistence.xml
Konfiguration:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="MyPersistenceUnit" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jboss/TimeReportDS</jta-data-source>
<mapping-file>META-INF/orm.xml</mapping-file>
<class>....</class>
<class>....</class>
<class>....</class>
<properties>
<property name="jboss.entity.manager.factory.jndi.name"
value="java:/modelEntityManagerFactory" />
<!-- PostgreSQL Configuration File -->
<property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
<property name="hibernate.connection.password" value="password" />
<property name="hibernate.connection.url" value="jdbc:postgresql://192.168.2.125:5432/t_report" />
<property name="hibernate.connection.username" value="username" />
<!-- Specifying DB Driver, providing hibernate cfg lookup
and providing transaction manager configuration -->
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
<property name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.JBossTransactionManagerLookup" />
<property name="hibernate.archive.autodetection" value="class" />
<!-- Useful configuration during development - developer can see structured SQL queries -->
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="false" />
</properties>
</persistence-unit>
</persistence>
Bitte lassen Sie mich wissen, wenn etwas in meine Frage ist nicht klar.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sie scheinen zu denken, dass
@TransactionManagement(TransactionManagementType.CONTAINER)
ermöglicht container-verwalteten Transaktionen und das@TransactionAttribute(TransactionAttributeType.REQUIRED)
ermöglicht dann eine Transaktion für eine Methode, für einen nicht EJB bean.Dies ist jedoch (noch) nicht möglich in Java EE.
Den
@TransactionManagement
annotation wird nur verwendet, um einen EJB-bean, schon bekommt CMT aus dem container in BMT (Bean Managed Transactions). DieCONTAINER
ständige ist mehr der Vollständigkeit halber, es ist, was Sie erhalten, wenn Sie weglassen die annotation zusammen.Ebenfalls, die
@TransactionAttribute
wird nicht aktivieren Sie Transaktionen für eine Methode auf einem nicht-EJB bean. Die annotation selbst ist das wechseln der Transaktion in einen anderen Typ (wie REQUIRES_NEW). Für eine EJB-wäre es nicht auch normalerweise erforderlich ist, da auch dies die Standardeinstellung ist und es auch hauptsächlich besteht für die Vollständigkeit, kann aber auch verwendet werden zum schalten einer einzigen Methode wieder zurück BENÖTIGT, wenn Transaktionen geändert werden auf Klassen-Niveau.Der richtige Weg ist, um ein Komponenten-Modell, das schon bekommt CMT aus dem container, wie Sie eine zustandslose session-bean:
Dann injizieren diese bean (mit
@EJB
oder@Inject
) in dem benannten Bohnen und verwenden Sie es. Alternativ kann dieser bean namens zu verwenden@Named
so kann es direkt in der EL, aber das ist nicht immer zu empfehlen.Den
@Stateless
bean nicht erlauben, scoping (es ist im Grunde 'Aufruf-Ebene"), aber die@Stateful
Modell session-scoped wie die original bean war. Jedoch, mit den gegebenen Funktionen die nicht benötigt werden-session-scoped. Wenn Sie nur, dass dies für den entity-manager, dann denken Sie daran:Gibt es Möglichkeiten, etwas umzusetzen, die sieht ein bisschen aus wie CMT mit CDI und JTA, aber wenn Sie wollen true CMT dann für den moment ist dies die einzige Möglichkeit. Es gibt Pläne, brechen die Feste Komponente-Modelle wie stateless, stateful, singleton-und message-driven in einzelne (CDI) Anmerkungen (siehe http://java.net/jira/browse/EJB_SPEC, und speziell für Ihre Frage Die Entkopplung der @TransactionAttribute annotation aus dem EJB-Komponentenmodell), aber das ist noch nicht passiert.
update für java EE 7 (CDI 1.1), können Sie jetzt mit @Transactional zu ermöglichen, der CMT in CDI-beans, keine Notwendigkeit zu verwenden EJB mehr.
Referenz:JEE7: Tun, EJB-und CDI-beans-Unterstützung von container-managed Transaktionen?
Hast du Recht, aber in der Projektmappe erstellen Sie eine verschachtelte
die Transaktion, die ausgeführt wird insolated, die vom aufrufenden Kontext.
Leider war ich nicht in der Lage, eine Lösung zu finden, pass
ein transctions Kontext