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 拾遗 —— Spring Cache 使用 Jackson 与 自定义 TTL
Spring Boot 升级后“找不到提供程序 com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule”