即使使用@ Transactional,LazyInitializationException [英] LazyInitializationException even though @Transactional is used
问题描述
当前我遇到以下异常:
org.hibernate.LazyInitializationException:无法延迟初始化角色集合:com.example.model.Link.subLinks,不能初始化代理-没有会话
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.model.Link.subLinks, could not initialize proxy - no Session
我用谷歌搜索,并且找到了针对此异常的另一种解决方案,但我想知道为什么@Transactional在我的案例中无法正常工作.我确定我做错了什么.我在做什么错了?
I googled and I found another solution for this exception but I would like to know why @Transactional in my case is not working. I am sure that I am doing something wrong. What am I doing wrong?
奇怪的是,我已经在该项目的其他地方使用了@Transactional,并且可以正常使用.
提前感谢您的提示.
我的链接类别:实体链接包含子链接的集合.
My Link class: The entity Link contains a collection of SubLink.
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Link {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@NotEmpty
private String title;
@NotEmpty
private String description;
@OneToMany(mappedBy = "link")
private Collection<SubLink> subLinks;
}
我的SubLink类:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class SubLink {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@NotEmpty
private String type;
@NotEmpty
@URL
private String url;
@ManyToOne
@JoinColumn(name = "link_id", referencedColumnName = "id")
private Link link;
}
我的LinkServiceImpl类:
@Service
public class LinkServiceImpl implements LinkService {
@Autowired
public LinkRepository linkRepository;
@Override
@Transactional
public Link findById(long id) {
return linkRepository.findById(id);
}
}
在我的控制器类中,有方法showLink():
@GetMapping("/link/{linkId}")
public String showLink(@PathVariable(value = "linkId") long linkId, Model model) {
Link link = linkService.findById(linkId);
Collection<SubLink> subLinkCollection = link.getSubLinks(); //Error
model.addAttribute("subLinkCollection", subLinkCollection);
return "link";
}
推荐答案
Aman 很好地解释了您的案例中 LazyInitializationException
的原因和贪婪>添加了有关为什么 @Transactional
不能按预期工作以及应如何使用的更多信息.
Aman explained well the cause of the LazyInitializationException
in your case and crizzis added more information about why @Transactional
is not worked as you expected and how it should be used.
因此,总结一下解决问题所必须采取的措施:
So, to summarize the options you have to solve your problem:
在 Aman 和 crizzis 的评论下,从性能的角度来看,这很容易,但不是最好的.
Commented by Aman and crizzis, this is the easier but not the best from the point of view of the performance.
为此,请在 subLinks
属性定义中包括 fetch = FetchType.EAGER
:
To do it, include fetch = FetchType.EAGER
in subLinks
property definition:
@OneToMany(mappedBy = "link", fetch = FetchType.EAGER)
private Collection<SubLink> subLinks;
但是,每次您从 Link
=>的数据库实例获取时,其相关的 SubLink
的集合也将包括在内.
However, every time you get from database instances of Link
=> its collection of related SubLink
will be included.
也由 Aman 评论(尽管在(link.id = sublink.link.id)上不是必需的).在这种情况下,您可以在存储库中创建一个新方法,以获取特定 Link
的 SubLink
集合.
Commented by Aman too (although is not necessary on (link.id = sublink.link.id)
). In this case, you can create a new method in your repository to get the SubLink
collection of an specific Link
.
通过这种方式,您将能够处理想要接收此类额外信息"的情况.( findWithSubLinkById
)或不提供( findById
).
In this way, you will be able to deal with situations on which you want to receive such "extra information" (findWithSubLinkById
) or not (provided findById
).
使用双向 OneToMany
,就可以满足以下要求:
With a bidirectional OneToMany
, it is enough with something like:
@Query("select l from Link l left join fetch l.subLinks where l.id = :id")
Link findWithSubLinkById(Long id);
使用单向 OneToMany
,除了上述查询外,您还必须包括如何"加入两个表:
With a unidirectional OneToMany
, besides the above query you have to include how "join" both tables:
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "link_id")
private Collection<SubLink> subLinks;
从 SubLink
类中删除 link
属性.
这是前一个版本的变体.因此,不是使用 @Query
创建新方法,而是使用 @EntityGraph
配置一个更简单的选择:
This is a variation of the previous one. So, instead of create the new method using @Query
, an easier choice will be configured with @EntityGraph
:
@EntityGraph(attributePaths = "subLinks")
Link findWithSubLinkById(Long id);
更多信息此处(示例77
)
正如 crizzis 所评论的那样,在用 @Transactional
配置的方法内,您不会收到此类异常.因此,另一种选择是将使用 Sublink
的代码从您的控制器移至您的服务.
As crizzis commented, inside the method configured with @Transactional
you won't receive such exception. So, another option is move the code that uses Sublink
from your controller to your service.
这篇关于即使使用@ Transactional,LazyInitializationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!