java - 使用延迟获取类型检索外部对象的正确方法

标签 java mysql spring hibernate lazy-loading

我正在使用 Spring、Hibernate 和 MySql,我将 fetchType 设置为 LAZY 以提高我的软件的性能,因为使用 EAGER 时速度非常慢。 现在我需要检索链接到我的类的外部对象的信息,例如我有 Car 类:

/**
 * Car generated by hbm2java
 */
@Entity
@Table(name = "car", catalog = "ats")
public class Car implements java.io.Serializable {

/**
 * 
 */
private static final long serialVersionUID = 1L;
private Integer idCar;
private CarType carType;
private Fleet fleet;
private String id;
private int initialKm;
private String carChassis;
private String note;
@JsonIgnore
private Set<Acquisition> acquisitions = new HashSet<Acquisition>(0);

我需要 carType id。所以如果我使用

public List<Car> findByFleetIdFleet(int idFleet);

我检索到一个异常,因为我将结果放在另一个我的类 TableUi 中(用于允许从表进行 ajax 调用):

public class TableUI {

   private Object data;

/**
 * @return the data
 */
public Object getData() {
    return data;
}

/**
 * @param data the data to set
 */
public void setData(Object data) {
    this.data = data;
}

}

我的 Controller 返回 @ResponseBody TableUI。显然 jackson 无法映射对象,因为它的字段 fleet 和 carType 只是代理。 这是异常(exception)情况:

    ERROR com.controller.ErrorController - org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.model.tablesField.TableUI["data"]->java.util.ArrayList[0]->com.domain.Car["carType"]->com.domain.CarType_$$_jvst4de_f["handler"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.model.tablesField.TableUI["data"]->java.util.ArrayList[0]->com.domain.Car["carType"]->com.domain.CarType_$$_jvst4de_f["handler"])
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:271)
    at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:100)
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:167)
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:100)
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:166)
    at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:80)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:127)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:729)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1526)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1482)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.model.tablesField.TableUI["data"]->java.util.ArrayList[0]->com.domain.Car["carType"]->com.domain.CarType_$$_jvst4de_f["handler"])
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:59)
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:26)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:505)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:639)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:505)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:639)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:100)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:21)
    at com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:183)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:505)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:639)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:128)
    at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:602)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:264)
    ... 37 more

.11:24:38.387 [http-nio-8086-exec-4] WARN  o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Handler execution resulted in exception: Could not write content: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.model.tablesField.TableUI["data"]->java.util.ArrayList[0]->com.domain.Car["carType"]->com.domain.CarType_$$_jvst4de_f["handler"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.model.tablesField.TableUI["data"]->java.util.ArrayList[0]->com.domain.Car["carType"]->com.domain.CarType_$$_jvst4de_f["handler"]) 

相反,如果我在 model.addAttribute 中使用 findByFleetIdFleet 它会起作用 因此,我需要另一种方法,它返回带有 Car 对象的 carType,仅当我需要更多信息时才使用该方法(如果我需要所有对象,JOIN FETCH 只处理一个对象?)。 我发现的唯一工作方式是:

 @SuppressWarnings("unchecked")
        @Override
        public List<CarWithCarType> findByFleetIdFleetFetch(int idFleet) {
            String jpql = "select f from Fleet f where f.idFleet = :idFleet";
            Query query = entityManager.createQuery(jpql);
            query.setParameter("idFleet", idFleet);
            Fleet fleet=(Fleet) query.getSingleResult();
            String jpql2 = "select c from Car c JOIN FETCH c.carType where c.fleet = :fleet";
            Query query2 = entityManager.createQuery(jpql2);
            query2.setParameter("fleet", fleet);
            List<Car> cars= query2.getResultList();
            List<CarWithCarType> carsList = new ArrayList<CarWithCarType>();
            for (Car car: cars){
                CarWithCarType newCar = new CarWithCarType();
                newCar.setId(car.getId());
                newCar.setCarChassis(car.getCarChassis());
                newCar.setCarType(car.getCarType());
                newCar.setIdCar(car.getIdCar());
                newCar.setInitialKm(car.getInitialKm());
                newCar.setNote(car.getNote());
                carsList.add(newCar);
            }
            return carsList;
        }

这是最好的方法还是有其他更好的方法?谢谢

更新: 这是添加到我的配置类中的 jackson hibernate 映射配置:

   public MappingJackson2HttpMessageConverter jacksonMessageConverter(){
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();

        ObjectMapper mapper = new ObjectMapper();
        //Registering Hibernate4Module to support lazy objects
        mapper.registerModule(new Hibernate4Module());

        messageConverter.setObjectMapper(mapper);
        return messageConverter;

    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        //Here we add our custom-configured HttpMessageConverter
        converters.add(jacksonMessageConverter());
        super.configureMessageConverters(converters);
    }

没有抛出异常,但我在 carType 和 fleet 中收到 null:

{
  "data": [
    {
      "idCar": 4,
      "carType": null,
      "fleet": null,
      "id": "06",
      "initialKm": 1000,
      "carChassis": "VPNEWCAR",
      "note": ""
    }
  ]
}

所以我使用了 Hibernate.initialize(car.getCarType()); 并且它有效。正确吗?

最佳答案

我认为解决方案是(使用其中之一):

  1. 配置hibernate module .
  2. 使用数据传输对象 (DTO) 和任何映射实用程序,例如 Dozer 或 ModelMapper。

更新: 现在调用 Hibernate4Module hbm.enable(Hibernate4Module.Feature.FORCE_LAZY_LOADING); 当然,您可以手动初始化,但这种解决方案要简单得多。

关于java - 使用延迟获取类型检索外部对象的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33754024/

相关文章:

java - 如何在特定书签中使用docx4j在word文档中创建表格而不覆盖word文档

java - 基于 Web 的应用程序设计模式

java - Streams 可以通过返回的方法关闭吗?

java - Spring Cloud Contracts - 没有为主题设置消费者[...]

java - 如何将 web.xml 中的 <security-constraint> 迁移到基于 spring 类的配置(WebApplicationInitializer)

php - 如何手动将时间戳值调整为上一年?

php - 检索模板 joomla 2.5 中的模块参数设置

java - 如何使用 Spring Boot 在后端跟踪文件下载进度?

java - Spring MVC 缺少矩阵变量

PHP bin2hex 与 mysql