JpaRepository.findOne()对JpaRepository.getOne()

时间:2017-07-11 10:14:36

标签: java hibernate jackson spring-data

我正在使用以下示例的弹簧靴,弹簧腹板和弹簧数据。

我有一个名为Person的实体,我已经在数据库中填充了两个Person

人员实体

@Entity
public class Person {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(unique = true, nullable = false)
private long id;
private String name;

public long getId() {
    return id;
}
public void setId(long id) {
    this.id = id;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public Personne() {
}
public Personne(long id, String name) {
    this.id = id;
    this.name = name;
}}

PersonRepository

@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
}

PersonController

@RestController
public class PersonController {

@Autowired
private PersonRepository personRepo;

@RequestMapping(value = "/perss/{id}")
public Person getById(@PathVariable("id") long id) {
    return personRepo.xxxx(id);
}}

用例1

当我用 personRepo.xxxx(id) 替换 personRepo.getOne(id) 并点按localhost:8080/perss/1时,我在浏览器中出现Could not write JSON: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)错误事实上,getOne()方法返回一个代理人,杰克逊以某种方式无法转换。

用例2

当我用 personRepo.xxxx(id) 替换 personRepo.findOne(id) 并点击localhost:8080/perss/1时,我会以正确的JSON格式获得所需的Person对象(这个工作正常。)

用例3

当我使用以下代码替换PersonController getById()方法的代码时:

@RequestMapping(value = "/perss/{id}")
public Person getById(@PathVariable("id") long id) {
    Person p1 = personRepo.findOne(id);
    Person p2 = personRepo.getOne(id);
    return p2;
}

点击localhost:8080/perss/1我以正确的JSON格式获取所需的Person对象。

问题:

使用getOne()给我一个错误,但使用findOne()getOne()一起给了我很好的结果。

findOne()如何影响getOne()的行为。

修改

使用案例4

当我颠倒p1和p2的顺序时,我得到一个错误。

@RequestMapping(value = "/perss/{id}")
public Person getById(@PathVariable("id") long id) {
    Person p2 = personRepo.getOne(id);
    Person p1 = personRepo.findOne(id);
    return p2;
}

2 个答案:

答案 0 :(得分:1)

尝试返回p1,您可能会收到同样的错误。

@RequestMapping(value = "/perss/{id}")
public Person getById(@PathVariable("id") long id) {
    Person p1 = personRepo.findOne(id);
    Person p2 = personRepo.getOne(id);
    return p1;
}

您没有得到任何内容,因为您没有序列化p1 JavassistLazyInitializer代理。你序列化了p2而已经很好了。

这个也没关系:

@RequestMapping(value = "/check/{id}")
public void getById(@PathVariable("id") long id) {
    personRepo.getOne(id);
}

当对象从POJO转换为JSON时发生JSON序列化。

由于序列化在完全加载之前发生,因此发生了具有lazy-init属性的bean序列化的错误。

您可以尝试使用findOne()执行以下选项来修复错误:

  1. 将下面的属性设置为application.properties文件(如异常消息所示):

    spring.jackson.serialization.fail-on-empty-beans=false

  2. 使用lazy-init属性注释实体,如:

    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})

  3. 所以,回答这个问题:

      

    findOne()如何影响getOne()的行为。

    没有。并且对存储库的调用也不会调用JSON序列化过程。

答案 1 :(得分:1)

在使用findOne()getOne()时,调用的顺序影响结果是正确的。

简答:两种方法都将首先在持久化上下文中查找ID,并返回缓存的值(如果存在)。如果在持久化上下文中找不到任何内容,则它们将继续加载其首选结果并对其进行缓存。下次运行时,其他方法将找到缓存的值。

    如果getOne(id)不在持久性上下文中,
  • id将加载(并缓存)代理。
  • 如果findOne(id)不在持久化上下文中,
  • id将加载(并缓存)裸实体。

长答案:我遇到了同样的问题,我的项目使用了Hibernate 5.2.4.Final。正在发生的事情的细节涉及一些Hibernate代码。调试一段时间后,我发现findOne()getOne()最终都调用了Hibernate的DefaultLoadEventListener.onLoad()方法,但是他们用不同的loadType参数调用它:

  • getOne()最终委托SessionImpl.IdentifierLoadAccessImpl<T>.doGetReference()指定LoadEventListener.LOAD的loadType,最终传递给DefaultLoadEventListener.proxyOrLoad()LoadEventListener.LOAD 确实允许创建代理。
  • findOne()最终委托SessionImpl.IdentifierLoadAccessImpl<T>.doLoad()指定LoadEventListener.GET的loadType值,最终传递给DefaultLoadEventListener.proxyOrLoad()LoadEventListener.GET 允许创建代理。

DefaultLoadEventListener.proxyOrLoad() 中设置断点,以验证传入的LoadType options参数是否具有其allowProxyCreation字段的不同值,具体取决于{{1} }或findOne()正在调用它。

您可以看到,如果getOne()为真并且没有代理,则allowProxyCreation将返回proxyOrLoad()的结果。在使用 createProxyIfNecessary()的情况下,这将导致返回代理。

如果在getOne()之前调用了findOne()相同的实体类型和ID,那么当getOne()调用进入getOne()时,它将提前返回因为实体已经在持久化上下文中找到了。在这种情况下,调用createProxyIfNecessary() 会导致创建代理。

如果在getOne()之前调用getOne(),则代理将被创建并存储在持久性上下文中,findOne()也将返回代理,因为它只是从中检索缓存的代理持久化背景。