Spring Boot 2. Jackson json 序列化或 Spring Data JPA FetchType.Lazy

Posted

技术标签:

【中文标题】Spring Boot 2. Jackson json 序列化或 Spring Data JPA FetchType.Lazy【英文标题】:Spring Boot 2. Jackson json serialization or Spring Data JPA FetchType.Lazy 【发布时间】:2018-11-07 17:12:55 【问题描述】:

我的情况非常奇怪,坦率地说,我不完全确定它是 Jackson 序列化问题还是与 Spring Data JPA 如何获取 Lazy 对象有关

春季 2.0.2

spring-boot-starter-data-jpa spring-boot-starter-web spring-boot-devtools mysql-connector-java

当您搜索大多数人对 Jackson 的问题时,它是序列化会话之外的延迟提取,导致以下异常。 但是,我根本没有遇到这个异常......

org.hibernate.LazyInitializationException:无法初始化代理 - 没有会话

问题

    它实际上在我的控制器中获取数据并返回 json 对象(下面的休眠查询)。急切地获取它是一个问题,因为它会获取未使用的不必要的大数据。

结构(省略getter和setter以使线程更短)

       User
        | <---[ OneToMany ]        
     Employee  hierarchies entity 
        |
  +-----+-----+
  |           |
PartTime   FullTime

用户

@Entity
public class User 

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;

@OneToMany(mappedBy="user")
@JsonIgnoreProperties("user")
private List<Employee> employee = new ArrayList<>();

员工

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Employee 

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JsonIgnoreProperties("employee")
private User user;

FullTime / PartTime(在 PartTime 时,现场工资更改为每小时工资)

@Entity
public class FullTime extends Employee  

private BigDecimal salary;

UserRepository 扩展 CrudRepository

用户服务

public User getUserById(Long id) 

    Optional<User> optionalUser = userRepo.findById(id);
    User user = optionalUser.get();

    logger.info("\n User -> ", user);
    return user;

控制器

@RestController
@RequestMapping(value="/api/user")
public class UserController 

  @GetMapping(value="/userId" )
  public User getUser(@PathVariable("userId") Long id) 
    return userService.getUserById(id);
     


在我的应用程序上扩展了 CommandLineRunner,它允许我在应用程序启动时运行命令

@Override
public void run(String... args) throws Exception 
  logger.info("users 1 -> " , userService.getUserById(1L));



Hibernate: 
select
    user0_.id as id1_3_0_,
    user0_.name as name2_3_0_ 
from
    user user0_ 
where
    user0_.id=?

INFO 14434 --- [  restartedMain] ication$$EnhancerBySpringCGLIB$$6cf0457c :     
users 1 -> 
User [id=1, name=Jack]

但是当我通过我的控制器http://localhost:8080/api/user/1 时,我得到了 2 个单独的休眠调用,这两个调用似乎都在我的服务层内。请记住,我的服务层没有事务,所以它真的很奇怪......

Hibernate:  << 1st
select
    user0_.id as id1_3_0_,
    user0_.name as name2_3_0_ 
from
    user user0_ 
where
    user0_.id=?

com.example.app.service.UserService      : << -- In service 
User -> 
User [id=1, name=Jack]

Hibernate: 
select
    employee0_.user_id as user_id2_0_0_,
    employee0_.id as id1_0_0_,
    employee0_.id as id1_0_1_,
    employee0_.user_id as user_id2_0_1_,
    employee0_1_.salary as salary1_1_1_,
    employee0_2_.hourly_wage as hourly_w1_2_1_,
    case 
        when employee0_1_.id is not null then 1 
        when employee0_2_.id is not null then 2 
        when employee0_.id is not null then 0 
    end as clazz_1_ 
from
    employee employee0_ 
left outer join
    full_time employee0_1_ 
        on employee0_.id=employee0_1_.id 
left outer join
    part_time employee0_2_ 
        on employee0_.id=employee0_2_.id 
where
    employee0_.user_id=?

现在,如果它是 Jackson 序列化问题,我访问过 Avoid Jackson serialization on non fetched lazy objects 、Configure Jackson to omit lazy-loading attributes in Spring Boot 等等,但所有这些都是通过扩展 WebMvcConfigurerAdapter 来完成的,我认为它在 spring5 中已被弃用?

如果它与 Spring Data JPA 有关...那么请说明一下,因为我一直认为您需要 @Transaction 注释来进行惰性 Fetch 以将关系与休眠会话关联...

对不起,长线程...

【问题讨论】:

你应该使用 DTO。请检查***.com/questions/1612334/… 和baeldung.com/… 您正在返回休眠对象,并且在序列化期间,没有会话,因为它已经关闭。 感谢收看。但我实际上没有得到 LazyInitializationException....我不喜欢 DTO,因为它为应用程序添加了额外的层.... 【参考方案1】:

我认为您启用了属性spring.jpa.open-in-view(默认为true)。检查您是否在日志中看到以下消息:

spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning

如果禁用它,您应该会看到所需的异常。

【讨论】:

以上是关于Spring Boot 2. Jackson json 序列化或 Spring Data JPA FetchType.Lazy的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 2. Jackson json 序列化或 Spring Data JPA FetchType.Lazy

Spring boot与Jackson ObjectMapper

Spring Boot 升级后 Jackson 序列化不起作用

spring-boot 使用啥版本的 Jackson?

Spring boot 拾遗 —— Spring Cache 使用 Jackson 与 自定义 TTL

Spring Boot 升级后“找不到提供程序 com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule”