简体   繁体   中英

Spring-boot: cannot use persistence

I am days into this, and - although I am learning a lot - starting to despair.

I have tried all the suggestions on this excellent question:

No Persistence provider for EntityManager named

I had this working at one point using the ubiquitous HibernateUtil class, but was told to move to a plain JPA style here:

Spring RESTful controller method improvement suggestions

Unfortunately, I could not get the bean injection to work properly in spring-boot. Here is my attempt:

Spring JPA (Hibernate) No qualifying bean of type: javax.persistence.EntityManagerFactory

After much work down that path I ended up with a null entity manager. I found this and began to think it could not work:

Using JPA2 in Tomcat 6: @PersitenceContext doesn't work, EntityManager is null

It seems to me like the EntityManagerFactory absolutely should be a bean in whatever context spring-boot creates, but ... whatever. I would think that at least this would work:

Application launch:

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Controller:

@Controller
public class GetController {

    private static final String PERSISTENCE_UNIT_NAME = "cpJpaPu";  

    @RequestMapping(value = "/user", method = RequestMethod.GET)
    public @ResponseBody User getUser(@RequestParam(value="id", required=true) int id) {
        User user = null;

        EntityManagerFactory emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        EntityManager em = emf.createEntityManager();
        UserDAO userDao = new UserDAO();
        userDao.setEntityManager(em);
        user = userDao.load(id);

        return user;
    }
}

DAO:

public class UserDAO {

    public EntityManager entityManager;

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }   

    public void insert(User user) {
        entityManager.persist(user);
    }

    public User load(int id) {
        return entityManager.find(User.class, id);
    }
}

/src/main/resources/persistence.xml:

<persistence 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_1_0.xsd" version="1.0">
  <persistence-unit name="cpJpaPu" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>com.mydomain.User</class>
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
      <property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
      <property name="hibernate.show_sql" value="false"/>
      <property name="hibernate.connection.username" value="user"/>
      <property name="hibernate.connection.password" value=""/>
      <property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/mydb"/>
    </properties>
  </persistence-unit>
</persistence>

And it doesn't work:

javax.persistence.PersistenceException: No Persistence provider for EntityManager named cpJpaPu
    javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:61)
    javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:39)
    com.mydomain.GetController.getUser(GetController.java:25)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    java.lang.reflect.Method.invoke(Unknown Source)
    org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:214)
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:748)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:947)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:878)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:946)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:837)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:822)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)

--- Added Info ---

POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mygroup</groupId>
    <artifactId>myartifact</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>0.5.0.M6</version>
    </parent>

    <dependencies>
        <!--  Spring framework -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--  Hibernate -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.3.0.Final</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <!-- Must override version or face stack traces -->
            <version>4.3.0.Final</version>
        </dependency>

        <!-- Spring ORM, works with Hibernate -->   
        <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-orm</artifactId>
        </dependency>

        <!--  Spring implementation of Jackson for RESTful JSON -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>         
        </dependency>

        <!--  JDBC -->
        <dependency>
            <groupId>postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.1-901.jdbc4</version>
        </dependency>

        <!-- Logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>

        <!-- Prevent logging conflicts -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
            <scope>compile</scope>
            <exclusions>                
                <exclusion>
                    <groupId>ch.qos.logback</groupId>
                    <artifactId>logback-classic</artifactId>
                </exclusion>
            </exclusions> 
        </dependency>
    </dependencies>

    <properties>
        <start-class>com.cloudfordev.controlpanel.Application</start-class>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <plugins>   
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>          
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <url>http://repo.spring.io/libs-snapshot</url>
            <snapshots><enabled>true</enabled></snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-snapshots</id>
            <url>http://repo.spring.io/libs-snapshot</url>
            <snapshots><enabled>true</enabled></snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>

spring boot does not read persistence.xml file by default, see the document here

https://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html

so if you want to keep using persistence.xml file just add below code into your AppConfig class

@Bean
public LocalEntityManagerFactoryBean entityManagerFactory(){
     LocalEntityManagerFactoryBean factoryBean = new LocalEntityManagerFactoryBean();
    factoryBean.setPersistenceUnitName("cpJpaPu");
    return factoryBean;
}

persistence.xml应位于META-INF目录中

/src/main/resources/META-INF/persistence.xml

There are some features of JPA that only work in XML configuration unfortunately, but I can't see anything like that in yours. I don't think persistence.xml is loaded by default, so probably that's the issue. So why don't you go with the flow and use Java and application.properties to configure the entity manager? The JPA sample from Spring Boot has everything you need to get started. It uses Spring Data JPA, whereas your code is only using the JPA APIs, but you can easily strip back to that level by just removing the Spring Data dependencies in the sample.

Recent Spring Boot snapshots have a feature that lets you create your own LocalEntityManagerFactoryBean so that you can add a custom XML configuration, but up to M7 you would have to do all the JPA configuration manually once you needed a custom EntityManager .

NB you aren't really using dependency injection very effectively in your controller - why wouldn't you just inject the UserDao ?

This question was answered with a much better architecture over here:

Spring JPA (Hibernate) No qualifying bean of type: javax.persistence.EntityManagerFactory

I resolved this issue after deleted all hibernate-core folders under below directory: .m2\\repository\\org\\hibernate\\hibernate-core

and rebuilt my projects.

Now, it works fine under Spring Boot 2.0.4.RELEASE. And I'm sure that it loads the main/resources/META-INF/persistence.xml without injecting LocalEntityManagerFactoryBean Bean.

Before I delete them, there are 4 versions of hibernate-core in the above folder. They are "4.3.6"/"5.0.12"/"5.2.17"/"5.3.4".

After I deleted them, there are "5.0.12"/"5.2.17"/"5.3.4" after rebuilt my projects.

And when I dig into this issue, I found that the "hibernate-core-5.2.17.Final.jar" in previous "5.2.17" folder is bigger than the normal and it has no "hibernate-core-5.2.17.Final.jar.sha1".

So, it may caused by poor network or poor mirror.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM