IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Développement SQL Server Discussion :

DUPLICATION DE LA CLE PRIMAIRE --> NEW IDENTITY


Sujet :

Développement SQL Server

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 12
    Points : 6
    Points
    6
    Par défaut DUPLICATION DE LA CLE PRIMAIRE --> NEW IDENTITY
    Bonjour,

    Je développe actuellement un projet en Java (JDK 1.4) avec une connexion à une base de donnée SQL 2005. Pour les besoins d'un client, nous avons mis en place une procédure stockée que l'on appelle depuis l'application.

    Dans cette procédure stockée, on effectue une insertion en boucle dans l'une des tables de la BD.
    Pour générer la clé primaire à chaque insertion, je récupére le max de la table auquelle je rajoute 1. La clé primaire pour cette table est de type INT. La procédure fonctionne trés bien.

    Le soucis majeur que nous rencontrons est le suivant :
    Après avoir exécuté la requête, a un autre endroit dans l'application, il y a insertion dans la même table mais cette fois-ci en utilisant une requête. Le code est le suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    MonObjet newObj = new MonObjet();
    new Identity(newObj);
    StringBuffer requete = new StringBuffer ("INSERT INTO MONOBJET VALUES
    (" + newObj.getId() + ", " +.............
    Le problème est que le new Identity(newObj); permettant en JAVA de générer une clé dans SQL, génére une clé déja existante, ce qui remonte systématiquement une erreur de duplication de la clé primaire... Et ce pb n'est apparu qu'après mise en place de la procédure stockée.
    Nous ne savons vraiment plus quoi faire, si l'un d'entre vous connait la solution, il serait aimable de nous aider.
    Merci d'avance pour vos réponses.

  2. #2
    Membre confirmé Avatar de agemis31
    Profil pro
    DBA
    Inscrit en
    Octobre 2007
    Messages
    399
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : DBA

    Informations forums :
    Inscription : Octobre 2007
    Messages : 399
    Points : 478
    Points
    478
    Par défaut
    Bonsoir,

    Apparament,vous utilisez deux modèles concurrents, qui s'ignorent et rentrent donc en conflit:
    - votre procédure stockée (dans la base, ignorant l'application java)
    - votre code java (complètement externe à la base)

    Soit vous passez par un serveur d'application et une gestion de type ORM, soit vous passez par la base.

    Je préfère de loin l'approche en base de données. Il me semble préférable, si vous pouvez vous le permettre, de modifier votre clef et d'en faire une clef auto incrémentée (IDENTITY)
    -Dans votre procédure stockée, plus besoin de max
    -Votre code java devra fonctionner à l'envers au niveau de la clef, il faudra qu'il la récupère après l'insertion plutôt qu'il ne l'impose à l'insertion.

    Sinon, vous pouvez aussi passer par java pour votre insertion en masse.

    Troisième solution qui relève un peu de la bidouille: utiliser des clefs qui ne risquent pas d'entrer en concurrence. Par exemple, si votre application java utilise des entiers positifs, vous pouvez peut être utiliser des entiers négatifs dans votre procédure stockée.

    @+

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 12
    Points : 6
    Points
    6
    Par défaut
    Salut,

    Merci Agemis31 pour ta réponse.

    Concernant tes solutions, la première me semble la plus rapide et facile a réaliser, a savoir de modifier le type de la clé primaire de la table pour la mettre en UNIQUEIDENTIFIER. Ainsi lors de l'insertion via la procStock, j'aurais plus qu'a faire newID() pour générer une nouvelle clé. Par contre, je ne comprends pas trés bien ce que tu entends par
    Votre code java devra fonctionner à l'envers au niveau de la clef, il faudra qu'il la récupère après l'insertion plutôt qu'il ne l'impose à l'insertion.
    Si je laisse le code JAVA tel quel et que je ne modifie que le type de la clé primaire comme décrit ci-dessus, penses-tu que j'aurais des soucis?

    La seconde solution que tu as proposé, à savoir de passer par java pour faire l'insertion en masse était notre solution initiale mais il s'est avéré que le client trouvait le temps de chargement beaucoup trop long, du coup on est passé par des proc stock.

    Enfin, pour la troisième solution, lol, elle rélève vraiment de la bidouille, mais pourquoi pas...j'y penserais au cas ou la première solution ne fonctionne pas.

    Merci pour tes propositions en tout cas, si d'autres en ont, qu'ils n'hésitent pas.

  4. #4
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    Bonjour,

    la première me semble la plus rapide et facile a réaliser, a savoir de modifier le type de la clé primaire de la table pour la mettre en UNIQUEIDENTIFIER
    Et pourtant ceci est une mauvaise idée, qui est principalement due à la taille de stockage de ce type : 16 octets.
    Comme un index cluster est implicitement créé pour toute clé primaire, vous allez en plus répandre cette valeur de 16 octets dans les index non-cluster de votre table : au niveau performance lors des lectures, ce sera bien moins bon que si vous utilisez un type entier.
    Enfin utiliser une telle largeur pour votre clé primaire va faciliter la fragmentation de la table : comme les valeurs de UNIQUEIDENTIFIER ne sont pas consécutives, le moteur de base de données sera sans cesse obligé d'allouer de nouvelles pages et/ou de séparer les valeurs qui se trouvent déjà dans des pages pour en déplacer la moitié dans une nouvelle ... berf ce ne sera pas franchement performant.

    Une colonne de type BIGINT peut stocke les valeurs sur 8 octets allant donc de -2^63 a 2^63 (-9 223 372 036 854 775 808 à 9 223 372 036 854 775 807), et INT sur 4 octets : de -2^31 à 2^31-1 (-2 147 483 648 à 2 147 483 647).
    A vous de choisir la plage de valeur qui convient le mieux

    Votre code java devra fonctionner à l'envers au niveau de la clef, il faudra qu'il la récupère après l'insertion plutôt qu'il ne l'impose à l'insertion.
    Ce que veut dire agemis31, c'est qu'en donnant la propriété de compteur à une colonne de clé primaire qui plus est, vous laissez le soin à SQL Server de calculer la valeur de la clé à l'insertion d'une nouvelle ligne dans la table.
    Vous pouvez récupérer sa valeur avec lafonction système SCOPE_IDENTITY().

    Gloabalement je vous conseille de passer par des procédures stockées pour tous les traitements que vous avez à faire en base de données, pour les raisons que j'évoque ici

    @++

  5. #5
    Membre confirmé Avatar de agemis31
    Profil pro
    DBA
    Inscrit en
    Octobre 2007
    Messages
    399
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : DBA

    Informations forums :
    Inscription : Octobre 2007
    Messages : 399
    Points : 478
    Points
    478
    Par défaut
    Bonjour,

    Pour le GUID, effectivement, au niveau performance, ce n'est pas terrible du tout, disons que c'est la solution de facilité.

    Au sujet du code client (java ici) vs code serveur (procédures stockées), il me semble clair que le code serveur est plus évolutif, rapide, et permet surtout de conserver des données pérennes et intègres quelque soit l'évolution des applicatifs :-)

    Maintenant, c'est aussi une question de pragmatisme et de cout, si 99,9% de l'application est développée selon un autre modèle et fonctionne bien, il vaut mieux s'adapter sur cette insertion en masse.

    @+

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 12
    Points : 6
    Points
    6
    Par défaut
    RE,

    Encore une fois merci pour vos réponses.
    Donc pour résumer, il faudrait pas que j'utilise UNIQUEIDENTIFIER comme type de ma colonne car trop gourmand en espace disque mais pluôt que j'utilise la fonction SQL SCOPE_IDENTITY() pour l'insertion depuis JAVA.

    Il y a un truc que je ne comprends pas trés bien concernant ce dernier point, SCOPE_IDENTITY () retourne la dernière ligne insérée. Que deviendrait mon code JAVA si je passais par cette fonction, car il faut bien qu'à l'insertion je saisisse une clé pour cette nouvelle ligne. Puis-je faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    StingBuffer requete = new StringBuffer( "SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];
    INSERT INTO MONOBJET  (IDENTIFIANT,VALEUR) VALUES (" + 
    SCOPE_IDENTITY + 1 + ", " + MAVALEUR + ")" )
    Qu'en pensez-vous??Est'ce la bonne méthode??

  7. #7
    Membre confirmé Avatar de agemis31
    Profil pro
    DBA
    Inscrit en
    Octobre 2007
    Messages
    399
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : DBA

    Informations forums :
    Inscription : Octobre 2007
    Messages : 399
    Points : 478
    Points
    478
    Par défaut
    Bonjour,

    Pour le GUID, ce sont les performances qui le limitent, plutot que l'espace disque.

    Pour l'insertion, ce n'est pas ça. SCOPE_IDENTITY() renvoie la valeur du dernier identify inséré, après l'insertion. C'est SQL Serveur qui s'occupe d'attribuer une valeur à la clef. Par contre, votre application java doit récupérer cette valeur et l'affecter à votre objet. Il faut donc faire le select sur SCOPE_IDENTITY() après l'insertion et ne pas inclure la colonne IDENTIFIANT dans la liste des colonne de l'INSERT. Le mieux serait sans doute d'appeler une procédure stockée.

    @+

  8. #8
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 12
    Points : 6
    Points
    6
    Par défaut
    RE,

    Ouai je pensais également à faire un procStock pour remplacer le bout de code JAVA posant pb.
    Dans ta solution, tu propose de faire un INSERT sans mettre la colonne IDENTIFIANT mais quand je le ferais n'y a-t-il pas un risque que ca aboutisse à une erreur étant donné que cette colonne est déclarée en tant que clé primaire??? De plus, ce champ est obligatoire donc j'aurais forcément des soucis...

  9. #9
    Membre confirmé Avatar de agemis31
    Profil pro
    DBA
    Inscrit en
    Octobre 2007
    Messages
    399
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : DBA

    Informations forums :
    Inscription : Octobre 2007
    Messages : 399
    Points : 478
    Points
    478
    Par défaut
    Bonsoir,

    Pas de problème au niveau de la clef, SCOPE_IDENTITY() est fait pour des IDENTITY :-)
    C'est SQL Serveur qui affectera la valeur.

    @+

  10. #10
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 12
    Points : 6
    Points
    6
    Par défaut
    RE,

    OK!!!Je vais tester ca, à la première heure demain matin, je vous tiendrais donc au courant...
    Merci encore pour votre aide.

  11. #11
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 902
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 902
    Points : 51 646
    Points
    51 646
    Billets dans le blog
    6
    Par défaut
    J'ai écrit depuis de nombreuses années pourquoi il était stupide d'utiliser un MAX + 1 pour générer un auto incrément servant de clef, car il n'existe aucune garantie d'unicité sauf à introduire une transaction au niveau d'isoaltion SERIALIZABLE.

    Lire cet article et les techniques de contournement :
    http://sqlpro.developpez.com/cours/clefs/

    A +

Discussions similaires

  1. Déterminer si un champ est une clé primaire
    Par fbalien dans le forum Bases de données
    Réponses: 5
    Dernier message: 23/09/2019, 10h19
  2. Clé primaire et incrémentation automatique
    Par spacegoogie dans le forum 4D
    Réponses: 4
    Dernier message: 20/06/2005, 10h36
  3. [debutant]cle primaire particuliere
    Par christophebmx dans le forum MS SQL Server
    Réponses: 6
    Dernier message: 21/08/2004, 13h27
  4. [ db2 ] cle primaire autoincrement
    Par hocinema dans le forum DB2
    Réponses: 4
    Dernier message: 25/02/2004, 14h20
  5. XSD, Cle primaire...
    Par Goupil dans le forum Valider
    Réponses: 3
    Dernier message: 21/10/2003, 09h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo