2009-07-30 5 views
7

Je travaille sur une application de base de données qui est la plupart du temps en lecture seule, mais il y a une table qui enregistre le mouvement de l'utilisateur dans l'application et a un grand nombre d'écritures. Pour tous les quelques milliers écrit, nous voyons quelques exceptions dans le journal des erreurs comme ceci:Obtenir des erreurs d'entrée en double à partir d'Hibernate, MySQL est à blâmer?

[WARN][2009-07-30 11:09:20,083][org.hibernate.util.JDBCExceptionReporter] SQL Error: 1062, SQLState: 23000 
[ERROR][2009-07-30 11:09:20,083][org.hibernate.util.JDBCExceptionReporter] Duplicate entry '17011' for key 1 
[ERROR][2009-07-30 11:09:20,083][org.hibernate.event.def.AbstractFlushingEventListener] Could not synchronize database state with session 
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update 
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94) 
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) 
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275) 

Le tableau en question a le schéma suivant:

CREATE TABLE IF NOT EXISTS `my_table` (
    `id` int(11) NOT NULL, 
    `data1` int(11) NOT NULL, 
    `data2` int(11) NOT NULL, 
    `timestamp` datetime default NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; 

Et le XML mapping Hibernate correspondant:

Il est possible, bien que peu probable, que plusieurs instances de notre webapp puissent écrire dans la base de données en même temps, puisque nous les numéros de version dans notre contexte webapp pour libérer de façon transparente de nouveaux v ersions des applications. Les clients avec l'ancienne version de l'application mise en cache dans leur navigateur Web accèderaient donc aux anciennes versions du serveur, que nous ne déploierons plus après quelques semaines.

De toute façon, je ne suis pas convaincu que c'est le problème, mais je me méfie qu'il y ait un problème de synchronisation entre MySQL et Hibernate ici. Est-ce que changer mon générateur pour la séquence, seqhilo ou hilo aider? Aussi, si vous pouvez fournir un exemple de configuration d'un tel générateur dans MySQL, ce serait très utile, car la plupart des ressources en ligne sont simplement copiées-collées à partir des exemples terriblement minimalistes du manuel Hibernate.

Répondre

9

L'incrément est définitivement mauvais si vous avez plus d'un processus écrit dans la même table - vous êtes lié à des collisions.

Puisque nous parlons de MySQL, la chose la plus facile à utiliser serait identity. Dans votre mapping Hibernate:

<generator class="identity"/> 

Dans votre script MySQL:

CREATE TABLE IF NOT EXISTS `my_table` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `data1` int(11) NOT NULL, 
    `data2` int(11) NOT NULL, 
    `timestamp` datetime default NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; 

Pour modifier une table existante:

ALTER TABLE `my_table` 
    CHANGE COLUMN `id` `id` int(11) NOT NULL AUTO_INCREMENT=$NEW_VALUE$; 

où doit être remplacé $ NEW_VALUE $ par le prochain ID disponible si cette séquence ne se réinitialise pas à 1.

+0

Réponse très complète et claire - merci! –

Questions connexes