If you are running a web application, Spring Boot will by default register OpenEntityManagerInViewInterceptor to apply the “Open EntityManager in View” pattern, i.e. to allow for lazy loading in web views. If you don’t want this behavior you should set spring.jpa.open-in-view to false in your application.properties.
@RequestMapping("/testNormalGetOne") @ResponseBody public String testNormalGetOne(){ // new Thread(new Runnable() { // @Override // public void run() { studentService.testNormalGetOne(); // } // }).start(); return"testNormalGetOne"; }
报错如下:
1
{"timestamp":1498194914012,"status":500,"error":"Internal Server Error","exception":"org.hibernate.LazyInitializationException","message":"could not initialize proxy - no Session","path":"/testNormalGetOne"}
是的,我们使用 spring 的 controller 作为单元测试时,以及我们平时在直接使用 jpa 的懒加载属性时没有太关注这个 jpa 的特性,因为 springboot 帮我们默认开启了这个过滤器。这也解释了,为什么在新的线程中,定时任务线程中,rpc 远程调用时 session 没有打开的原因,因为这些流程没有经过 springboot 的 web 调用链。
/** * Set the bean name of the EntityManagerFactory to fetch from Spring's * root application context. * <p>Default is "entityManagerFactory". Note that this default only applies * when no "persistenceUnitName" param has been specified. * * @see #setPersistenceUnitName * @see #DEFAULT_ENTITY_MANAGER_FACTORY_BEAN_NAME */ publicvoidsetEntityManagerFactoryBeanName(String entityManagerFactoryBeanName){ this.entityManagerFactoryBeanName = entityManagerFactoryBeanName; }
/** * Return the bean name of the EntityManagerFactory to fetch from Spring's * root application context. */ protected String getEntityManagerFactoryBeanName(){ returnthis.entityManagerFactoryBeanName; }
/** * Set the name of the persistence unit to access the EntityManagerFactory for. * <p>This is an alternative to specifying the EntityManagerFactory by bean name, * resolving it by its persistence unit name instead. If no bean name and no persistence * unit name have been specified, we'll check whether a bean exists for the default * bean name "entityManagerFactory"; if not, a default EntityManagerFactory will * be retrieved through finding a single unique bean of type EntityManagerFactory. * * @see #setEntityManagerFactoryBeanName * @see #DEFAULT_ENTITY_MANAGER_FACTORY_BEAN_NAME */ publicvoidsetPersistenceUnitName(String persistenceUnitName){ this.persistenceUnitName = persistenceUnitName; }
/** * Return the name of the persistence unit to access the EntityManagerFactory for, if any. */ protected String getPersistenceUnitName(){ returnthis.persistenceUnitName; }
/** * Look up the EntityManagerFactory that this filter should use. * <p>The default implementation looks for a bean with the specified name * in Spring's root application context. * * @return the EntityManagerFactory to use * @see #getEntityManagerFactoryBeanName */ protected EntityManagerFactory lookupEntityManagerFactory(){
String emfBeanName = getEntityManagerFactoryBeanName(); String puName = getPersistenceUnitName(); if (StringUtils.hasLength(emfBeanName)) { return ApplicationContextProvider.getApplicationContext().getBean(emfBeanName, EntityManagerFactory.class); } elseif (!StringUtils.hasLength(puName) && ApplicationContextProvider.getApplicationContext().containsBean(DEFAULT_ENTITY_MANAGER_FACTORY_BEAN_NAME)) { return ApplicationContextProvider.getApplicationContext().getBean(DEFAULT_ENTITY_MANAGER_FACTORY_BEAN_NAME, EntityManagerFactory.class); } else { // Includes fallback search for single EntityManagerFactory bean by type. return EntityManagerFactoryUtils.findEntityManagerFactory(ApplicationContextProvider.getApplicationContext(), puName); } }
/** * Create a JPA EntityManager to be bound to a request. * <p>Can be overridden in subclasses. * * @param emf the EntityManagerFactory to use * @see javax.persistence.EntityManagerFactory#createEntityManager() */ protected EntityManager createEntityManager(EntityManagerFactory emf){ return emf.createEntityManager(); }
@Override public Response filter(Caller<?> caller, Request request){ if (!(caller instanceof Provider)) { return caller.call(request); }