Comment mettre en œuvre gérée par le conteneur de transaction (CMT)?
J'ai voulu persister un objet(ReportBean
) à la base de données, mais j'ai eu le message d'erreur:
javax.persistence.TransactionRequiredException: Transaction is required to perform this operation (either use a transaction or extended persistence context)
Voici un peu de code:
entité
@Entity
@Table(name="t_report")
@Access(AccessType.FIELD)
public class ReportBean implements Serializable {
//fields (@Column, etc.)
//setters/getters methods
//toString , hashCode, equals methods
}
annotations personnalisées pour permettre à l'EntityManager injection (avec @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 fournisseur de
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 classe - a une méthode pour persister rapport à la base de données.
Je suis en train de coller avec les importations les plus importantes.
Si je veux utiliser le EntityManager
pour créer une requête (ou NamedQuery comme dans l'exemple) tout fonctionne.
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
: Ici, dans la createReport()
méthode lorsque l'em.persistent s'exécute est où l'erreur apparaît. Je pensais que la transaction est gérée par le conteneur (CMT
), mais maintenant je pense que je me trompe. Où ai-je fait une erreur? Quelle est la bonne façon de mettre en œuvre CMT?
Ici est aussi mon persistence.xml
configuration:
<?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>
S'il vous plaît laissez-moi savoir si quelque chose dans ma question n'est pas claire.
OriginalL'auteur nyxz | 2012-01-07
Vous devez vous connecter pour publier un commentaire.
Vous semblez penser que
@TransactionManagement(TransactionManagementType.CONTAINER)
permet gérée par le conteneur des transactions et que@TransactionAttribute(TransactionAttributeType.REQUIRED)
permet ensuite d'une transaction sur une méthode, pour un non EJB bean.Ce n'est cependant pas (encore) possible en Java EE.
La
@TransactionManagement
annotation est utilisée uniquement pour passer un EJB bean qui fait déjà l'CMT à partir du conteneur dans BMT (Bean Managed Transactions). LeCONTAINER
constante est le plus complet, c'est ce que vous obtenez lorsque vous omettez l'annotation au total.De même, la
@TransactionAttribute
ne seront pas permettre à des transactions pour une méthode sur un non-EJB bean. L'annotation elle-même existe pour passer de la transaction dans un autre type (comme REQUIRES_NEW). Pour un EJB, il ne serait même pas nécessaire en général, puisque c'est aussi la valeur par défaut et il existe principalement pour des raisons d'exhaustivité, mais peut aussi être utilisé pour changer une méthode unique de retour à la NÉCESSITE, si les transactions sont modifiés au niveau de la classe.La bonne façon est d'utiliser un modèle de composant qui reçoit déjà CMT à partir du conteneur, comme un bean session sans état:
Puis à l'injecter ce bean (à l'aide de
@EJB
ou@Inject
) dans votre nommée haricots et de l'utiliser. Sinon, cet haricot peut être nommé aussi l'utilisation de@Named
de sorte qu'il peut être utilisé directement en EL, mais ce n'est pas toujours recommandé.La
@Stateless
bean ne permet pas de portée (en gros, c'est 'invocation d'étendue"), mais la@Stateful
modèle peut être de la session d'étendue que l'original de votre bean a été. Cependant, avec la fonctionnalité donnée, il n'a pas besoin d'être de la session d'étendue. Si vous ne l'as fait pour le gestionnaire de l'entité, alors souvenez-vous:Il existe des moyens pour mettre en place quelque chose qui ressemble un peu à de la CMT à l'aide de la CDI et de la JTA, mais si vous voulez un vrai CMT puis pour l'instant c'est le seul moyen. Il y a des plans pour briser la composante fixe des modèles comme stateless, stateful, singleton et par message en individuel (CDI) annotations (voir http://java.net/jira/browse/EJB_SPEC, et plus précisément à votre question Le découplage de la @TransactionAttribute annotation à partir du modèle de composant EJB), mais ce n'est pas encore arrivé.
Tijms , est que cette réponse est-elle encore valable ?
Eh bien, "@Transactionnelle" est maintenant disponible sous forme d'annotation, de sorte que le "n'est pas encore arrivé" est arrivé 😉
OriginalL'auteur Arjan Tijms
mise à jour de java EE 7 (CDI 1.1), vous pouvez maintenant utiliser @Transactionnelle pour permettre à la CMT en CDI haricots, pas besoin d'utiliser les EJB plus.
référence:JEE7: Ne EJB et CDI haricots soutien container-managed transactions?
OriginalL'auteur neptune
Vous avez raison, mais dans votre solution, vous créez un imbriquée
la transaction, qui s'exécute isolés à partir le contexte de l'appel.
Malheureusement, je n'ai pas été en mesure de trouver une solution pour passer
un transctions contexte comme celui-ci
OriginalL'auteur GroovieMan