#mysql #jpa #jboss #ejb #infinity
#mysql #jpa #jboss #ejb #бесконечность
Вопрос:
У меня есть следующий простой объект JPA:
@Entity
@Table( name = myentity_table )
public class MyEntity {
private double a;
private double b;
//(...)
}
a и b могут быть установлены на Double.POSITIVE_INFINITY
. Когда я пытаюсь сохранить объект с двойным значением INF в базе данных (MySQL), используя стандартный диспетчер объектов, я получаю исключение:
java.sql.SQLException: ‘Infinity’ не является допустимым числовым значением или приблизительным числовым значением
Насколько я знаю, MySQL может не поддерживать числа NaN /-INF / INF. Есть ли какой-либо способ сохранить эту сущность без написания запросов HQL и перевода INF в null (или max double)? В идеале я хотел бы сделать это через entity manager, как обычно.
Заранее спасибо.
Ответ №1:
Методы обратного вызова жизненного цикла объекта @prePersist, @preUpdate могут быть использованы здесь для проверки значения поля NAN /-INF / INF и т.д., А затем соответствующей установки значения по умолчанию.
//--
@PrePersist
@PreUpdate
private void resetField() {
if(field == Double.POSITIVE_INFINITY)
field = somePredefinedValue;
}
//--
Комментарии:
1. Спасибо, вот и все! Мое решение состоит в том, чтобы использовать обратные вызовы до / после и (как я выбрал) в случае INF установить для поля значение Double. MAX_VALUE (это для обратных вызовов до *, для post это должно быть сделано MAX-> INF)
Ответ №2:
MySQL, похоже, не поддерживает «бесконечность». В этой статье говорится, что:
Сохранение и извлечение отрицательной бесконечности в базе данных MySQL осуществляется путем вставки произвольно большого отрицательного числа.
То же самое касается positive. Другие ресурсы также используют 1e500
.
Вместо использования infinity я бы посоветовал вам использовать Float.MAX_VALUE
и Float.MIN_VALUE
(или Double
эквиваленты)
Если вы не можете сделать это в своем коде при установке значений, сделайте это в @PrePersist
, как уже предлагалось.
Комментарии:
1. Мне нравится идея преднамеренного использования не бесконечных констант для эффективного представления бесконечности в приложении.
@PrePersist
Метод может удивить пользователей вашего кода, если они попытаются сохранить бесконечность, но получить что-то еще обратно. Для моего приложения я выбрал 1e12 (1 триллион) в качестве значения, представляющего бесконечность, поскольку у нас нет требования хранить значение выше этого. Мне больше понравилось красивое круглое число, подобное 1 триллиону, чем Float.MAX_VALUE, потому что его намного проще писать в SQL.
Ответ №3:
Я справился с этой проблемой, добавив столбец varchar для хранения текстового представления Float.NaN
, Float.POSITIVE_INFINITY
и Float.NEGATIVE_INFINITY
в то время как исходный столбец будет храниться NULL
. Затем я использую установщик и получатель для управления этими двумя столбцами.
В моем классе @Entity
/** The value I persist. See it is a Float; */
@Column(name = "VALUE")
private Float value;
/** the 'value complement' that does the trick. */
@Column(name = "VALUE_COMPLEMENT") // You can see I've added a new column in my table (it is a varchar)
private String valueComplement;
/**
* value getter.
* If my value is null, it could mean that it is a NaN or /- infinity.
* Then let's check the complement.
*/
public Float getValue() {
if (value == null) {
try {
return Float.parseFloat(this.valueComplement);
} catch (NumberFormatException e) {
return null;
}
} else {
return value;
}
}
/**
* value setter
* If the given value is a NaN or Inf, set this.value to null
* and this.complement to the string representation of NaN or /- Inf.
*/
public void setValue(Float value) {
if (value != null amp;amp; (value.isNaN() || value.isInfinite())) {
this.valueComplement = value.toString();
this.value = null;
} else {
this.value = value;
}
}
Результат :
| ID | LABEL | VALUE | VALUE_COMPLEMENT |
| -- | --------------------- | ----- | ---------------- |
| 1 | PI | 3.14 | NULL |
| 2 | gravity acceleration | 9.81 | NULL |
| 3 | sqare root of -1 | NULL | NaN |
| 4 | log of 0 | NULL | -Infinity |