2017-02-10 170 views
3

我有这样的JPA库:为什么JpaRepository没有更新我的实体?

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)更新的记录,价值似乎被更新,但在数据库中的值不会改变。

+0

是否真的在数据库中没有更新?合并操作不会更新您传递的实体,但会返回一个新的实体 – Deltharis

+0

真的,数据库表中没有更新...(我用'spring.jpa.show-sql = true'写出查询) – Artegon

+0

您是否尝试过做一个实体Mananger。更新后刷新()? JPA缓存数据库请求并稍后刷新它们(在事务结束后)......只要您在单个节点/应用程序上使用jpa,那么这是没有问题的...... – Anton

回答

0

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

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

+1

EntityManager.persist(会在第一次保存时调用)会更新传递给它的对象 - 所以'bal'确实有生成的id。 – Deltharis

+0

@昆顿 - 它击败所有优点.... – Artegon

+0

是啊......我没有想到这一点。我的错。 8- { 我通常使用Spring Boot的CrudRepository ...所以我的JPA Repository有点生疏......忽略我的答案。 8-} –

0

尝试重写代码这样的方式:

@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); 

    } 

} 

并告诉我,它帮助与否。

+1

从@ javax或Spring的'@ Transactional'? – Artegon

+0

Spring,off course – rvit34

+0

这不会有什么区别... Spring使用代理和内部方法调用不通过代理。因此'@ Transactional'在这里基本上被忽略了。 –

0

这部分看起来怪我:

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; 
} 
相关问题