Spring boot JPA - 延迟加载不适用于一对一映射
Posted
技术标签:
【中文标题】Spring boot JPA - 延迟加载不适用于一对一映射【英文标题】:Spring boot JPA - Lazy loading is not working for One to One mapping 【发布时间】:2019-12-01 19:22:29 【问题描述】:请注意,我查看了类似的问题,并解释了为什么它们对我不起作用
我有一个简单的 Spring Boot JPA-Hibernate 应用程序,在用户和地址之间具有一对一的映射。 (请注意,一对多映射没有这个问题)
用户实体
@Entity
@Table(name = "users")
public class User implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column
private String name;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
private Address address;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private Set<Note> notes;
地址实体
@Entity
@Table(name = "addresses")
public class Address implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column
private String street;
@Column
private String city;
@JsonIgnore
@OneToOne
@JoinColumn(name = "user_id")
private User user;
笔记实体
@Entity
@Table(name = "notes")
public class Note implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column
private String date;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
我的问题是,每当我调用映射的控制器以获取所有用户时,我都会得到地址以及所有相关的注释。但我希望FetchType.LAZY
能够解决这个问题。
我在 *** 上阅读了很多问题,提到杰克逊可能是这里的罪魁祸首:
Post 1
我还读到 spring.jpa.open-in-view 默认值可能是罪魁祸首:
Post 2
Post 3
所以我尝试了以下选项:
我通过将spring.jpa.open-in-view=false
添加到我的application.properties
来禁用默认打开视图属性,这开始给我
Could not write JSON: failed to lazily initialize a collection of role error
我假设它是因为 Jackson 正在调用我延迟加载的对象上的 getter,所以我按照另一篇文章的说明添加了以下内容,让 Jackson 不理会延迟加载的集合:
pom.xml
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
<version>2.9.9</version>
</dependency>
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters)
for (HttpMessageConverter converter : converters)
if (converter instanceof org.springframework.http.converter.json.MappingJackson2HttpMessageConverter)
ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
mapper.registerModule(new Hibernate5Module());
上述解决方案解决了一对多映射的问题,但仍然在响应中关联了地址。
我不确定我能在这里做什么。默认登录页面上的用户实体不需要任何地址详细信息,因此我不想在登录页面上加载它。单击记录时,它会导航到另一个页面,这就是我希望在响应中返回所有延迟加载的对象的地方。
我已经尝试了所有可以在网上找到的方法,但到目前为止仍然没有任何效果。我真的很感激这方面的一些帮助。
正如其中一位用户所说,它可能与 SO 上的另一个问题重复: Suggested Possible duplicate 我想提一下,我通过禁用 spring.jpa.open-in-view 属性但添加了
mapper.registerModule(new Hibernate5Module());
在响应中返回与用户关联的地址。
【问题讨论】:
您是否考虑过序列化某种 DTO(专用于每个用例而不是单个实体)? 我有,但我也想找出解决这个问题的办法。如果不探索所有选项,我不想进一步发展。 Jackson triggering JPA Lazy Fetching on serialization的可能重复 您是在问 (1) 如何防止 Jackson 映射User.address
,或者 (2) 如何在 User.adress
上启用延迟加载?这些是非常不同的问题。你已经得到了两个答案,每个答案都是我列出的两个答案中的一个。请注意,延迟加载意味着在请求时加载,不 根本不加载
@crizzis 我在问杰克逊如何尊重延迟加载。即使我让延迟加载工作,杰克逊也不尊重它并加载关联。
【参考方案1】:
它的工作方式与 JPA 规范中的一样:-
参考以下网址 https://javaee.github.io/javaee-spec/javadocs/javax/persistence/FetchType.html
LAZY 获取策略只是一个提示(正如 javadoc 所说,数据可以被延迟获取).. 不是强制性操作。
Eager 是强制性的(正如 javadoc 所说,必须急切地获取数据)。
【讨论】:
如果您不想检索地址详细信息,请考虑在 JPA 界面中提供查询。【参考方案2】:你可以看看Jackson Serialization Views。
我查看了您尝试过的 Hibernate5 模块,它有一些有趣的功能......但没有一个可以为您解决这个问题。
顺便说一句,我通常通过不返回实体作为响应而是返回 DTO 来解决此问题。
【讨论】:
JsonView 可能会解决我遇到的问题,但我只是想知道它会延迟加载调用。让我试试【参考方案3】:问题是jackson在写JSON的时候触发了初始化,所以就不要写当前字段(地址)。但是你不应该使用@jsonIgnore
,所以在其他地方你可以返回一个Eager
obj。
你可以使用@jsonView
注解,它可以在不同的请求下为同一个obj提供不同的JSON。你可以看看这个例子:
创建视图类:
public class ViewFetchType
static class lazy
static class Eager extends lazy
注释你的实体
@Entity
public class User
@Id
@JsonView(ViewFetchType.Lazy.class)
private String id;
@JsonView(ViewFetchType.Eager.class)
@OneToOne( fetch = FetchType.LAZY)
private Address address ;
在您的控制器中指定FetchType
类:
public class UserController
private final UserRepository userRepository;
@Autowired
UserController(UserRepository userRepository)
this.userRepository = userRepository;
@RequestMapping("get-user-details")
@JsonView(ViewFetchType.Eager.class)
public @ResponseBody Optional<User> get(@PathVariable String email)
return userRepository.findByEmail(email);
@RequestMapping("get-all-users")
@JsonView(ViewFetchType.Lazy.class)
public @ResponseBody List<User> getUsers()
return userRepository.findAll();
这是我从...得到这个想法的答案...https://***.com/a/49207551/10162200
【讨论】:
以上是关于Spring boot JPA - 延迟加载不适用于一对一映射的主要内容,如果未能解决你的问题,请参考以下文章
当加载 spring-boot 和 spring-data-jpa 时,Hibernate 无法加载 JPA 2.1 Converter