当违反唯一约束时,会抛出
javax.persistence.RollbackException
。但抛出 RollbackException
的原因可能有多种。我怎样才能发现违反了唯一约束?
try {
repository.save(article);
}
catch(javax.persistence.RollbackException e) {
// how to find out the reason for the rollback exception?
}
我怎样才能发现违反了唯一约束?
异常是链式的,您必须递归调用
getCause()
来获取提供者特定的异常(可能会转到 SQLException
),将其转换为您的应用程序可以为用户很好地处理的内容。以下将打印异常链:
for (t = e.getCause(); t != null; t = t.getCause()) {
logger.debug("Exception:" + t);
}
对于异常处理和“翻译”,您可以执行类似于 Spring 的操作(请参阅各种
JpaDialect
类,例如 HibernateJpaDialect
来了解想法)。
所有这些都不好,该代码不可移植,并且查找导致违规的属性并不容易。这在某种程度上证实了 JPA 中没有优雅且可移植的方式来处理约束违规。
如果您使用Spring框架,您可以使用:
org.springframework.dao.DataIntegrityViolationException
对于标准 JPA,可以使用:
org.hibernate.exception.ConstraintViolationException
在 SQL 级别,可以使用:
java.sql.SQLIntegrityConstraintViolationException
使用
e.getCause()
检查导致回滚的原因。
这对你来说可能很晚了,但这是我为 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);
}
编译器在尝试违反唯一约束时返回异常 SQLIntegrityConstraintViolationException。
使用以下 catch 块概念来处理适当的异常。
catch(SQLIntegrityConstraintViolationException e)
{
// Error message for integrity constraint violation
}
catch(Exception e)
{
// Other error messages
}
查明违反约束的原因的最简单方法是首先正确定义约束的名称:
在
@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");
}
}
我认为打印堆栈跟踪将帮助您了解这一点。 e.printStackTrace();
你可以这样做:
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.
然后查看异常信息。
你必须捕获 javax.persistence.PersistenceException。 抛出的异常是 org.hibernate.exception.ConstraintViolationException。
异常消息:org.hibernate.exception.ConstraintViolationException:键“nic_account_no”的重复条目“893073116V-1234567”