【问题标题】:Spring Framework Collection was evictedSpring Framework Collection 被驱逐
【发布时间】:2021-06-27 19:06:21
【问题描述】:

我有这个错误:

2020-11-16 22:36:09.313 ERROR 19428 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: collection was evicted; nested exception is org.hibernate.HibernateException: collection was evicted] with root cause

org.hibernate.HibernateException: collection was evicted
    at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:43) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]

我创建了一个 API REST 应用程序,我的实体有这样的组合:

public class Label {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long Id;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "label")
    private Set<Release> releases;
public class Release {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    
    @ManyToOne(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
    @JoinColumn(name = "label_id")
    private Label label;
    

在创建发布/标签关联数据的第三个 API-REST 请求之后,我在顶部出现错误

休息控制器:

    @PostMapping(value = "/release", consumes = "application/json", produces = "application/json")
    Release newRelease(@RequestBody ReleaseDto releaseDto) {
        return releaseService.addRelease(releaseDto);
    }

发布服务:

@Service("ReleaseService")
public class ReleaseServiceImpl implements ReleaseService{

    @Autowired
    ReleaseRepository repository;
    @Autowired
    LabelRepository labelRepository;
    
    @Override
    public Release addRelease(ReleaseDto releaseDto) {
        Release release = new Release();
        Optional<Label> label = labelRepository.findById(releaseDto.getLabel_id());
        if(label.isPresent()){
            release.setName(releaseDto.getName());
            release.setLabel(label.get());
            repository.save(release);
        }
        return release;
    }

我很困惑,也许我必须实现一个实体管理器?

您好。

【问题讨论】:

  • 你也可以添加你的 addRelease 方法吗?到目前为止看起来还不错。
  • @Thomas 我使用了lombok,在 releaseDto 中我使用了@Data notation
  • 我的意思是服务,实现 addRelease。也许您在配置休眠时也有一些不寻常的设置?
  • @Thomas 我是春季的初中生,在我的应用程序中我的 application.properties spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect spring.jpa.hibernate.ddl-auto=update§ spring.datasource.url=jdbc:mysql://IPXX:3306/DB spring.datasource.username=(Username) spring.datasource.password=(Password)
  • @Thomas 我确实更新了这项服务。

标签: java spring hibernate


【解决方案1】:
@EqualsAndHashCode.Exclude
@ToString.Exclude

我为@onetomany 对象添加了这两个注释,我的错误消失了。 但我不知道怎么做。

【讨论】:

  • 你在使用Lombok的@Data注解吗?该通知创建了 equals 和 hashcode 实现,包括检查 OneToMany 集合的内容。这会干扰 Hibernate 的加载策略或类似的东西。添加这些注释将防止 OneToMany 集合被过早访问。
  • 我有同样的问题,我的问题发生在 spring security 中,在添加这个注释之前它起作用了。
【解决方案2】:

作为第一个建议,我建议更改此行:

release = repository.save(release)

save 方法返回实体的更新对象,因此通过返回“未更新”的对象,尝试序列化响应时可能会出现问题。

根据我们的讨论,这里的问题可能是删除 CascadeType.ALL - Hibernate 试图对不同步的相关实体做一些魔术。

也许您还想为响应创建一个 DTO,因为最好将其与实体分开。

使用 FetchType.EAGER 通常也不是一个好主意 - 关于此 https://vladmihalcea.com/eager-fetching-is-a-code-smell/ 的一些注释。如果您更改此设置,您可能需要在服务中手动获取相关实体 - 更改为单独的 DTO,这无论如何都不是问题。

您可以查看https://bootify.io,您可以创建一个示例 REST API(但无论如何都不能使用您的自定义端点)。

【讨论】:

  • 哟!我尝试更改这些行,但不起作用:(我保存了您的项目,我会研究它。我不明白我错在哪里
  • 嗯也不太确定 - 您现在可以从服务/控制器中删除响应,看看错误是否仍然存在。
  • 我删除控制器的响应,错误仍然存​​在。
  • 另一个想法:尝试删除 CascadeType.ALL - 也许 Hibernate 在内部尝试使用已过时的版本更新标签。
  • 我删除了 CascadeType.ALL,并用 LAZY 更改了所有 EAGER,它可以工作了!谢谢托马斯!现在仔细阅读vladmihalcea.com/eager-fetching-is-a-code-smell,之后我想阅读你的项目bootify.io。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-23
  • 2022-11-11
  • 2014-10-12
  • 2018-09-26
  • 2011-11-11
  • 2016-09-10
  • 1970-01-01
相关资源
最近更新 更多