Org.springframework.dao.DataIntegrityViolationException неправильная причина?
Я использую hibernate для вставки в таблицу mysql, для которой все столбцы определены как не равные нулю. Он имеет уникальный первичный ключ и еще один уникальный индекс для нескольких столбцов.
Я получаю следующую ошибку:
org.springframework.dao.DataIntegrityViolationException: не удалось выполнить пакетное обновление JDBC; SQL [вставить в MY_TABLE (col1, col2, col3, col4, ID_) значения (?,?,?,?,?)]; ограничение [null]
Эта ошибка возникает в журналах клиентов, и я не могу воспроизвести проблему самостоятельно, поэтому я не могу отложить отладку, чтобы увидеть, что значения находятся в инструкции insert.
Мое понимание заключается в том, что "ограничение [null]" означает, что ограничение "не нуль" нарушается. Однако, глядя на мой код, я не вижу никакого способа, чтобы какая-либо из данных могла быть нулевой во время вставки, если только hibernate не пытается вставить нулевой идентификатор (что было бы очень плохой ошибкой в спящем режиме, и поэтому кажется, что маловероятно).
Однако я могу видеть, как может случиться, что нарушается уникальное ограничение. Возможно ли, что сообщение вводит в заблуждение, и я действительно получаю уникальное нарушение ключа? "Ограничение [null]" всегда означает, что было нарушено не нулевое ограничение?
Ответы
Ответ 1
Если вы ищете вызывающих объектов конструктора DataIntegrityViolationException в исходном коде Spring, вы обнаружите, что он вызвал в org.springframework.orm.hibernate3.SessionFactoryUtils
:
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() +
"]; constraint [" + jdbcEx.getConstraintName() + "]", ex);
Таким образом, исключение вызвано нарушенным ограничением, а null
- это имя ограничения, возвращаемого исключением JDBC. Поэтому вы должны обвинить драйвер MySQL в том, что вы не заселили нарушенное имя ограничения в исключении JDBC. Но нарушенным ограничением может быть любое ограничение, а не обязательно ограничение not null
.
Ответ 2
вы можете получить имя Constain непосредственно из типа исключения Hibernate.
используйте
getConstraintName
чтобы получить имя ограничения DB.
} catch (ConstraintViolationException conEx) {
if (conEx.getConstraintName().contains("PROJECT_UK")) {
//TODO Project Entity is violating it constrain
Я использовал содержит, потому что я хочу, чтобы это приложение запускалось на нескольких схемах БД. По умолчанию getConstraintName содержит имя базы данных, например
MyDBName.ConstrainName