yo quería que persista un objeto (ReportBean
) a la base de datos, pero me dio el mensaje de error:¿Cómo implementar la transacción administrada por contenedor (CMT)?
javax.persistence.TransactionRequiredException: Transaction is required to perform this operation (either use a transaction or extended persistence context)
Aquí es un poco de un código:
entidad
@Entity
@Table(name="t_report")
@Access(AccessType.FIELD)
public class ReportBean implements Serializable {
// fields (@Column, etc.)
// setters/getters methods
// toString , hashCode, equals methods
}
anotación personalizada para permitir la inyección de EntityManager (con @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 {
}
proveedor de EntityManager
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;
}
clase ValidateReportAction - tiene un método para persistir informe a la base de datos.
Estoy tratando de seguir con las importaciones más importantes.
Si quiero usar el EntityManager
para crear una consulta (o NamedQuery como en el ejemplo) todo funciona.
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
: Aquí, en el método createReport()
cuando el em.persist ejecuta es donde aparece el error. Pensé que la transacción está gestionada por el contenedor (CMT
), pero ahora creo que estoy equivocado. ¿Dónde he cometido un error? ¿Cuál es la forma correcta de implementar CMT?
Aquí es también la configuración de mi persistence.xml
:
<?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>
Por favor, hágamelo saber si hay algo en mi pregunta no es clara.
Otra respuesta perfecta, gracias! – nyxz
@Arjan Tijms, ¿esta respuesta sigue siendo válida? – Ced
@Ced Bueno, "@Transactional" ahora está disponible como una anotación separada, por lo que el "no ha sucedido todavía" ahora ha sucedido;) –