代码之家  ›  专栏  ›  技术社区  ›  WesternGun

Spring data-“错误:当前事务被中止”:捕获DataIntegrityViolationException时如何回滚/提交事务?

  •  0
  • WesternGun  · 技术社区  · 7 年前

    如果我要在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() 每次插入/更新之前?我的懒惰选择方法在任何情况下都行不通?

    0 回复  |  直到 7 年前