【问题标题】:Spring Boot JPA Lazy Fetch is not workingSpring Boot JPA Lazy Fetch 不起作用
【发布时间】:2018-12-09 05:00:30
【问题描述】:

我有以下两个域对象 Suggestion 和 UserProfile

它们以一对多的关系相互映射。当我使用 Spring Data JPA 获取所有建议时,我会得到每个建议对象对应的用户对象。即使我将fetch 设置为FetchType.Lazy,也会观察到此结果。以下是我的代码:

Suggestion.java

@Entity
@Table(name="suggestion")
@JsonIgnoreProperties({"suggestionLikes"})
public class Suggestion {

public Suggestion() {
    // TODO Auto-generated constructor stub
}

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="suggestion_id")
private Integer suggestionId;

@Column(name="description")
private String description;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="suggestion_by")
private UserProfile user;

//getters and setters
}

UserProfile.java

@Entity
@Table(name = "user_master")
@JsonIgnoreProperties({"suggestions", "suggestionLikes"})
public class UserProfile implements Serializable {

/**
 * 
 */
private static final long serialVersionUID = 7400472171878370L;


public UserProfile() {

}


@Id
@NotNull
@Column(name = "username", length = 55)
private String userName;

@NotNull
@Column(name = "password")
private String password;

@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private Set<Suggestion> suggestions;

//getters and setters
}

以下是获取记录的服务

@Override
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public List<Suggestion> getAllSuggestion() {
    return suggestionRespository.findAll();;
}

建议存储库:

@Repository
public interface SuggestionRespository extends JpaRepository<Suggestion, 
Integer> {

    public List<Suggestion> findAll();
}

以下是 Application 类:

@EnableTransactionManagement
@SpringBootApplication
public class AngularSpringbootApplication {

public static void main(String[] args) {
    SpringApplication.run(AngularSpringbootApplication.class, args);
}
}

application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/plan_trip
spring.datasource.username=root
spring.datasource.password=root

spring.jpa.properties.hibernate.dialect = 
org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto = update
spring.jackson.serialization.fail-on-empty-beans=false

getAllSuggestions() 执行时收到的响应:

[
{
    "suggestionId": 2,
    "description": "Germanyi!",
    "createdBy": "vinit2",
    "createdDate": "2018-06-19T10:38:32.000+0000",
    "modifiedBy": "vinit2",
    "modifiedDate": "2018-06-19T10:38:32.000+0000",
    "user": {
        "userName": "vinit2",
        "password": 
"$2a$10$.hP0sQWpl6qqDKiNTkiu0OciQeHRFnkEbEWcDvnv1HY4QCi2tKo.2",
        "firstName": "Vinit2",
        "lastName": "Divekar2",
        "emailAddress": "vinit@gmail.com",
        "createdBy": null,
        "modifedBy": null,
        "createdDate": "2018-06-04",
        "modifiedDate": "2018-06-04",
        "isActive": "1",
        "handler": {},
        "hibernateLazyInitializer": {}
    }
},
{
    "suggestionId": 1,
    "description": "Vasai!",
    "createdBy": "vinit1",
    "createdDate": "2018-06-19T10:37:38.000+0000",
    "modifiedBy": "vinit1",
    "modifiedDate": "2018-06-19T10:37:38.000+0000",
    "user": {
        "userName": "vinit1",
        "password": "$2a$10$D0RMSTWu03Jw7wC1/zqFxOOjb0Do24o/4mq2PhDhRUyBrs8bdGvUG",
        "firstName": "Vinit1",
        "lastName": "Divekar1",
        "emailAddress": "vinit@gmail.com",
        "createdBy": null,
        "modifedBy": null,
        "createdDate": "2018-06-04",
        "modifiedDate": "2018-06-04",
        "isActive": "1",
        "handler": {},
        "hibernateLazyInitializer": {}
    }
}

]

预期响应:

