Quarkus Hibernate Reactive 未捕获 onFailure() 块中的 ConstraintViolationException

问题描述 投票:0回答:1

我正在使用 Hibernate Reactive 和 PostgreSQL 开发 Quarkus 项目。我有一种方法可以在数据库中保留新用户,并且我想处理由于电子邮件字段的唯一约束而导致重复用户(同一电子邮件)导致 ConstraintViolationException 的情况。

我使用 .onFailure() 设置了一个错误处理块来捕获此异常并抛出自定义 UserAlreadyExistsException。但是,异常并未在故障块中被捕获,相反,我在日志中看到了未捕获的 ConstraintViolationException。

@POST
    @Path("/register")
    @WithTransaction
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Uni<Response> registerUser(@Valid Auth authRequest) {
        return authService.createUser(authRequest)
                .onItem().transform(success -> Response.status(Response.Status.CREATED)
                        .entity(success).build())
                .onFailure()
                .recoverWithItem(ex -> {
                    log.error("Unable to create User, email: {}, Exception: {}", authRequest.getEmail(), ex.getMessage(), ex);
                    ErrorResponse errorResponse = new ErrorResponse(ex.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
                    return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorResponse).build();
                });
    }

public Uni<Auth> createUser(Auth authRequest) {
        User user = new User(authRequest);
        String passwordHash = Password.hash(authRequest.getPassword()).withArgon2().getResult();
        user.setPasswordHash(passwordHash);
        return PanacheEntityBase.persist(user).onItem().transform(success -> {
            log.info("Successfully created user, email: {}", authRequest.getEmail());
            return authRequest;
        })
        .onFailure().invoke(ex -> {
            log.error("Unable to create User, email: {}, Exception: {}",
                    authRequest.getEmail(), ex.getMessage(), ex);
            throw new RegistrationFailedException(Errors.UNABLE_TO_REGISTER_USER + ex.getMessage());
        });
    }

我的期望:

当尝试插入具有现有电子邮件(重复键)的用户时,ConstraintViolationException 应由 onFailure() 块捕获,并应抛出自定义 UserAlreadyExistsException。

发生了什么:

返回以下错误,而不是被 onFailure() 块捕获:

org.hibernate.exception.ConstraintViolationException: error executing SQL statement
[ERROR: duplicate key value violates unique constraint "user_email_key" (23505)]

故障处理程序似乎没有捕获异常,并且我得到了未捕获的异常响应。

quarkus quarkus-panache quarkus-reactive
1个回答
0
投票

调用

.persist
告诉 Hibernate 该对象需要保存在数据库中,但它并没有告诉何时实际应该发生插入查询。

在您的用例中,查询在事务提交时执行。 由于您已在 REST 端点上添加

@WithTransaction
,因此它发生在
.recoverWithFailure
范围之外。

您有几个选择:

  1. flush操作:代替
    .persist
    ,可以调用
    .persistAndFlush
  2. 提交事务,然后捕获失败。例如:
     public Uni<Auth> createUser(Auth authRequest) {
         User user = new User(authRequest);
         String passwordHash = Password.hash(authRequest.getPassword()).withArgon2().getResult();
         user.setPasswordHash(passwordHash);
         return Panache.withTransaction( () -> PanacheEntityBase
                         .persist( user ).onItem().transform( success -> {
                             log.info( "Successfully created user, email: {}", authRequest.getEmail() );
                             return authRequest;
                         } )
                 )
                 .onFailure().invoke(ex -> {
                     log.error("Unable to create User, email: {}, Exception: {}", authRequest.getEmail(), ex.getMessage(), ex);
                     throw new RegistrationFailedException(Errors.UNABLE_TO_REGISTER_USER + ex.getMessage());
                 });
     }
    

第二种方法通常是推荐的方法,因为您应该让 Hibernate 决定运行查询的最佳时间。

© www.soinside.com 2019 - 2024. All rights reserved.