【问题标题】:Why doesn't JpaRepository update my entity?为什么 JpaRepository 不更新我的实体?
【发布时间】:2017-06-28 20:44:07
【问题描述】:

我有这样的 Jpa 存储库:

public interface BalanceRepository extends JpaRepository<Balance, Long> {

}

据我所知(并且这个answer 确认)实体管理器插入新记录(当实体是新的时)并在不是新的时更新实体记录。

我的实体类层次结构:

@Entity
@Table(name = "balances")
public class Balance extends BaseEntity {
// omitted 
}

和BaseEntity

    @MappedSuperclass
    @EntityListeners(AuditingEntityListener.class)
    @JsonIgnoreProperties({"handler", "hibernateLazyInitializer"})
    public abstract class BaseEntity {

        private static Logger LOGGER = LogManager.getLogger(BaseEntity.class);

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id", updatable = false, nullable = false)
        @JsonProperty("id")
        private Long id;

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
               this.id = id;
            }

    public boolean isNew() {
            return id == null;
        }

 }

当我保存新的Balance 实体时,插入了新记录但没有完成更新,为什么?

Balance bal = new Balance();
        bal.setFinalBalance(BigDecimal.TEN);
        bal.setUser(user);
        bal.setRecordDate(date);
        bal.setMinusBalance(BigDecimal.TEN);
        bal.setPlusBalance(BigDecimal.TEN);
        bal.setTotalBalance(BigDecimal.TEN);

        // entity is inserted
        balanceRepository.save(bal);

        // no update...
        bal.setFinalBalance(bal.getFinalBalance().add(BigDecimal.TEN));
        balanceRepository.save(bal);

更新1 - 当我findOne(Long id)更新记录时,值似乎更新了,但数据库中的值没有改变。

【问题讨论】:

  • 数据库真的没有更新吗?合并操作不会更新你传递的实体,而是会返回一个新的
  • 真的,数据库表没有更新...(我用spring.jpa.show-sql=true写出查询)
  • 您是否尝试在更新后执行 entityMananger.flush()? JPA 缓存数据库请求并稍后(在事务结束后)刷新它们...只要您在单个节点/应用程序上使用 jpa 就没有问题...
  • 不,我没有。真的需要吗?我认为它应该自动工作。
  • 您很可能缺少@Transactional 注释

标签: java spring-data-jpa


【解决方案1】:

尝试设置“bal = balanceRepository.save(bal);” ...这将返回保存的对象并包含生成的 id ...当您运行下一次保存时,它会知道它是现有对象,然后将执行更新而不是保存。

如果这不起作用,请创建一个 newBalance 对象,在第一次保存时设置它,并将其用于第二次保存和 setFinalBalance 调用。

【讨论】:

  • EntityManager.persist(将在第一次保存时被调用)确实会更新您传递给它的对象 - 所以 bal 确实有生成的 id。
  • 是的……我没想到。我的错。 8-{ 我通常使用 Spring Boot 中的 CrudRepository ...所以我的 JPA Repository 有点生疏...忽略我的回答。 8-}
【解决方案2】:

尝试这样重写你的代码:

@Service
public class BalanceService {
  // ...
  @Transactional
  public void save(Balance balance){
     balanceRepository.save(balance);  
  }

  public void check(){
     Balance bal = new Balance();
    bal.setFinalBalance(BigDecimal.TEN);
    bal.setUser(user);
    bal.setRecordDate(date);
    bal.setMinusBalance(BigDecimal.TEN);
    bal.setPlusBalance(BigDecimal.TEN);
    bal.setTotalBalance(BigDecimal.TEN);
    // entity is inserted
    save(bal);

    bal.setFinalBalance(bal.getFinalBalance().add(BigDecimal.TEN));
    save(bal);

  }

}

告诉我它有没有帮助。

【讨论】:

  • @Transactional 来自 javax 还是来自 Spring?
  • 这不会有任何区别...... Spring使用代理并且内部方法调用不通过代理。因此@Transactional在这里基本上被忽略了。
  • 对不起@rvit34,没有变化。我被卡住了。
【解决方案3】:

嘿

这部分在我看来很奇怪:

public boolean isNew() {
    return id == null;
}

因为这个函数被Persistable接口覆盖,是默认实现。在这里阅读:https://docs.spring.io/spring-data/jpa/docs/1.4.1.RELEASE/reference/html/jpa.repositories.html#jpa.entity-persistence.saving-entites

您可以通过在Entity 中实现Persistable 接口来覆盖此函数。我需要这样做,因为我使用了一个未生成的表 id 作为 PK。

您是否尝试在@DataJpaTest 期间保存数据?因为这可能会导致打开事务并且不会保存到数据库中。

balanceRepository.save(bal); 的返回值是否与bal 相同?如果没有,您可以尝试添加 @Version 注释。我读到这有时可能会有所帮助。 你也可以尝试实现Persistable接口,添加@Version注解,这样使用:

@Version
private Long version;

@Override
public Long getId() {
    return id;
}

@Override
public boolean isNew() {
    return version == null;
}

【讨论】:

    猜你喜欢
    • 2019-11-15
    • 2017-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-24
    • 2020-03-11
    • 1970-01-01
    相关资源
    最近更新 更多