我正在使用以下示例的弹簧靴,弹簧腹板和弹簧数据。
我有一个名为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;
}
答案 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()
执行以下选项来修复错误:
将下面的属性设置为application.properties
文件(如异常消息所示):
spring.jackson.serialization.fail-on-empty-beans=false
使用lazy-init属性注释实体,如:
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
所以,回答这个问题:
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()
也将返回代理,因为它只是从中检索缓存的代理持久化背景。