java - example - Spring JPA y persistence.xml
spring jpa repository (5)
Estoy confundido. ¿Está inyectando una PU en la capa de servicio y no en la capa de persistencia? No entiendo eso.
Inyerto la capa de persistencia en la capa de servicio. La capa de servicio contiene lógica de negocios y delimita los límites de las transacciones. Puede incluir más de un DAO en una transacción.
No consigo la magia en su método save () tampoco. ¿Cómo se guardan los datos?
En producción, configuro un resorte como este:
<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/ThePUname" />
junto con la referencia en web.xml
Para las pruebas unitarias, hago esto:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource" p:persistence-xml-location="classpath*:META-INF/test-persistence.xml"
p:persistence-unit-name="RealPUName" p:jpaDialect-ref="jpaDialect"
p:jpaVendorAdapter-ref="jpaVendorAdapter" p:loadTimeWeaver-ref="weaver">
</bean>
Estoy tratando de configurar un Spring WAR Hibernate ejemplo simple WAR para su implementación en Glassfish. Veo que algunos ejemplos usan un archivo persistence.xml y otros no. Algunos ejemplos usan un dataSource y otros no. Hasta ahora entiendo que un dataSource no es necesario si tengo:
<persistence-unit name="educationPU"
transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.coe.jpa.StudentProfile</class>
<properties>
<property name="hibernate.connection.driver_class"
value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url"
value="jdbc:mysql://localhost:3306/COE" />
<property name="hibernate.connection.username" value="root" />
<property name="show_sql" value="true" />
<property name="dialect" value="org.hibernate.dialect.MySQLDialect" />
</properties>
</persistence-unit>
Puedo implementar bien, pero mi EntityManager no está siendo inyectado por Spring.
Mi applicationContext.xml:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="educationPU" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="StudentProfileDAO" class="com.coe.jpa.StudentProfileDAO">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="studentService" class="com.coe.services.StudentService">
</bean>
Mi clase con EntityManager:
public class StudentService {
private String saveMessage;
private String showModal;
private String modalHeader;
private StudentProfile studentProfile;
private String lastName;
private String firstName;
@PersistenceContext(unitName="educationPU")
private EntityManager em;
@Transactional
public String save()
{
System.out.println("*** em: " + this.em); //em is null
this.studentProfile= new StudentProfile();
this.saveMessage = "saved";
this.showModal = "true";
this.modalHeader= "Information Saved";
return "successs";
}
Mi web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
¿Hay alguna pieza que me falta para que Spring inyecte "em" en StudentService?
Puede que sea antiguo, pero si alguien tiene el mismo problema, intente cambiar el nombre de la unidad por el nombre en la anotación de PersistenceContext:
De
@PersistenceContext(unitName="educationPU")
a
@PersistenceContext(name="educationPU")
Si alguien quiere usar la configuración puramente Java en lugar de la configuración xml
de hibernación, use esto:
Puedes configurar Hibernate sin usar persistence.xml en Spring como este:
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean()
{
Map<String, Object> properties = new Hashtable<>();
properties.put("javax.persistence.schema-generation.database.action",
"none");
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect"); //you can change this if you have a different DB
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(adapter);
factory.setDataSource(this.springJpaDataSource());
factory.setPackagesToScan("package name");
factory.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
factory.setValidationMode(ValidationMode.NONE);
factory.setJpaPropertyMap(properties);
return factory;
}
Como no está utilizando persistence.xml, debe crear un bean que devuelva DataSource que especifique en el método anterior que establece el origen de datos:
@Bean
public DataSource springJpaDataSource()
{
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl("jdbc:mysql://localhost/SpringJpa");
dataSource.setUsername("tomcatUser");
dataSource.setPassword("password1234");
return dataSource;
}
Luego usa la anotación @EnableTransactionManagement
sobre este archivo de configuración. Ahora cuando pones esa anotación, tienes que crear un último bean:
@Bean
public PlatformTransactionManager jpaTransactionManager()
{
return new JpaTransactionManager(
this.entityManagerFactoryBean().getObject());
}
Ahora, no te olvides de usar @Transactional
Annotation sobre los métodos que tratan con DB.
Por último, no olvides EntityManager
en tu repositorio (esta clase de repositorio debe tener @Repository
anotación @Repository
sobre él).
Solo para confirmar que probablemente lo hiciste ...
¿Incluiste el
<!-- tell spring to use annotation based congfigurations -->
<context:annotation-config />
<!-- tell spring where to find the beans -->
<context:component-scan base-package="zz.yy.abcd" />
bits en su aplicación context.xml?
Además, no estoy tan seguro de que puedas usar un tipo de transacción jta con este tipo de configuración. ¿No requeriría eso un grupo de conexiones administradas de fuente de datos? Por lo tanto, intente con RESOURCE_LOCAL en su lugar.
Tengo una aplicación de prueba configurada con JPA / Hibernate y Spring, y mi configuración es similar a la tuya, con la excepción de que creo un origen de datos e inyectándolo en EntityManagerFactory, y moví las propiedades específicas de la fuente de datos de la persistenceUnit a la fuente de datos. Con estos dos pequeños cambios, mi EM se inyecta correctamente.