[英]Spring JPA - Stackoverflow exception on updating Owning end of OnetoOne relation
我有两个对象之间one-to-one
映射。
UserDO.java:
public class UserDO {
@Id
@GeneratedValue
private Long id;
@Column(nullable = false)
@NotNull(message = "Username can not be null!")
private String username;
@Column(nullable = false)
@NotNull(message = "Password can not be null!")
private String password;
@Column(nullable = false)
private Boolean deleted = false;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private OnlineStatus onlineStatus;
@Column(nullable = false)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private ZonedDateTime dateCreated = ZonedDateTime.now();
@OneToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private CardDO card;
}
CardDO.java:
public class CardDO {
@Id
@GeneratedValue
@Column(name="id")
private Long id;
@Column(nullable = false)
private Long pan;
@Column(nullable = false)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private LocalDate expirationDate;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private CardType cardType;
@Column(nullable = false)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private ZonedDateTime dateCreated = ZonedDateTime.now();
@OneToOne(mappedBy="card")
private UserDO user;
}
现在,当我第一次将两者链接起来并将用户对象保存在回购中时,它可以正常工作,但是每次当我尝试更新用户对象时,它都会引发StackOverFlow异常。
用于链接两个对象的代码:
userDO.setCard(cardDO);
userRepository.save(userDO);
更新代码:
UserDO userDO = findUser(userId);
userDO.setOnlineStatus(onlineStatus);
userRepository.save(userDO);
有什么事吗
您需要设置关系的拥有站点:
public class CardDO {
//skipped
@OneToOne(mappedBy="card", insertable = false, updateable = false)
private UserDO user;
}
和
@OneToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = card_id)
private CardDO card;
休眠检查机制发现CardDO
已更新,因此想更新User
。 然后是Card
,然后是User
等。
我可以在注释中进行一些小的更改来运行您的代码,如下所示
UserDO.java
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.validation.constraints.NotNull;
import com.fasterxml.jackson.annotation.JsonManagedReference;
@Entity
public class UserDO {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
@NotNull(message = "Username can not be null!")
private String username;
@Column(nullable = false)
@NotNull(message = "Password can not be null!")
private String password;
@Column(nullable = false)
private Boolean deleted = false;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private OnlineStatus onlineStatus;
@Column(nullable = false)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private ZonedDateTime dateCreated = ZonedDateTime.now();
@JsonManagedReference
@OneToOne(cascade = CascadeType.ALL)
private CardDO card;
}
CardDO.java
import java.time.LocalDate;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonBackReference;
@Entity
public class CardDO {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
private Long pan;
@Column(nullable = false)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private LocalDate expirationDate;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private CardType cardType;
@Column(nullable = false)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private ZonedDateTime dateCreated = ZonedDateTime.now();
@JsonBackReference
@OneToOne
private UserDO user;
}
如果使用以下代码保存数据,则无法将userId
保存在cartdo
实体中
userDO.setCard(cardDO);
userRepository.save(userDO);
如果要将userId
也保存在cartdo
实体中,则必须通过postman
其余api,并在api中发送数据,如下所示
{
"username":"vishal",
"password":"123456",
"onlineStatus":"OFFLINE",
"cardDO" :{
"cardType":"NEW",
"pan":"2"
}
}
我没有发送值datecreated
和expirationdate
因为我从实体中删除了这些字段以便于观察问题。 通过邮递员存储数据后,您可以检查database
中的carddo
表是否存在user_id
,但不为null。
当您要进行更新时,请先使用CrudRepository
findOne
方法进行CrudRepository
,然后像下面的代码那样进行保存。 在这段代码中我还可以更新cardType
是从属于CardDO.java
实体
UserDO userDO = repository.findOne(userId);
CardDO card = userDO.getCard();
card.setCardType(CardType.OLD);
userDO.setOnlineStatus(OnlineStatus.ONLINE);
userDO.setCard(card);
repository.save(userDO);
之所以会出现stackoverflow异常,是因为在UserDO
和CardDO
中都声明了@OneToOne
映射。 所以当你exceute方法类似findOne()
userRepository的,它会给你UserDO
对象,但这个对象@oneToOne
映射CardDo
这样的对象CardDo
将从数据库在同一时间被读取。 由于您的CardDo
对象具有与UserDO
@OneToOne
映射,因此会发生同样的事情,即从数据库中获取UserDo
对象。 这将造成无限循环并导致stackoverflow exception
。
我建议在您的CardDo
实体中使用以下代码:
private Long userId;
而不是执行@oneToOne
映射:
@OneToOne(mappedBy="card")
private UserDO user;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.