SpringBoot Rest API 中的 EntityManager 和 SessionHolder 错误

Posted

技术标签:

【中文标题】SpringBoot Rest API 中的 EntityManager 和 SessionHolder 错误【英文标题】:EntityManager and SessionHolder error in SpringBoot Rest API 【发布时间】:2019-07-28 00:07:31 【问题描述】:

以上查询是关于我正在从事的项目:

项目:

我有一个使用 SpringBoot 和 hibernate 的简单的基于 REST 的 API 项目,我需要使用 GET 和 POST 请求构建注册和登录机制。 每当我尝试发出 POST 请求以创建资源(在这种情况下创建一个新用户)时,我在 POSTMAN 和 Eclipse IDE 上都会收到以下错误:

我使用 POSTMAN 发出的 POST 请求


    "userId": "12345",
    "pin": "1234"
 

发出 POST 请求时 POSTMAN 出错

    
    "timestamp": 1551809931747,
    "status": 500,
    "error": "Internal Server Error",
    "exception": "java.lang.ClassCastException",
    "message": "org.springframework.orm.jpa.EntityManagerHolder cannot be cast to org.springframework.orm.hibernate4.SessionHolder",
    "path": "/employee/register"
 

错误的完整堆栈跟踪

java.lang.ClassCastException: org.springframework.orm.jpa.EntityManagerHolder cannot be cast to org.springframework.orm.hibernate4.SessionHolder
    at org.springframework.orm.hibernate4.HibernateTransactionManager.doGetTransaction(HibernateTransactionManager.java:380) ~[spring-orm-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:341) ~[spring-tx-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:461) ~[spring-tx-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:277) ~[spring-tx-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:671) ~[spring-aop-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at com.cerner.project.dao.EmployeeDAO$$EnhancerBySpringCGLIB$$1b4cb760.registerUser(<generated>) ~[classes/:na]
    at com.cerner.project.controller.EmployeeController.registerUser(EmployeeController.java:28) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_201]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_201]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_201]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:849) ~[spring-webmvc-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:760) ~[spring-webmvc-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) ~[spring-webmvc-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55) ~[spring-boot-1.5.19.RELEASE.jar:1.5.19.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:111) ~[spring-boot-actuator-1.5.19.RELEASE.jar:1.5.19.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:103) ~[spring-boot-actuator-1.5.19.RELEASE.jar:1.5.19.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493) [tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800) [tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806) [tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498) [tomcat-embed-core-8.5.37.jar:8.5.37]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.37.jar:8.5.37]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_201]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_201]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.37.jar:8.5.37]
    at java.lang.Thread.run(Unknown Source) [na:1.8.0_201]

可能是什么问题导致了这个错误?我想做的只是一个简单的 POST。

以下是我的文件: User.Java

    package com.cerner.project.model;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name="user")
public class User 

    @Id
    @Column(name="user_id")
    private int userId;

    @Column(name="pin")
    //@ColumnTransformer(read = "sha1(pin)",write = "sha1(?)")
    private String pin;

    @OneToMany(cascade=CascadeType.ALL)
    @JoinColumn(name="user_id")
    private List<UserLog> userLog=new ArrayList<UserLog>();

    public List<UserLog> getUserLog() 
        return userLog;
    

    public void setUserLog(List<UserLog> userLog) 
        this.userLog = userLog;
    

    public int getUserId() 
        return userId;
    

    public void setUserId(int userId) 
        this.userId = userId;
    

    public String getPin() 
        return pin;
    

    public void setPin(String pin) 
        this.pin = pin;
    

    public User() 

    
    public User(int userId, String pin) 
        this.userId = userId;
        this.pin= pin;
    
    //CLOVER:OFF
    @Override
    public String toString() 
        return "User [userId=" + userId + ", pin=" + pin + "]";
    
    //CLOVER:ON

EmployeeDao.Java

        package com.cerner.project.dao;

    import java.util.ArrayList;
    import java.util.List;

    import javax.transaction.Transactional;

    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Repository;
    import org.springframework.stereotype.Service;

    import com.cerner.project.model.Team;
    import com.cerner.project.model.User;
    import com.cerner.project.model.UserLog;

    //@Service
    @Repository
    @Transactional
    public class EmployeeDAO 

        @Autowired
        private SessionFactory sessionFactory;

        private Session getSession() 
            return sessionFactory.getCurrentSession();
        

        public User registerUser(User user) 
            int userId=user.getUserId();
            user.setUserId(userId);
            String userPin=user.getPin();
            user.setPin(userPin);
            return user;
        

        public List<User> getAllUsers() 
            List<User> users=new ArrayList<User>();
              User user1=new User(11111,"1234");
            User user2=new User(22222,"4321");
            users.add(user1);
            users.add(user2);
            getSession().beginTransaction();
            getSession().save(user1);
            getSession().save(user1);
            getSession().getTransaction().commit();
            return users;
        
    

