【问题标题】:Spring JPA and persistence.xmlSpring JPA 和 persistence.xml
【发布时间】:2026-01-18 17:35:01
【问题描述】:

我正在尝试设置一个 Spring JPA Hibernate 简单示例 WAR 以部署到 Glassfish。 我看到一些示例使用 persistence.xml 文件,而其他示例则没有。 有些示例使用数据源,有些则不使用。到目前为止,我的理解是,如果我有,则不需要数据源:

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

我可以正常部署,但我的 EntityManager 没有被 Spring 注入。

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

我的 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";
}

我的 web.xml:

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

在让 Spring 将“em”注入 StudentService 时,我有什么遗漏的吗?

【问题讨论】:

    标签: java spring jpa


    【解决方案1】:

    只是为了确认一下,虽然你可能做过......

    你有没有加入

    <!--  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" />
    

    应用程序 context.xml 中的位?

    另外,我不太确定您是否能够在这种设置中使用 jta 事务类型?那不需要数据源管理的连接池吗?所以试试 RESOURCE_LOCAL。

    【讨论】:

      【解决方案2】:

      我很困惑。您将 PU 注入服务层而不是持久层?我不明白。

      我将持久层注入到服务层中。服务层包含业务逻辑并划定事务边界。它可以在一个事务中包含多个 DAO。

      我也没有在你的 save() 方法中得到魔法。数据如何保存?

      在生产中我这样配置spring:

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

      连同 web.xml 中的引用

      对于单元测试,我这样做:

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

      【讨论】:

        【解决方案3】:

        如果有人想使用 Java 配置而不是 xml 的 hibernate 配置,使用这个:

        你可以像这样在 Spring 中完全不使用 persistence.xml 来配置 Hibernate:

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

        由于你没有使用persistence.xml,你应该创建一个bean,它返回你在上面设置数据源的方法中指定的DataSource:

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

        然后你在这个配置文件上使用@EnableTransactionManagement注解。现在,当您添加该注释时,您必须创建最后一个 bean:

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

        现在,不要忘记在那些处理 DB 的方法上使用 @Transactional 注释。

        最后,不要忘记在你的存储库中注入EntityManager(这个存储库类应该有@Repository注解)。

        【讨论】:

          【解决方案4】:

          我有一个使用 JPA/Hibernate 和 Spring 设置的测试应用程序,我的配置反映了你的配置,但我创建了一个数据源并将其注入 EntityManagerFactory,并将数据源特定属性移出 persistenceUnit 并移入数据源。有了这两个小改动,我的 EM 就可以正确注入了。

          【讨论】:

            【解决方案5】:

            这可能很旧,但如果有人遇到同样的问题,请尝试在 PersistenceContext 注释中将 unitname 更改为仅名称:

            来自

            @PersistenceContext(unitName="educationPU")
            

            @PersistenceContext(name="educationPU")
            

            【讨论】:

            • 嗯? @PersistenceContext 的可选name 属性用于查找注入的实体管理器。 它在persistence.xml中没有对应的元素。如果这对您有用,这只是 IMO 与缺少 unitName 相关的幸运副作用(这种情况下的行为是特定于供应商的)。但这是不正确的。
            最近更新 更多