web-dev-qa-db-fra.com

Contrainte Hibernate ConstraintViolationException. Existe-t-il un moyen simple d’ignorer les entrées en double?

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:
17
luxerama

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.

12
Pascal Thivent

Hibernate ne peut pas faire ça. Vous pouvez cependant le faire vous-même. Il existe essentiellement deux options:

  1. Vérifiez les doublons avant d'insérer; ou
  2. Attrapez l'exception ConstraintViolationException, puis assurez-vous que la violation est due à un doublon (car il peut y avoir d'autres raisons, telles que des champs nuls).

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.

9
Dean Povey

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
}
2
sendon1982

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.

1
Lars Andren

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);" 

1
agas

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¤") ;
    }
0
Ar maj

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.

0
vishva