如果我要在DB中插入或更新一些实例,例如:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@EqualsAndHashCode
@Table(name="user_purchases")
public class UserPurchase implements Serializable, Persistable<String> {
@Id
@Column(name="id")
@NotNull
private String id; // an UUID
@Column(name="user_id")
@NotNull
private String userId; // in user_info: "sub"
/**
* Seconds since epoch: when the last purchase happened.
*/
@Column(name="last_date")
private Date lastBuyDate;
@Transient
private boolean isNewObject;
// Add UUID before persisting
@PrePersist
public void prepareForInsert() {
this.id = UUID.randomUUID().toString();
}
@Override
public boolean isNew() {
return isNewObject;
}
// This part for Persistable is not required, because getId(), by accident,
// is the getter for the "id" field and returns a String.
//@Override
//public getId() {
// return id;
//}
}
id
是代理项id,将在持久化之前生成。以及
userId
在数据库中是唯一的。
了解更多有关接口的信息
Persistable<ID>
this answer
.
现在,当我们有一个没有id的实例时
用户ID
无法在数据库中复制,也无法判断是否在数据库中持久化或更新。
我想在扫描之前保存一个完整的表
坚持/更新,所以我试图抓住
DateIntegrationViolationException
repository.save(entity)
.
@Transactional(rollbackFor = DataIntegrityViolationException.class)
public UserPurchase saveUserPurchase(UserPurchase purchase) throws RuntimeException {
UserPurchase saved = null;
try {
saved = repository.saveAndFlush(purchase);
log.debug("UserPurchase was saved/updated with id {}, last buy time: {}", saved.getId(),
DateTimeUtil.formatDateWithMilliPart(saved.getLastBuyDate(), false));
} catch (DataIntegrityViolationException e) {
log.info("Cannot save due to duplication. Rolling back..."); // we don't distinguish userId and id duplication here.
UserPurchase oldPurchase = repository.findByUserId(purchase.getUserId()); // <--------- here we cannot proceed
if (oldPurchase != null) {
purchase.setId(oldPurchase.getId()); // set the existent ID to do updating
purchase.setNewObject(false); // for Persistable<String>
saved = repository.saveAndFlush(purchase); // now should be updating
} else {
log.error("Cannot find ID by user id");
}
}
return saved;
}
这给了我一个错误:
ERROR: current transaction is aborted, commands ignored until end of transaction
@Transactional(rollbackFor = DataIntegrityViolationException.class)
public UserPurchase saveUserPurchase(UserPurchase purchase) throws RuntimeException {
UserPurchase saved = null;
try {
saved = repository.saveAndFlush(purchase);
log.debug("UserPurchase was saved/updated with id {}, last buy time: {}", saved.getId(),
DateTimeUtil.formatDateWithMilliPart(saved.getLastBuyDate(), false));
} catch (DataIntegrityViolationException e) {
log.info("Cannot save due to duplication. Rolling back..."); // we don't distinguish userId and id duplication here.
throw e; // or throw new RuntimeException(e); is the same
}
return saved;
}
在我呼叫的地方
save()
try {
userPurchaseService.saveUserPurchase(purchase);
} catch (DataIntegrityViolationException e) {
log.info("Transaction rolled back, updating...");
// ... 1. select 2. getId() 3.setId() and save again
}
但是,它又失败了。
现在,根据Spring数据,我们没有
EntityManager
rollback()
.
现在该怎么办?我必须做一本手册吗
findByUserId()
每次插入/更新之前?我的懒惰选择方法在任何情况下都行不通?