[{
    "suggestionId": 2,
    "description": "Germanyi!",
    "createdBy": "vinit2",
    "createdDate": "2018-06-19T10:38:32.000+0000",
    "modifiedBy": "vinit2",
    "modifiedDate": "2018-06-19T10:38:32.000+0000"
},
{
    "suggestionId": 1,
    "description": "Vasai!",
    "createdBy": "vinit1",
    "createdDate": "2018-06-19T10:37:38.000+0000",
    "modifiedBy": "vinit1",
    "modifiedDate": "2018-06-19T10:37:38.000+0000"
}
]

当我将FetchType 声明为Lazy 时,当我在建议实体上执行findAll() 时,我不应该获取用户对象(JSON 格式)。

我在这里错过了什么?

【问题讨论】:

  • 你错过了懒惰的意思。懒惰并不意味着“在加载的建议中存储 null 而不是用户”。这意味着“仅当代码第一次尝试访问此数据时才从数据库加载实际用户数据”,例如使用suggestion.getUser().getUsername()。另外,不要将 List 转换为 ArrayList。绝对不能保证返回的列表是一个 ArrayList,你的代码不应该关心。你为什么这样做?
  • @JBNizet,感谢您的回复。我从“懒惰”获取的意思中理解的是; “在我询问他们何时访问他们的父母之前,不要给我孩子”。那是对的吗?我推荐了this question。另外,谢谢你的建议,我会相应地更新我的问题。我已经更新了
  • 没有。这意味着只有当您第一次尝试访问该状态时,才会从数据库中加载子对象的状态,即第一次调用子对象上的方法。
  • 再一次,调用 getUser() 不会从数据库中加载用户的状态。 在 getUser() 返回的 User 上调用方法 会做到这一点。为什么你认为延迟加载不起作用?你是怎么得出这个结论的?
  • 我不应该得到用户对象这是什么意思?你执行了哪些代码,你期望它做什么,它做了什么?除非该建议未链接到任何用户,否则您将始终在建议中包含一个用户。但是 User 的 state 会被延迟加载。这才是最重要的:避免无用的 SQL 查询。如果您从未对建议的用户调用任何方法,则不会执行查询以从数据库中加载用户数据。

标签: java spring hibernate spring-boot spring-data-jpa


【解决方案1】:

您可以使用@JsonManagedReference 和@JsonBackReference 来防止jakson 调用代理。以下代码可能会对您有所帮助。

@JsonBackReference
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private Set<Suggestion> suggestions;

@JsonManagedReference
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "suggestion_by")
private UserProfile user;

添加如下依赖,根据你的hibernate修改版本

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>

最后添加一个新配置

@Configuration
public class JacksonConfig {

@Bean
public Jackson2ObjectMapperBuilderCustomizer addCustomBigDecimalDeserialization() {
    return new Jackson2ObjectMapperBuilderCustomizer() {
        @Override
        public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
            jacksonObjectMapperBuilder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            jacksonObjectMapperBuilder.modules(new Hibernate5Module());
        }

    };
 }
}

【讨论】:

  • 感谢您的回复。但是,我仍然在 JSON 中获取用户对象。
  • @JsonBackReference 可以很好地隐藏 json 中的惰性数据
【解决方案2】:

当你声明 fetch = FetchType.LAZY 时,这意味着 hibernate 在运行时为这个字段创建一个代理。当调用该字段的 getter 时。 hibernate 执行另一个选择来获取这个对象。 如果您遇到问题,杰克逊会调用“用户”字段的获取器(如果您使用休息)。 因此,如果您不想要“用户”,请尝试使用模型映射器框架(推土机映射器是一个很好的框架)。

【讨论】:

    猜你喜欢
    • 2018-04-03
    • 1970-01-01
    • 2014-01-03
    • 2020-07-11
    • 2021-12-19
    • 1970-01-01
    • 2021-09-11
    • 1970-01-01
    • 2020-05-09
    相关资源
    最近更新 更多