当前位置: 首页 > 知识库问答 >
问题:

如何使用Spring Boot将大型实体转换为dto[副本]

乐宜民
2023-03-14

我正在尝试制作一个基于数据库的API,我有一个巨大的数据负载,但每次我尝试使用可分页属性的数据时,我都会得到这个错误:

{
    "timestamp": "2022-01-12T01:34:01.851+00:00",
    "status": 500,
    "error": "Internal Server Error",
    "trace": "org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: br.com.leomanzini.space.flight.news.model.Article.launches, could not initialize proxy - no Session\r\n\tat org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:612)\r\n\tat org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218)\r\n\tat org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:591)\r\n\tat org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)\r\n\tat org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:387)\r\n\tat java.base/java.lang.Iterable.forEach(Iterable.java:74)\r\n\tat br.com.leomanzini.space.flight.news.dto.ArticlesDTO.<init>(ArticlesDTO.java:65)\r\n\tat br.com.leomanzini.space.flight.news.service.ArticleService.lambda$findAll$0(ArticleService.java:30)\r\n\tat java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)\r\n\tat java.base/java.util.ArrayList$Itr.forEachRemaining(ArrayList.java:1032)\r\n\tat java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)\r\n\tat java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)\r\n\tat java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)\r\n\tat java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)\r\n\tat java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)\r\n\tat java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)\r\n\tat org.springframework.data.domain.Chunk.getConvertedContent(Chunk.java:173)\r\n\tat org.springframework.data.domain.PageImpl.map(PageImpl.java:106)\r\n\tat br.com.leomanzini.space.flight.news.service.ArticleService.findAll(ArticleService.java:30)\r\n\tat br.com.leomanzini.space.flight.news.controller.SpaceFlightsApiController.findAll(SpaceFlightsApiController.java:28)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:566)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:655)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:764)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:834)\r\n",
    "message": "failed to lazily initialize a collection of role: br.com.leomanzini.space.flight.news.model.Article.launches, could not initialize proxy - no Session",
    "path": "/articles"
}

在数据库中,我有大量的11795篇文章以及它们与其他表的各自关系,有一种方法可以优化此负载或只是使其工作?

第条实体:

import lombok.*;

import javax.persistence.*;
import java.util.List;

@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "article")
public class Article {

    @Id
    @EqualsAndHashCode.Include
    private Long id;

    @Column(nullable = false)
    private Boolean featured;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String url;

    @Column(name = "image_url", nullable = false)
    private String imageUrl;

    @Column(name = "news_site", nullable = false)
    private String newsSite;

    @Column(nullable = false)
    private String summary;

    @Column(name = "published_at", nullable = false)
    private String publishedAt;

    @ManyToMany(fetch = FetchType.LAZY)
    private List<Launches> launches;

    @ManyToMany(fetch = FetchType.LAZY)
    private List<Events> events;

    @Column(name = "inserted_by_human")
    private Boolean insertedByHuman = false;
}

活动和启动实体:

import lombok.*;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Events {

    @Id
    @EqualsAndHashCode.Include
    private Long id;

    private String provider;
}

import lombok.*;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Launches {

    @Id
    @EqualsAndHashCode.Include
    private String id;

    private String provider;
}

存储库只是一个接口,JpaRepository和文章作为实体。

服务类别:

import br.com.leomanzini.space.flight.news.dto.ArticlesDTO;
import br.com.leomanzini.space.flight.news.model.Article;
import br.com.leomanzini.space.flight.news.repository.ArticleRepository;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

@Service
@AllArgsConstructor
public class ArticleService {

    @Autowired
    private final ArticleRepository articleRepository;

    public Page<ArticlesDTO> findAll(Pageable pageable) {
        Page<Article> articleList = articleRepository.findAll(pageable);
        return articleList.map(article -> new ArticlesDTO(article));
    }
}

如果我只是使用我的实体作为返回,这些方法可以工作,但是当我将其转换为dto时,应用程序就会中断。dto类如下:

import br.com.leomanzini.space.flight.news.model.Article;
import lombok.*;

import javax.management.ConstructorParameters;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ArticlesDTO implements Serializable {

    @NotEmpty
    @EqualsAndHashCode.Include
    private Long id;

    @NotEmpty
    private String title;

    @NotEmpty
    private String url;

    @NotEmpty
    private String imageUrl;

    @NotEmpty
    private String newsSite;

    @NotEmpty
    private String summary;

    @NotEmpty
    private String publishedAt;

    @NotEmpty
    private String updatedAt;

    @NotEmpty
    private Boolean featured;

    @Valid
    private List<LaunchesDTO> launches;

    @Valid
    private List<EventsDTO> events;

    public ArticlesDTO (Article article) {
        id = article.getId();
        title = article.getTitle();
        url = article.getUrl();
        imageUrl = article.getImageUrl();
        newsSite = article.getNewsSite();
        summary = article.getSummary();
        publishedAt = article.getPublishedAt();
        updatedAt = article.getPublishedAt();
        featured = article.getFeatured();
        launches = new ArrayList<>();
        article.getLaunches().forEach(launch -> {
            LaunchesDTO launchesDTO = new LaunchesDTO(launch.getId(), launch.getProvider());
            launches.add(launchesDTO);
        });
        events = new ArrayList<>();
        article.getEvents().forEach(event -> {
            EventsDTO eventsDTO = new EventsDTO(event.getId(), event.getProvider());
            events.add(eventsDTO);
        });
    }
}

