调用页面大小大于 36 的 Spring Data MongoDB 存储库方法时发生 StackOverflowError
StackOverflowError when calling Spring Data MongoDB repository method with a page size bigger than 36
我在调用 MongoDB 存储库接口的方法时收到 WhosebugError:
public interface TermRepository extends MongoRepository<Term, String>, QuerydslPredicateExecutor<Term> {
// [...]
@Query("{$or:[{'apis' : {$in : ?0 } }, {$text:{$search:?1}}]}")
Page<Term> globalSearch(List<DBRef> apis, String searchKeyword, Pageable pageable);
}
apis
是一个只有一个 DBRef 的列表: new DBRef("api", new ObjectId("5e3ad9faaafa595898b6a682"))
searchKeyword
等于 "accounts"
pageable
是 Page request [number: 0, size 37, sort: UNSORTED]
。如果 size
是 36,它不会抛出 WhosebugError!
- 查询被翻译成
{
$or: [{
'apis': {
$in: [{
'$ref': 'api',
'$id': ObjectId('5e3ad9faaafa595898b6a682')
}]
}
}, {
$text: {
$search: 'account'
}
}]
}
- 如果我直接在 mongo 中执行查询,它 return 有 55 个元素。
- 我已经尝试将线程堆栈增加到 -Xss1G(我知道它很多),它只是一直缓慢地填充堆栈而不会 return。如果我重新运行页面大小为 36 的测试,它会立即 returns。
有人知道发生了什么事吗?
学期:
public class Term {
@Id
private String id;
@NotBlank
@TextIndexed
@JsonProperty
private String name;
@NotBlank
@TextIndexed
@JsonProperty
private String objectType;
@Transient
@JsonProperty
private String snakeCase;
@NotEmpty
@JsonProperty
private List<String> functionalCategories;
@NotNull
@JsonProperty
private TermTypeEnum termType;
@NotEmpty
@JsonProperty
private Map<String, String> description;
@Setter
@NotNull
@JsonProperty
private TermStateEnum state;
@NotBlank
@TextIndexed
@JsonProperty
private String example;
@DBRef
@NotNull
@Indexed
@JsonProperty
private List<Api> apis;
@DBRef
@NotNull
@JsonProperty
private User contributor;
@NotBlank
@TextIndexed
@JsonProperty
private String version;
@DBRef
@JsonProperty
private Map<String, Term> attributes;
}
堆栈跟踪:https://pastebin.com/y0XYt7p6
尽管可能存在循环引用,因为 Term 具有属性 Map,但我认为产生堆栈溢出的不是循环引用。
做一些调试,我看到发生堆栈溢出,因为最后spring-data 只实例化这个 Term(不是其他的,所以我没有看到循环引用):
Term(id=5e3ad9faaafa595898b6a7ea, name=debitCurrency, objectType=string, snakeCase=debit_currency, functionalCategories=null, termType=BODY, description={"english"=Debit Currency.}, state=PROPOSED, example=null, apis=[Api(id=5e3ad9faaafa595898b6a67f, name=Payments-1.0.1, description=null, responsible=null)], contributor=null, version=null, attributes=null)
这又不引用其他术语。
这是另一个Term,只是为了比较:
Term(id=5e3ad9faaafa595898b6a6c8, name=displayCardNumber, objectType=string, snakeCase=display_card_number, functionalCategories=null, termType=BODY, description={"english"=Related card number to the account.}, state=PROPOSED, example=null, apis=[Api(id=5e3ad9faaafa595898b6a682, name=Accounts-1.0.2, description=null, responsible=null)], contributor=null, version=null, attributes=null)
我看不出有什么区别,但是 debitCurrency
会产生堆栈溢出而 displayCardNumber
不会。
我确实有一个循环引用(更准确地说是自我引用)。
我想出了一个解决方法,包括制作 @DBRef
属性 lazy=true
,并实现 class Term
的自定义序列化程序,至极具有自引用(或循环引用)。实现自定义序列化程序的原因是,我可以保存一组已经序列化的对象,如果我必须再次序列化一个对象,我只是不这样做。
我在调用 MongoDB 存储库接口的方法时收到 WhosebugError:
public interface TermRepository extends MongoRepository<Term, String>, QuerydslPredicateExecutor<Term> {
// [...]
@Query("{$or:[{'apis' : {$in : ?0 } }, {$text:{$search:?1}}]}")
Page<Term> globalSearch(List<DBRef> apis, String searchKeyword, Pageable pageable);
}
apis
是一个只有一个 DBRef 的列表: new DBRef("api", new ObjectId("5e3ad9faaafa595898b6a682"))searchKeyword
等于 "accounts"pageable
是Page request [number: 0, size 37, sort: UNSORTED]
。如果size
是 36,它不会抛出 WhosebugError!- 查询被翻译成
{
$or: [{
'apis': {
$in: [{
'$ref': 'api',
'$id': ObjectId('5e3ad9faaafa595898b6a682')
}]
}
}, {
$text: {
$search: 'account'
}
}]
}
- 如果我直接在 mongo 中执行查询,它 return 有 55 个元素。
- 我已经尝试将线程堆栈增加到 -Xss1G(我知道它很多),它只是一直缓慢地填充堆栈而不会 return。如果我重新运行页面大小为 36 的测试,它会立即 returns。
有人知道发生了什么事吗?
学期:
public class Term {
@Id
private String id;
@NotBlank
@TextIndexed
@JsonProperty
private String name;
@NotBlank
@TextIndexed
@JsonProperty
private String objectType;
@Transient
@JsonProperty
private String snakeCase;
@NotEmpty
@JsonProperty
private List<String> functionalCategories;
@NotNull
@JsonProperty
private TermTypeEnum termType;
@NotEmpty
@JsonProperty
private Map<String, String> description;
@Setter
@NotNull
@JsonProperty
private TermStateEnum state;
@NotBlank
@TextIndexed
@JsonProperty
private String example;
@DBRef
@NotNull
@Indexed
@JsonProperty
private List<Api> apis;
@DBRef
@NotNull
@JsonProperty
private User contributor;
@NotBlank
@TextIndexed
@JsonProperty
private String version;
@DBRef
@JsonProperty
private Map<String, Term> attributes;
}
堆栈跟踪:https://pastebin.com/y0XYt7p6
尽管可能存在循环引用,因为 Term 具有属性 Map
做一些调试,我看到发生堆栈溢出,因为最后spring-data 只实例化这个 Term(不是其他的,所以我没有看到循环引用):
Term(id=5e3ad9faaafa595898b6a7ea, name=debitCurrency, objectType=string, snakeCase=debit_currency, functionalCategories=null, termType=BODY, description={"english"=Debit Currency.}, state=PROPOSED, example=null, apis=[Api(id=5e3ad9faaafa595898b6a67f, name=Payments-1.0.1, description=null, responsible=null)], contributor=null, version=null, attributes=null)
这又不引用其他术语。
这是另一个Term,只是为了比较:
Term(id=5e3ad9faaafa595898b6a6c8, name=displayCardNumber, objectType=string, snakeCase=display_card_number, functionalCategories=null, termType=BODY, description={"english"=Related card number to the account.}, state=PROPOSED, example=null, apis=[Api(id=5e3ad9faaafa595898b6a682, name=Accounts-1.0.2, description=null, responsible=null)], contributor=null, version=null, attributes=null)
我看不出有什么区别,但是 debitCurrency
会产生堆栈溢出而 displayCardNumber
不会。
我确实有一个循环引用(更准确地说是自我引用)。
我想出了一个解决方法,包括制作 @DBRef
属性 lazy=true
,并实现 class Term
的自定义序列化程序,至极具有自引用(或循环引用)。实现自定义序列化程序的原因是,我可以保存一组已经序列化的对象,如果我必须再次序列化一个对象,我只是不这样做。