什么时候hibernate会更新相关的实体?

时间:2018-03-19 22:16:19

标签: java database hibernate spring-data-jpa hibernate-onetomany

我正在使用spring数据JPA并拥有PlayerScore个实体。 Player@OneToManyScore@ManyToOneScore)有Player个关系。我将Player保存到数据库而未指定相关分数。之后,我将Score保存到数据库,向构造函数传递一个指向Player的链接。然后在同一个函数中,我读了Player条目,但它还没有指向Score条目的链接。
我的FetchType.LAZY关系中有OneToMany,因此我需要在该函数中使用注释@Transactional。我还尝试在内部事务中保存玩家和得分(使用propogation=Propogation.REQUIRES_NEW)并在外部事务中读取玩家条目,但它没有帮助。我还尝试添加CascadeType.ALL - 没有效果。我使用flush()中的JpaRepository方法 - 也没有帮助 但是如果我将在一个控制器方法中保存玩家和得分(使用弹簧MVC),并在另一个控制器方法中读取,则玩家将获得分数的链接。
已修改:添加代码,代码中的得分为 GamePlayerScore 。所有课程都有lombok注释@Getter@ToString

播放器

@Temporal(TemporalType.DATE)
@NonNull
@Column(updatable = false)
private Date createdAt;

@Setter
@NonNull
@Column(unique = true)
private String nickname;

@OneToMany(mappedBy = "winner", cascade = CascadeType.REFRESH)
private Set<GameStatistic> gamesWon;

@OneToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH}, optional = false)
@JoinColumn
private PlayerStatistic stat;

@OneToMany(mappedBy = "player", cascade = CascadeType.REFRESH)
private Set<GamePlayerScore> scores;

@ManyToOne
@JoinColumn
private Game currentGame;

public Player(String nickname, Date createdAt) {
    this.nickname = nickname;
    this.createdAt = createdAt;
    stat = new PlayerStatistic(0, 0, 0, this);
}

GamePlayerScore

@ManyToOne(optional = false)
@JoinColumn
@NonNull
@JsonIgnore
private GameStatistic game;

@ManyToOne(optional = false)
@JoinColumn
@NonNull
@JsonIgnore
private Player player;

@NonNull
private Integer score;


@PrePersist
private void updatePlayerStat() {
    player.getStat().incrementTotalGames();
    player.getStat().addTotalScore(score);
}

GameStatistic

@Column(updatable = false)
@NonNull
private Integer durationMinutes;

@Temporal(TemporalType.TIMESTAMP)
@NonNull
private Date startedAt;

@ManyToOne(optional = false)
@JoinColumn
@NonNull
@JsonIgnore
private Player winner;


@OneToMany(mappedBy = "game")
private Set<GamePlayerScore> scores;

@PrePersist
private void update() {
    winner.getStat().incrementTotalWins();
}

以及我如何存储条目

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void prepossess() {
    Date date = new Date();

    Player john = new Player("john", date);
    GameStatistic game = new GameStatistic(35, new Date(), john);
    GamePlayerScore johnScore = new GamePlayerScore(game, john, 100);
    playerRepository.save(player);
    gameRepository.save(game);
    scoreRepository.save(johnScore);
}

以及我如何阅读条目

@Transactional
public void insertAndRead() {
    preprocess();
    Player player = playerRepository.findByNickname("john");
    System.out.println(player.getScores());
}

1 个答案:

答案 0 :(得分:1)

一旦刷新了这些更改,保存得分应更新与数据库中玩家的关系。

但是,使用已包含Player的会话重新加载Player将调出旧的Player实例,而不会使用数据库中的数据进行更新。

因此,为了查看已更改的Player,您需要刷新会话并从会话中删除Player,然后重新加载它。或者,您可以关闭会话。

您似乎尝试通过单独的事务方法实现此目的。 这应该原则上有效,但我几乎100%肯定,你有一个跨越save和load方法运行的事务。 您可以启用交易日志记录,以便进一步调查:Spring hibernate Transaction Logging

你真正想要做的是通过编写自定义setter来保持两个java对象同步。