我在Spring Boot上创建的API中有两种方法(通过Hibernate和JpaRepository)从mySQL数据库中检索数据。有一种方法可以返回名为 test 的表中的所有事件,而另一种方法可以返回与作为GET调用中的参数传递的id对应的 test 。两个API入口点(通过服务和存储库)最终都调用了两个JpaRepository方法(分别是 findAll()和 getOne())。
我观察到的问题是,在 findAll()方法中,JpaRepository的行为与 getOne()不同,涉及到返回与之相对应的内部对象列表模型中的@ManyToMany关系。 test 类具有与模型的不同实体相对应的必要对象的列表。这两个类如下:
@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="idtest")
public class Pectest {
@Id
@Column(name="idtest")
private long idtest;
private String testname;
private String testdescription;
[...]
// Other properties and fields
[...]
@ManyToMany(fetch = FetchType.LAZY
)
@JoinTable(name = "test_checks_requisite",
joinColumns = @JoinColumn(name = "test_idtest"),
inverseJoinColumns = @JoinColumn(name = "requisite_idrequisite")
)
@JsonProperty(access=Access.READ_ONLY)
private Set<Requisite> requisites = new HashSet<Requisite>();
[...]
@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="idrequisite")
public class Requisite {
@Id
@Column(name="idrequisite")
private long idrequisite;
private String Name;
private String Title;
private String Description;
@ManyToOne(cascade = {CascadeType.PERSIST}, fetch=FetchType.LAZY)
@JoinColumn(name="functionality_idfunctionality")
@JsonProperty(access=Access.WRITE_ONLY)
private Functionality functionality;
@ManyToMany(mappedBy="requisites")
private Set<Pectest> tests = new HashSet<Pectest>();
这是由GET映射返回的JSON片段,该映射返回所有测试。可以看出,第一个 test 对象(具有 idtest 9的对象)在必要条件<下具有5个必要条件对象的集合。 / strong>属性。相反,第二个 test (ID为10)仅显示前一个对象中不存在的完整 Requirement 对象,仅显示ID的值在其他人中:
[
{
"idtest": 9,
"testtype": {
"idTestType": 5,
"testTypeName": "Manual"
},
"datatype": null,
"requisites": [
{
"idrequisite": 7,
"name": "REQ-0006",
"description": "Campo para traducción de nombres, debe mostrar el nombre en el idioma seleccionado por el cliente.",
"title": "DisplayName"
},
{
"idrequisite": 4,
"name": "REQ-0003",
"description": "Se ofrece acceso a parámetros a través de este tipo de nodo",
"title": "Parameter Type"
},
{
"idrequisite": 5,
"name": "REQ-0004",
"description": "El BrowseName de las variables debe ser sólo el último campo de las variables exportadas por FW de BR (ItemName)",
"title": "BrowseName"
},
{
"idrequisite": 3,
"name": "REQ-0002",
"description": "Se ofrece acceso a variables analógicas a través de este tipo de nodo",
"title": "Analog Type"
},
{
"idrequisite": 2,
"name": "REQ-0001",
"description": "Se ofrece acceso a variables digitales a través de este tipo de nodo",
"title": "Digital Type"
}
],
"testDescription": "El servidor es capaz de devolver correctamente todos los tipos de dato.",
"lastUpdated": null,
"testName": "Lectura de DataTypes",
"dateCreated": null,
"testURL": ""
},
{
"idtest": 10,
"testtype": {
"idTestType": 5,
"testTypeName": "Manual"
},
"datatype": {
"idDataType": 2,
"dataTypeName": "Boolean"
},
"requisites": [
7,
5,
{
"idrequisite": 10,
"name": "REQ-0009",
"description": "Se generan a partir de los niveles de acceso de la variable. Se deben escalar los valores, de 256 a 1000.",
"title": "AccessLevel & UserAccessLevel"
},
2
],
"testDescription": "El servidor es capaz de admitir escrituras correctamente de todos los tipos de dato.",
"lastUpdated": null,
"testName": "Escritura de DataTypes",
"dateCreated": null,
"testURL": ""
}
...
]
下面是通过其ID调用单个对象的GET方法的结果(在本例中是ID为10的对象,在先前的JSON中不正确):
{
"idtest": 10,
"testtype": {
"idTestType": 5,
"testTypeName": "Manual"
},
"datatype": {
"idDataType": 2,
"dataTypeName": "Boolean"
},
"requisites": [
{
"idrequisite": 7,
"name": "REQ-0006",
"description": "Campo para traducción de nombres, debe mostrar el nombre en el idioma seleccionado por el cliente.",
"title": "DisplayName"
},
{
"idrequisite": 2,
"name": "REQ-0001",
"description": "Se ofrece acceso a variables digitales a través de este tipo de nodo",
"title": "Digital Type"
},
{
"idrequisite": 5,
"name": "REQ-0004",
"description": "El BrowseName de las variables debe ser sólo el último campo de las variables exportadas por FW de BR (ItemName)",
"title": "BrowseName"
},
{
"idrequisite": 10,
"name": "REQ-0009",
"description": "Se generan a partir de los niveles de acceso de la variable. Se deben escalar los valores, de 256 a 1000.",
"title": "AccessLevel & UserAccessLevel"
}
],
"testDescription": "El servidor es capaz de admitir escrituras correctamente de todos los tipos de dato.",
"lastUpdated": null,
"testName": "Escritura de DataTypes",
"dateCreated": null,
"testURL": ""
}
我观察到以下行为:
由于这两点,我认为这似乎是一些缓存问题(我没有启用二级缓存或查询级缓存)。我的意思是,hibernate似乎仅是第一次从数据库中检索给定的条件,而其余的则检测到已请求了具有该ID的条件,并且没有启动查询。当然,这很好,但是如何在随后具有必要条件关联的 test 对象中将缓存的对象包含在结果中?
编辑:好的,我将其发布为答案,因为我在原始帖子中描述的问题似乎消失了。就像我在原始帖子的评论中说的那样,我删除了Requisite类上的@JsonIdentityInfo批注。我使用它来避免由于模型类之间的@ManyToMany关系而导致的无限递归。
但是,我不认为这是一种解决方案,并且绝对不了解@JsonIdentityInfo的工作原理。我会阅读该文档,但是如果有人可以提供一个解释,我将不胜感激。