Fondamentalement, j'ai le schéma ci-dessous et j'insère des enregistrements s'ils n'existent pas. Cependant, s’agissant de l’insertion d’un duplicata, le résultat est une erreur comme je l’attendais. Ma question est la suivante: existe-t-il un moyen simple de faire en sorte qu'Hibernate ignore simplement les insertions qui inséreraient des doublons?
CREATE TABLE IF NOT EXISTS `method` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
SEVERE: Duplicate entry 'GET' for key 'name'
Exception in thread "pool-11-thread-4" org.hibernate.exception.ConstraintViolationException: could not insert:
Ma question est la suivante: existe-t-il un moyen simple de faire en sorte qu'Hibernate ignore simplement les insertions qui inséreraient des doublons?
Comment Hibernate pourrait-il savoir qu'un enregistrement a une valeur non unique sans l'insérer?
Si vous effectuez des insertions par lots et que vous ne souhaitez pas annuler la transaction dans son intégralité et abandonner la session en cas de ConstraintViolationException
(c'est ce que vous devriez faire en théorie après une exception, consultez ce fil et ceci réponse précédente ), ma suggestion serait d'utiliser l'API StatelessSession
et d'attraper le ConstraintViolationException
.
Hibernate ne peut pas faire ça. Vous pouvez cependant le faire vous-même. Il existe essentiellement deux options:
Le premier a l'inconvénient que vous vérifiez les doublons sur chaque insert lorsque la probabilité qu'il y ait un doublon peut être faible. Ce dernier sera plus rapide dans les cas habituels où il n’ya pas de doublons, mais présente le désavantage de vérifier les doublons après le visage. Quand une exception ConstraintViolationException est levée, elle invalide la session en cours. Cela signifie que vous devrez effacer avant de faire une recherche d'un duplicata.
La vérification des doublons avant l’insertion est probablement l’approche la plus propre, sauf en cas de problème de performances majeur dont vous devez vous préoccuper. Assurez-vous que vous effectuez la recherche et l'insertion dans une transaction pour vous assurer que quelqu'un n'ajoute pas de doublon entre la recherche et l'insertion, sinon vous obtiendrez une exception ConstraintViolationException.
Vous pouvez essayer d'attraper l'exception org.hibernate.exception.ConstraintViolationException
et d'avaler l'exception dans votre code
Par exemple:
try {
sessionFactory.getCurrentSession().saveOrUpdate(entity);
} catch (ConstraintViolationException e) {
// Ignore the exception here by doing nothing
}
Comme l'a dit Pascal, Hibernate ne saura pas s'il s'agit d'un doublon tant qu'il n'aura pas été inséré.
J'ai rencontré une situation similaire auparavant; plusieurs threads faisaient des insertions dans la base de données, mais certaines d'entre elles seraient des doublons. Tout ce que je faisais était d'attraper et de récupérer gracieusement quand l'une de ces exceptions était lancée.
Au lieu d'utiliser createQuery () en veille prolongée, utilisez createSQLQuery () et essayez une requête du type "méthode REPLACE INTO (id) VALUES (123);"
même si vous attrapez l'exception, il peut y avoir d'autres problèmes
try{
session.save(O);
session.getTransaction().commit();
}catch (HibernateException e) {
System.out.println("you are carched ¤#%SD¤") ;
}
Vous pouvez utiliser l'annotation @SqlInsert sur votre entité pour modifier les utilisations de hibernate par sql afin d'effectuer une insertion dans la base de données. Hibernate doit actuellement utiliser cette instruction.
insert into method(name, id) values (?,?)
Si vous utilisez mysql, vous pouvez utiliser l'instruction @SqlInsert pour modifier l'insertion SQL à l'aide de l'instruction insert ignore mysql.
@SQLInsert(sql = "insert ignore into method(name, id) values (?,?)")
Cependant, vous devriez obtenir les insertions sqls en activant le mode show sql dans hibernate, car l'ordre des colonnes est généré via une logique, et leur documentation le suggère.