如何使用 Spring Boot 带来一个大实体并将其转换为 dto
How can I bring a large entity and convert the same to dto using Spring Boot
我正在尝试创建一个基于数据库的数据库 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[=11=](ArticleService.java:30)\r\n\tat java.base/java.util.stream.ReferencePipeline.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 和文章作为实体的接口。
服务class:
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));
}
}
如果我只是将我的实体用作 return,这些方法可以工作,但是当我将其转换为 dto 时,应用程序会中断。 dto class 如下:
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);
});
}
}
有什么方法可以修复错误并使其正常工作?可以加速数据库加载还是其他?
建议的答案是在服务class中启用了@Transactional(readOnly = true)
属性,可以很好地解决错误
failed to lazyly initialize a collection of role: br.com .
leomanzini.space.flight.news.model.Article.launches, could not
initialize proxy.
服务中的方法 class 如下所示:
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));
}
}
申请工作正常!
使用FetchType.LAZY
,用于检索这些字段的查询将仅在第一次访问时执行。为了做到这一点,Hibernate 为我们的实体 类 创建并配置了代理 类 (这就是为什么我们也不应该声明我们的实体 类 为 final
如果我们想使用延迟加载功能)。
当 Hibernate 初始化代理时,它需要 Session
才能完成任务。这就是为什么当您不向服务方法添加 @Transactional
注释时,它会抛出一个 LazyInitializationException...no Session
.
除了上面的解决方案,如果不想添加@Transactional
注解,可以将hibernate.enable_lazy_load_no_trans
属性设置为true
。
<property
name="hibernate.enable_lazy_load_no_trans"
value="true"/>
但是这个解决方案被认为是一种反模式。每次您尝试延迟加载时,它都会创建一个新的 Session
。您可以在这里阅读更多内容。
The hibernate.enable_lazy_load_no_trans Anti-Pattern
我正在尝试创建一个基于数据库的数据库 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[=11=](ArticleService.java:30)\r\n\tat java.base/java.util.stream.ReferencePipeline.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 和文章作为实体的接口。
服务class:
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));
}
}
如果我只是将我的实体用作 return,这些方法可以工作,但是当我将其转换为 dto 时,应用程序会中断。 dto class 如下:
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);
});
}
}
有什么方法可以修复错误并使其正常工作?可以加速数据库加载还是其他?
建议的答案是在服务class中启用了@Transactional(readOnly = true)
属性,可以很好地解决错误
failed to lazyly initialize a collection of role: br.com . leomanzini.space.flight.news.model.Article.launches, could not initialize proxy.
服务中的方法 class 如下所示:
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));
}
}
申请工作正常!
使用FetchType.LAZY
,用于检索这些字段的查询将仅在第一次访问时执行。为了做到这一点,Hibernate 为我们的实体 类 创建并配置了代理 类 (这就是为什么我们也不应该声明我们的实体 类 为 final
如果我们想使用延迟加载功能)。
当 Hibernate 初始化代理时,它需要 Session
才能完成任务。这就是为什么当您不向服务方法添加 @Transactional
注释时,它会抛出一个 LazyInitializationException...no Session
.
除了上面的解决方案,如果不想添加@Transactional
注解,可以将hibernate.enable_lazy_load_no_trans
属性设置为true
。
<property
name="hibernate.enable_lazy_load_no_trans"
value="true"/>
但是这个解决方案被认为是一种反模式。每次您尝试延迟加载时,它都会创建一个新的 Session
。您可以在这里阅读更多内容。
The hibernate.enable_lazy_load_no_trans Anti-Pattern