web-dev-qa-db-fra.com

Spring JPA et persistence.xml

J'essaie de mettre en place un exemple de WAR simple Spring HPA Hibernate pour le déploiement sur Glassfish. Je vois que certains exemples utilisent un fichier persistence.xml, et d'autres exemples ne le font pas. Certains exemples utilisent un dataSource et d'autres non. Jusqu'à présent, ma compréhension est qu'un dataSource n'est pas nécessaire si j'ai:

<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>

Je peux déployer correctement, mais mon EntityManager n'est pas injecté par Spring.

Mon 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>

Ma classe avec 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";
}

Mon web.xml:

  <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

Y a-t-il des éléments qui me manquent pour que Spring injecte "em" dans StudentService?

23
bmw0128

Juste pour confirmer que vous l'avez probablement fait ...

Avez-vous inclus le

<!--  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 dans votre application context.xml?

De plus, je ne suis pas sûr que vous puissiez utiliser un type de transaction jta avec ce type de configuration? Cela ne nécessiterait-il pas un pool de connexions gérées par source de données? Essayez plutôt RESOURCE_LOCAL à la place.

13
Michael Wiles

Je suis confus. Vous injectez un PU dans la couche service et non la couche persistance? Je ne comprends pas.

J'injecte la couche de persistance dans la couche de service. La couche de service contient la logique métier et délimite les limites des transactions. Il peut inclure plusieurs DAO dans une transaction.

Je n'ai pas non plus la magie de votre méthode save (). Comment les données sont-elles enregistrées?

En production, je configure le printemps comme ceci:

<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/ThePUname" />

avec la référence dans web.xml

Pour les tests unitaires, je fais ceci:

<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>
4
Gene

Si quelqu'un veut utiliser purement Java au lieu de la configuration xml de la mise en veille prolongée, utilisez ceci:

Vous pouvez configurer Hibernate sans utiliser persistence.xml dans Spring comme ceci:

@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;
}

Puisque vous n'utilisez pas persistence.xml, vous devez créer un bean qui renvoie DataSource que vous spécifiez dans la méthode ci-dessus qui définit la source de données:

@Bean
public DataSource springJpaDataSource()
{
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl("jdbc:mysql://localhost/SpringJpa");
dataSource.setUsername("tomcatUser");
dataSource.setPassword("password1234");
return dataSource;
}

Ensuite, vous utilisez @EnableTransactionManagement annotation sur ce fichier de configuration. Maintenant, lorsque vous mettez cette annotation, vous devez créer un dernier bean:

@Bean
public PlatformTransactionManager jpaTransactionManager()
{
return new JpaTransactionManager(
this.entityManagerFactoryBean().getObject());
}

Maintenant, n'oubliez pas d'utiliser @Transactional Annotation sur les méthodes qui traitent de DB.

Enfin, n'oubliez pas d'injecter EntityManager dans votre référentiel (cette classe de référentiel devrait avoir @Repository annotation dessus).

1
Faraz Durrani

J'ai une application de test configurée à l'aide de JPA/Hibernate & Spring, et ma configuration reflète la vôtre à l'exception que je crée une source de données et l'injecte dans EntityManagerFactory, et que j'ai déplacé les propriétés spécifiques de la source de données hors de l'unité persistence et dans la source de données. Avec ces deux petits changements, mon EM est injecté correctement.

0
Rich Kroll

Cela peut être ancien, mais si quelqu'un a le même problème, essayez de changer le nom d'unité pour simplement nommer dans l'annotation PersistenceContext:

De

@PersistenceContext(unitName="educationPU")

à

@PersistenceContext(name="educationPU")
0
billy vandory