@Transactional 块末尾抛出的唯一约束错误

Unique Constraint error thrown at the end of @Transactional block

假设我有一个用户class:

@Entity
@Data
@Builder
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long userKey;

    @Column(unique = true)
    String someId;

    String name;
}

以及对应的服务

@Component
@Slf4j
public class UserService {

    @Autowired
    UserRepository repository;

    @Transactional
    public User createUserWithId(String name, String id) {
        User userToAdd = User.builder()
                .name(name)
                .someId(id)
                .build();
        repository.save(userToAdd);
        log.info("No issue in saving");
        //some more code
        return userToAdd;
    }

}

如您所见,我对 User class 中的 someId 字段有一个唯一约束,但是当我执行方法 createUserWithId 时,someId 中的值已经存在于数据库中,我希望得到包含 repository.save() 及其后的代码不被执行的行中的错误。但是在它被执行之后的代码,我在事务块的末尾遇到了一个异常。我的问题是为什么会发生这种情况以及在与存储库对象交互时我通常会遇到哪些异常(如本例 repository.save )以及在事务块结束时我会遇到哪种类型的异常?

PS 我从一个简单的控制器内部调用 UserService,我创建了一个空的 UserRepository,它只是扩展了 CrudRepository。为简洁起见,我在问题中遗漏了这两个问题,但如果将它们添加到此处是否有意义,请告诉我。

编辑 1:根据评论中的请求添加用户存储库

@Repository
public interface UserRepository extends CrudRepository<User, Long> {
}

复制时出现唯一错误。 spring 有数据库错误帮助程序 class,您可以在由 @transactional 传递给控制器​​的控制器层上捕获数据库异常。

  } catch (DataAccessException ex) {

 } catch (DataIntegrityViolationException ex) {

如果数据库连接器支持标准异常抛出。

就你而言,我认为你错过了

@Transactional(readOnly = false)

错误发生在拦截器中,因为就在提交事务之前,Hibernate 需要刷新对数据库的未决更改。在刷新期间,发生数据库异常。您可以通过在存储库上调用 saveAndFlush 来手动刷新。

当我们打电话时

repository.save(obj); 

hibernate 将这个实体保存在内存中,实体将在事务中的方法中持久化。

执行此类操作的另一种方法,首先您应该尝试获取 id

上的结果
repository.findById(id)

并检查是否为null并据此进行保存操作。