我无法理解将实体保存到数据库时出错的原因。我想澄清一下,有时实体会被保存。
我有两个实体:
@Data
@Entity
@Table(...)
public class RuleCollection {
// Fields
}
@Data
@Entity
@Table(...)
public class RuleAttribute {
// Fields
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "rule_collection_id", nullable = false)
private RuleCollection ruleCollection;
}
Rule属性必须包含RuleCollection。
首先,在处理JSON文件期间,保存"RuleCollection"对象:
Map<UUID, RuleCollection> ruleCollectionsMap =
json.getRuleCollections().stream().map(ruleCollectionDto -> {
RuleCollection ruleCollection = new RuleCollection();
// Set ruleCollection fields
return ruleCollectionRepository.save(ruleCollection);
}
).collect(Collectors.toMap(RuleCollection::getId, Function.identity()));
之后,填充并保存“规则属性”:
List<RuleAttribute> attributes = json.getAttributes().stream()
.filter(attr -> ruleCollectionsMap.get(attr.getCollectionId()) != null)
.parallel()
.map(attr -> {
RuleAttribute ruleAttribute = new RuleAttribute();
// Set ruleAttribute fields
ruleAttribute.setRuleCollection(ruleCollectionsMap.get(attr.getCollectionId()));
return ruleAttribute;
}
).collect(Collectors.toList());
ruleAttributeRepository.save(attributes);
然后可能会出现错误:
无法初始化代理-无会话;嵌套异常是org. hibernate.LazyFirst alizationException:无法初始化代理-无会话
如果我在流中保存属性,错误会发生变化:
.map(attr -> {
...
return ruleAttributeRepository.save(ruleAttribute);
}
).collect(Collectors.toList());
org. hibernate.TranentProperty tyValueException:非空属性引用一个瞬态值-必须在当前操作之前保存瞬态实例:RuleProperties.ruleCollection-
我不知道可能是什么问题,因为“规则收集”已经保存了。
我尝试更改类“RuleAt在StackOverflow上有类似问题的帖子中提到:
@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "rule_collection_id", nullable = false)
private RuleCollection ruleCollection;
错误发生在相同的数据上。有一次,我可以不出错地保存数据,从数据库中删除它,当我再次保存它时得到这个错误。
UPD:
RuleCollection Repository和RuleAtbanteRepository扩展org.springframework.data. reposity.CrudRepository
保存和处理在具有@Transactional
属性的方法中。
显然,在这种情况下,并行流违反了Hibernate会话:Java。
在搜索了类似的问题后,我找到了几个解决方案:
>
将属性@Transactional中的参数传播设置为传播。REQUIRES_NEW。但是,此选项不可靠,因为由于主会话不知道子会话的状态,它可能导致数据丢失或类似问题。
不要使用并行流。
如果无法拒绝并行流,则需要去掉@Transactional
属性,先设置必要的数据,然后在标有@Transactional
属性的单独方法中进行顺序保存。例如:
public void saveData(Json json) {
Map<UUID, RuleCollection> ruleCollectionsMap = // Set data
List<RuleAttribute> attributes = // Set data
saveInDB(ruleCollectionsMap.values(), attributes);
}
@Transactional
private void saveInDB(Collection<RuleCollection> ruleCollections, Collection<RuleAttribute> attributes) {
ruleCollectionRepository.save(ruleCollections);
ruleAttributeRepository.save(attributes);
}