EmployeeController.Java

    package com.cerner.project.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.cerner.project.dao.EmployeeDAO;
import com.cerner.project.model.User;

@RestController
@RequestMapping("/employee")
public class EmployeeController 

    @Autowired
    private EmployeeDAO employeeDao;

    @RequestMapping("/test")
    public String test() 
        return "Hello World!";
    
    @PostMapping("/register")
    public String registerUser(@RequestBody User user) 
        employeeDao.registerUser(user);
        return("SUCCESS");
    


    @GetMapping("/getUsers")
    public List<User> getAllUsers()
        return employeeDao.getAllUsers();

    


DBConfiguration.Java

    package com.cerner.project.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@PropertySource(value =  "classpath:application.properties" )
@Configuration
//@EnableTransactionManagement
public class DBConfiguration 

    @Value("$jdbc.driverClassName")
    private String driverClass;
    @Value("$jdbc.url")
    private String url;
    @Value("$jdbc.username")
    private String username;
    @Value("$jdbc.password")
    private String password;
    @Value("$hibernate.dialect")
    private String dialect;

    @Bean
    public DataSource getDataSource() 
        DriverManagerDataSource dataSource = new DriverManagerDataSource(url, username, password);
        dataSource.setDriverClassName(driverClass);
        return dataSource;
    

    @Bean
    public LocalSessionFactoryBean sessionFactory() 
        LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
        factory.setDataSource(getDataSource());
        factory.setHibernateProperties(hibernateProperties());
        factory.setPackagesToScan(new String[]  "com.cerner.project" );
        return factory;
    

    private Properties hibernateProperties() 
        Properties properties = new Properties();
        properties.put("hibernate.dialect", dialect);
        properties.put("hibernate.hbm2ddl.auto", "update");
        properties.put("hibernate.show_sql", "true");
        properties.put("hibernate.format_sql", "true");
        return properties;
    

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory factory) 
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(factory);
        return transactionManager;
    
 

【问题讨论】:

EntityManagerHolder.classSessionHolder.class 可能会有所帮助,因为这两个在异常中被引用。 但是我在哪里使用它们?你能提供一个解决方案吗? 删除你的配置并简单地重写你的 DAO 以使用EntityManager 【参考方案1】:

@SpringBootApplication 更改为

@SpringBootApplication(exclude=HibernateJpaAutoConfiguration.class)

随着 Hibernate 5.2 的发布,SessionFactory 扩展了 EntityManagerFactory 接口。这导致 SessionFactory 也成为 EntityManagerFactory。

在以前的休眠版本中,情况并非如此。

简单的解决方案是将休眠版本降级为


你可以参考12这些了解更多详情


编辑:

当你写exclude=HibernateJpaAutoConfiguration.class作为结果

@SpringBootApplication

不会考虑进一步执行该特定类。正如您在图片中看到的HibernateJpaAutoConfiguration 已经实现了一些您不需要配置任何东西或使其易于使用的类(可能实现其他类),例如LocalContainerEntityManagerFactoryBean.class。由于您已经排除了课程,因此您必须手动执行 HibernateJpaAutoConfiguration.class 为您完成的事情。

【讨论】:

非常感谢@Romil。我已经做到了。但我不知道为什么。除了这个改变,我还必须做出一些特定的改变,比如从 DBConfiguration.Java 文件中删除 HibernateTransactionManager 代码,并添加一个 Bean 来创建像这样的 EntityManager -- public LocalContainerEntityManagerFactoryBean entityManagerFactory() 。我不知道为什么我必须做出这些改变。你能帮我解决这个问题吗?

以上是关于SpringBoot Rest API 中的 EntityManager 和 SessionHolder 错误的主要内容,如果未能解决你的问题,请参考以下文章

spring boot 2.2中默认的rest api超时是啥

Spring REST API 中的 Json 模式验证

SpringBoot 项目配置 Swagger 接口api 搭建 REST

如何使用 ReactiveUserDetailsS​​ervice springboot 通过 Rest API 登录

使用 SpringBoot 配置文件模拟 REST API 调用

通过 SpringBoot 调用 REST api 时 POST 不支持异常