[SQL/Hibernate] Erreur "Overflow Exception trying to bind NaN" alors que je lis un objet
Bonjour à tous,
j'ai une erreur de type SQL (SQLException) qui est générée : "java.sql.SQLException: Overflow Exception trying to bind NaN"
Vous me direz, que j'essaye de mettre à jour un champ dans une table.
Et bien, de prime abord (du moins explicitement), non ! Je ne tente que de lire un objet (c'est à dire que je fais monDAO.find(trucId)). Je ne tente pas de faire un update de champ (ou alors cela se passe en sous-main : mais quoi donc ?). J'ai beau essayer de chercher ce que je peux mettre à jour, je ne trouve pas.
Dans mon objet, j'ai même un champ de type "Numéro de version" de ligne, j'ai même testé en essayant de ne plus le charger (cas où la valeur en base serait trop grande pour être caster en type java : et toujours le même problème).
Mais qu'est ce que j'ai bien pu oublier ?!?!?!
J'utilise Hibernate (3.4), ma base de données est Oracle
Mon DAO :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| @Repository
public class MonDAO extends MutableDAOImpl<MaClasse> {
public static final Logger LOGGER = Logger.getLogger(MonDAO.class);
/**
* Private constructor used to prevent from instantiation.
* Use DAOFactory.
*/
private MonDAO() {
super();
}
public Class<MaClasse> getModelClass() {
return MaClasse.class;
}
public MaClasse find(Long trucId) throws DAOException {
try {
StringBuffer req = new StringBuffer("select c from MaClasse c ");
req.append("where c.truc.id = :trucID ");
Query query = em.createQuery(req.toString());
query.setParameter("trucID", trucId);
return (MaClasse) query.getSingleResult(); // c'est ici que l'erreur est générée
} catch (NoResultException e) {
return null;
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
throw new DAOException(e);
}
}
} |
Mon objet en lui-même est :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| @Entity
@Table(name = "T_PROXY_PTF", uniqueConstraints = { @UniqueConstraint(columnNames = { "FUND_ID" }) })
public class MaClasse {
/** The id. */
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "proxy_ptf_seq")
@SequenceGenerator(name = "proxy_ptf_seq", allocationSize = 10, sequenceName = "SEQ_PROXY_PTF_ID")
private Long id;
@Version
private Integer version;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "FUND_ID")
private Fund fund;
@Column(name = "PROCESS_DATE", nullable = false)
@Type(type = "com.nexar.domain.NxDateTimeUserType")
private NxDateTime processDate;
@Lob
private String data;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
public NxFund getFund() {
return fund;
}
public void setFund(NxFund fund) {
this.fund = fund;
}
public NxDateTime getProcessDate() {
return processDate;
}
public void setProcessDate(NxDateTime processDate) {
this.processDate = processDate;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
} |
L'erreur générée est asse la suivante :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| 06 mai 19:45:29 ERROR [MonDAO] - org.hibernate.exception.GenericJDBCException: could not update: [com.(....).MaClasse#810]
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not update: [com.(....).MaClasse#810]
at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:614)
at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:128)
at com.(...).MonDAO.find(MonDAO.java:47)
(...)
Caused by: org.hibernate.exception.GenericJDBCException: could not update: [com.nexar.model.portfolio.NxProxyPortfolioIndicator#810]
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:126)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:114)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2453)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2335)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2635)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:115)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:64)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:996)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1141)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:88)
... 69 more
Caused by: java.sql.SQLException: Overflow Exception trying to bind NaN
at oracle.jdbc.driver.DoubleBinder.bind(OraclePreparedStatement.java:13868)
at oracle.jdbc.driver.OraclePreparedStatement.setupBindBuffers(OraclePreparedStatement.java:2911)
at oracle.jdbc.driver.OraclePreparedStatement.processCompletedBindRow(OraclePreparedStatement.java:2190)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3334)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3423)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2435)
... 81 more |
La classe mère de mon DAO est :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public abstract class MutableDAOImpl<E> extends ImmutableDAOImpl<E> implements MutableDAO<E> {
private static final Logger logger = Logger.getLogger(MutableDAOImpl.class);
protected MutableDAOImpl() {
super();
}
public void save(E object) throws DAOException {
try {
if (em.contains(object)) {
em.merge(object);
} else {
em.persist(object);
}
em.flush();
} catch (Exception e) {
logger.error("Error while saving: " + object + " on " + getModelClass(), e);
throw new DAOException(e);
}
}
public void merge(E object) throws DAOException {
try {
em.merge(object);
} catch (Exception e) {
logger.error("Error while saving: " + object + " on " + getModelClass(), e);
throw new DAOException(e);
}
}
public void flush() throws DAOException {
try {
em.flush();
} catch (Exception e) {
logger.error("Error while flushing on: " + getModelClass(), e);
throw new DAOException(e);
}
}
public void delete(E object) throws DAOException {
try {
object = em.merge(object);
em.remove(object);
} catch (Exception e) {
logger.error("Error while deleting: " + object + " on " + getModelClass(), e);
throw new DAOException(e);
}
}
} |
Et la classe grand-mère de mon DAO est :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| public abstract class ImmutableDAOImpl<E> implements ImmutableDAO<E> {
private static final Logger logger = Logger.getLogger(ImmutableDAOImpl.class);
@PersistenceContext
protected EntityManager em;
protected ImmutableDAOImpl() {
super();
}
public abstract Class<E> getModelClass();
public E getById(Long id) throws DAOException {
try {
return em.find(getModelClass(), id);
} catch (Exception e) {
logger.error("Error while getting by id: " + id + " on " + getModelClass(), e);
throw new DAOException(e);
}
}
@SuppressWarnings("unchecked")
public List<E> findByExample(E object) throws DAOException {
try {
if (object == null)
return null;
Session session = (Session) em.getDelegate();
Criteria criteria = session.createCriteria(getModelClass());
return (List<E>) criteria.add(Example.create(object)).list();
} catch (Exception e) {
logger.error("Error while finding by example: " + object + " on " + getModelClass(), e);
throw new DAOException(e);
}
}
@SuppressWarnings("unchecked")
public List<E> findAll() throws DAOException {
try {
String q = "SELECT e FROM " + getModelClass().getSimpleName() + " e";
Query query = em.createQuery(q);
return (List<E>) query.getResultList();
} catch (Exception e) {
logger.error("Error while fetching all on " + getModelClass(), e);
throw new DAOException(e);
}
}
/**
* Find all with a sort field and sort side (asc, desc)
*
* @param sortField
* The sort field must be present.
* @param sort
* Sort side (defauls is asc).
* @return
* @throws DAOException
*/
@SuppressWarnings("unchecked")
protected List<E> findAll(String sortField, SortType sort) throws DAOException {
try {
SortType sortType = SortType.ASC;
if (sort != null) {
sortType = sort;
}
String q = "SELECT e FROM " + getModelClass().getSimpleName() + " e order by e." + sortField + " "
+ sortType;
Query query = em.createQuery(q);
return (List<E>) query.getResultList();
} catch (Exception e) {
logger.error("Error while fetching all on " + getModelClass(), e);
throw new DAOException(e);
}
}
} |
Argh, il fallait lire avec attention les logs ...
Le lendemain matin, après la tête reposée et de nouvelles heures de recherche et de test ...
En fait, lorsque je fais la requête "find" en question, parfois Hibernate tente de flusher son cache et donc, lance des update sur des objets modifiés (qui ne sont pas du type "MaClasse", mais du type, par ex "MonAutreClasse"). Une fois identifié l'autre objet en question, il a fallu regarder à quels endroits je tentais de mettre "NaN", et c'est là que j'ai compris que dans mes modifications précédentes j'avais omis de traiter le cas "NaN".
Problème corrigé ! Ouf !
Leçon : toujours regarder avec attention les erreurs fournies. Et se méfier un peu du cache d'Hibernate ...