有什么方法可以修复这个错误并让它正常工作?是加速数据库加载还是别的什么?

共有2个答案

司徒修能
2023-03-14

建议的答案是,在服务类中,@Transactional(readOnly = true)属性已被启用,它可以很好地解决错误

未能懒散地初始化角色集合:br.com.leomanzini.space.flight.news.model.Article。启动时,无法初始化代理。

服务类上的方法如下所示:

import br.com.leomanzini.space.flight.news.dto.ArticlesDTO;
import br.com.leomanzini.space.flight.news.model.Article;
import br.com.leomanzini.space.flight.news.repository.ArticleRepository;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@AllArgsConstructor
public class ArticleService {

    @Autowired
    private final ArticleRepository articleRepository;

    @Transactional(readOnly = true)
    public Page<ArticlesDTO> findAll(Pageable pageable) {
        Page<Article> articleList = articleRepository.findAll(pageable);
        return articleList.map(article -> new ArticlesDTO(article));
    }
}

请购单工作正常!

方高丽
2023-03-14

使用< code>FetchType。LAZY,用于检索这些字段的查询只有在第一次被访问时才会被执行。为了做到这一点,Hibernate为我们的实体类创建并配置代理类(这就是为什么如果我们想使用延迟加载特性,我们也不应该将我们的实体类声明为< code>final。

当Hibernate初始化代理时,它需要一个< code >会话来完成任务。这就是为什么当您没有向服务方法添加< code>@Transactional注释时,它会抛出一个< code > LazyInitializationException...没有会话。

除了上面的解决方案,如果您不想添加@Transactional注释,您可以将hibernate.enable_lazy_load_no_trans属性设置为true

<property
name="hibernate.enable_lazy_load_no_trans"
value="true"/>

但是这种解决方案被认为是反模式的。每当您尝试延迟加载时,它将创建一个新的< code >会话。你可以在这里读到更多。< br > hibernate . enable _ lazy _ load _ no _ trans反模式

 类似资料:
  • 我有一个项目,我需要在数据库中存储用户。我正在使用Hibernate,在模块的某些部分中,也在实验性地使用Spring数据JPA。我有一个用于注册客户的RESTendpoint,并在那里接收UserDTO对象。之后,在其他服务中,我需要将其转换为UserEntity并保存在数据库中。 现在我创建了用户设置页面,我需要显示一些关于登录用户的信息。我不想发送UserDTO对象,因为有太多的数据,所以我

  • 好的,我有三个实体:主题、用户、类别、图片。用户有图片,主题有用户和类别。 我还有一个话题要讲 我可以将ModelMapper注入TopicService,并使用它进行转换,但它不能按照我的需要工作,在这种情况下,如果我试图将Topic转换为TopicDTO,在转换后的TopicDTO对象中,UserDTO和CategoryTo将为null,但在调试中,在转换之前,在Topic对象中,Catego

  • 我找了无数的问题。但大多数问题如下。 实体- 但我不想这样。 若Dto中不存在实体中的属性值,我想知道如何将Dto转换为实体。 没有为[annotations,Lombok,jpa,…]指定代码,但是它存在! userService的所有方法都返回DTO。如何在Post实体中设置用户实体?我收到一个userDto返回,它只有用户名。 这种时候我该怎么办? 存储库不是直接从控制器调用的。 服务将无条

  • 我试图使用MapStruct创建一个“PersondTo”类到“PersonEntity”的映射器 无法将属性“java.util.List Cars”映射到“com.example.car.CarEntity Cars”。考虑声明/实现一个映射方法:“com.example.car.carEntity map(java.util.List value)”。 如果我从Person类中删除“加法器”

  • 我正在尝试将复杂的实体转换为Dto。我想从DTO中删除实体中的一些值。 我的实体看起来像这样(为了简单起见,省略了实体的大部分): 我找到了一个对简单实体非常有效的解决方案:将实体转换为数据。如果我采纳了自定义拦截器的建议,删除id或整个item属性就可以了。 我尝试了两种方法来定义我的DTO: < li >它仅返回id和整个项目。 现在的问题是我只想删除 item 属性中的某些值。例如,私有字段

  • 如何正确转换dto到json在Java?我这样做就像下面使用: 问题在于格式化字段。在Dto我有我的日期在这种格式:但转换此dto到json字节后,我看到我的拆分为对象与许多属性如下: 在使用之后,我希望将中的所有属性以与转换之前相同的格式进行转换。如何做到这一点? 谢谢你的帮助!