如何处理JPA唯一约束违规?

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

当违反唯一约束时,会抛出

javax.persistence.RollbackException
。但抛出
RollbackException
的原因可能有多种。我怎样才能发现违反了唯一约束?

try {
    repository.save(article);
}
catch(javax.persistence.RollbackException e) {
    // how to find out the reason for the rollback exception?
}
java jpa exception constraints
9个回答
22
投票

我怎样才能发现违反了唯一约束?

异常是链式的,您必须递归调用

getCause()
来获取提供者特定的异常(可能会转到
SQLException
),将其转换为您的应用程序可以为用户很好地处理的内容。以下将打印异常链:

for (t = e.getCause(); t != null; t = t.getCause()) {
    logger.debug("Exception:" + t);
}

对于异常处理和“翻译”,您可以执行类似于 Spring 的操作(请参阅各种

JpaDialect
类,例如
HibernateJpaDialect
来了解想法)。

所有这些都不好,该代码不可移植,并且查找导致违规的属性并不容易。这在某种程度上证实了 JPA 中没有优雅且可移植的方式来处理约束违规


8
投票

如果您使用Spring框架,您可以使用:

org.springframework.dao.DataIntegrityViolationException

对于标准 JPA,可以使用:

org.hibernate.exception.ConstraintViolationException

在 SQL 级别,可以使用:

java.sql.SQLIntegrityConstraintViolationException


3
投票

使用

e.getCause()
检查导致回滚的原因。


3
投票

这对你来说可能很晚了,但这是我为 PostGres 解决的方法。

catch (DataIntegrityViolationException e) {

            for (Throwable t = e.getCause(); t != null; t = t.getCause()) {

                if (PSQLException.class.equals(t.getClass())) {
                    PSQLException postgresException = (PSQLException) t;

                    // In Postgres SQLState 23505=unique_violation
                    if ("23505".equals(postgresException.getSQLState())) {
                        throw new CustomDataAlreadyExistsException("YourErrorCode", e);
                    }
                }
            }
            throw new SomeOtherException("YourErrorCode2", e);

        }

2
投票

编译器在尝试违反唯一约束时返回异常 SQLIntegrityConstraintViolationException

使用以下 catch 块概念来处理适当的异常。

catch(SQLIntegrityConstraintViolationException e) 
{
  // Error message for integrity constraint violation
}
catch(Exception e)
{
 // Other error messages
}

1
投票

查明违反约束的原因的最简单方法是首先正确定义约束的名称

定义唯一约束:

@UniqueConstraint
中使用
@Table
,我们可以定义一列或多列约束,以及自定义约束名称

@Entity
@Table(uniqueConstraints = {
        @UniqueConstraint(columnNames = { "name" }, name = "name_constraint"),
        @UniqueConstraint(columnNames = { "teamId", "orderIndex" }, name = "teamId_orderIndex_constraint")
})
public class Space {
    // .. other field omitted

    private String name;

    private Integer orderIndex;

    private Integer teamId;
}

JPA 使用我们的自定义名称更改约束:

Hibernate: 
    alter table space
       add constraint name_constraint unique (name)

Hibernate: 
    alter table space
       add constraint teamId_orderIndex_constraint unique (team_id, order_index)

妥善处理
DataIntegrityViolationException
:

使用

e.getMessage()
,我们得到结果,其中包含我们上面定义的约束的名称:

could not execute statement; SQL [n/a]; constraint [space.name_constraint]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement

然后简单地检查结果是否包含我们定义的名称:

import org.springframework.dao.DataIntegrityViolationException;

try {
    repository.save(space);
} catch (DataIntegrityViolationException e) {

    if(e.getMessage().contains("name_constraint")) {
        System.out.println("Unique name constraint violated");
    }

    if(e.getMessage().contains("teamId_orderIndex_constraint")) {
        System.out.println("Unique teamId_orderIndex constraints violated");
    }
}

参考:在 JPA 中定义唯一约束


0
投票

我认为打印堆栈跟踪将帮助您了解这一点。 e.printStackTrace();


0
投票

你可以这样做:

StringWriter writer=new StringWriter(); //remains the message from stack trace.
e.printStackTrace(new PrintWriter(writer));
String message=writer.toString(); // gets the message of full stack trace.

然后查看异常信息。


0
投票

你必须捕获 javax.persistence.PersistenceException。 抛出的异常是 org.hibernate.exception.ConstraintViolationException。

异常消息:org.hibernate.exception.ConstraintViolationException:键“nic_account_no”的重复条目“893073116V-1234567”

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