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