Question

Ceci est une version spécifique de cette question .
Je veux vérifier si j'insère une ligne en double. Dois-je vérifier par programme dans ma couche d'application:

if (exists(obj))
{
    throw new DuplicateObjectException();
}
HibernateSessionFactory.getSession().save(obj);

ou dois-je attraper l'exception levée par la couche de base de données et déclenchée lorsque je ne respecte pas la contrainte?

try
{
    HibernateSessionFactory.getSession().save(obj);
}
catch(ConstraintViolationException e)
{
    throw new DuplicateObjectException();
}

EDIT: En d'autres termes, même si la contrainte est là pour rester (la conception de la base de données est bonne, de toute façon, et je ne peux pas être sûr que mon application sera la seule à accéder à la table). compter sur la contrainte et gérer l'exception que sa violation soulèvera, ou je ferais mieux de vérifier de toute façon?

EDIT2: Bien sûr, je vérifie + insère une transaction en verrouillant la table pour s'assurer qu'aucun autre processus n'écrit un autre enregistrement entre-temps

Était-ce utile?

La solution

Tout d'abord, vous devez disposer d'une clé primaire ou d'une contrainte unique sur la base de données pour appliquer correctement cette unicité - aucune question.

Étant donné que la contrainte existe, de quelle manière devriez-vous coder dans l'application? Ma préférence serait d'essayer l'insertion et attraper les exceptions. Parce que la plupart des insertions vont probablement réussir, seules quelques-unes échouent en tant que doublons (c'est ce que "l'exception" implique!): Il est inefficace d'effectuer une vérification d'existence avant chaque insertion, lorsque la base de données exécute de toute façon sa propre vérification de contrainte. .

De même, il est théoriquement possible que le contrôle exist soit faux de toute façon - si quelqu'un d'autre parvient à valider un enregistrement avec la même valeur de clé dans le petit intervalle entre votre contrôle exist et votre insertion. Ensuite, si vous ne capturez pas l’exception de base de données, vous penserez que l’insertion a réussi alors qu’elle ne l’a pas fait.

Autres conseils

Vous vérifiez que l'objet existe uniquement dans le code de l'application, puis, une fois convaincu que tel n'est pas le cas, sauvegardez-le allègrement. Mais un autre client simultané peut insérer son propre objet au moment où il se trouve entre vos deux lignes de code. Donc, vous obtiendrez de toute façon une exception en double, mais cette fois-ci, vous ne l'attraperez pas.

Vous devez faire la sauvegarde () et attraper l'exception. Sinon, vous avez une situation de concurrence critique avec d'autres clients simultanés travaillant sur la même base de données.

Vous devez intercepter l'exception de base de données à moins que vous ne puissiez garantir que votre application est la seule à avoir jamais inséré des lignes (et inséré des lignes) dans votre base de données.

EDIT: J'ai peut-être mal compris la question, mais je maintiendrais quand même l'idée que l'option B (HibernateSessionFactory lève l'exception ConstraintException de la base de données) est la meilleure option. Il y a toujours une petite chance qu'une autre application insère quelque chose dans le laps de temps entre votre vérification et l'appel de fonction réel. En outre, le seul moyen de détecter une dupe consiste à effectuer une requête supplémentaire, qui constitue une perte inutile de performances.

Ma compréhension initiale de la question était que, dans l'option A, la vérification de la dupe serait effectuée en interne (c'est-à-dire en utilisant uniquement les structures de données que le programme avait déjà créées et sans requête jusqu'à l'insert). Ma réponse initiale était en réponse à cette méthode.

En général, j'essaie d'éviter un code reposant sur des erreurs car j'ai commis une erreur. Parfois, cependant, c'est tout ce que vous pouvez faire. Dans votre cas, je pense que vous devriez d'abord vérifier.

Cela s’arrêtera (autorisant les entrées en double) si la contrainte est supprimée pour une raison quelconque (généralement des travaux de maintenance pour lesquels le DBA néglige de la réactiver). Vous devriez vérifier cette situation dans l'application.

Cependant, la conception de la base de données est bonne si elle doit appliquer la contrainte (comme vous l'avez très justement souligné), car d'autres utilisateurs pourraient également utiliser la base de données. En règle générale, il est préférable de supposer que les applications et les bases de données vivent dans une relation M: M - ce sera le cas presque tout le temps.

Les exceptions émises par Hibernate (ou tout composant ORM) ont tendance à être difficiles à interpréter.

Si l'exception contient suffisamment d'informations pour que vous puissiez générer un message d'erreur qui aide réellement l'utilisateur, capturez-la, analysez-la et passez à autre chose.

Si l'exception ne contient pas suffisamment d'informations, vous devez rechercher la condition d'erreur et générer un message d'erreur utile pour indiquer à l'utilisateur qu'il fait quelque chose de mal.

La question est l'une des "comment l'opaque est-elle opaque"? Certains sont assez opaques. D'autres en ont assez pour pouvoir analyser la chaîne de message et déterminer ce qu'il faut dire à l'utilisateur.

Une fois en veille prolongée, une doit être écartée de la session. la session (voir section 11.2.3). Donc, si vous avez besoin de vérifier les doublons et de continuer à utiliser la même session, vous n'avez pas d'autre choix que de vérifier d'abord dans l'application.

Il est également possible avec le code du premier extrait de code qu'un autre processus insère un enregistrement générant la levée de l'exception de duplication entre le moment où vous vérifiez le double et celui où il est effectivement inséré.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top