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

JDBC Java Discussion :

Locker une ligne : SELECT FOR UPDATE


Sujet :

JDBC Java

  1. #1
    Membre à l'essai
    Inscrit en
    Janvier 2011
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Janvier 2011
    Messages : 20
    Points : 10
    Points
    10
    Par défaut Locker une ligne : SELECT FOR UPDATE
    Bonjour,

    Après deux jours de recherches je viens vers en espérant trouver ma réponse

    J'ai une application qui est utilisé en multi thread, et je veux qu'un thread puisse verrouiller une ligne (pour que les autres threads ne puisse rien faire sur cette ligne) pour là mettre à jour puis la débloquer après l'update.

    Donc je voulais utiliser SELECT FOR UPDATE, mais j'ai l'impression que ca ne fonctionne pas, voilà mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    public BasicJDBCDemo()
      {
        try
        {
        	conn = ds.getConnection();
        	conn.setAutoCommit(false);
        	doSelectTest();
        	doSelectTest();
     
            conn.close();
        }
        catch (SQLException ex)           
          {System.err.println(ex.getMessage());}
      }
     
      private void doSelectTest()
      {
        System.out.println("[OUTPUT FROM SELECT]");
        String query = "Select * from b2bicheckpoint where OID = ? FOR UPDATE";
        PreparedStatement pst = null;
        ResultSet rs=null;
        try
        {
          pst = conn.prepareStatement(query);
          pst.setLong(1, 3001);
          rs = pst.executeQuery();
     
          while (rs.next())
          {
            String s = rs.getString("HostName");
            long oid = rs.getLong("OID");
            System.out.println("OID/Host=="+oid+"/"+s);        
          }      
        }
        catch (SQLException ex)
        {
          ex.printStackTrace();
        }
        finally
        {
        	DBUtil.close(pst);
        	DBUtil.close(rs);
        }
      }
    Donc, le premier appel doSelectTest() devrait faire le lock, mais le deuxième appel doSelectTest() devrait planter en faisant le lock, ce qui n'est pas le cas, result :

    1) premier appel doSelectTest()

    [OUTPUT FROM SELECT]
    query==Select * from b2bicheckpoint where OID = ? FOR UPDATE
    OID/Host==3001/UnknownHost

    2) deuxiéme appel doSelectTest()

    [OUTPUT FROM SELECT]
    query==Select * from b2bicheckpoint where OID = ? FOR UPDATE
    OID/Host==3001/UnknownHost

  2. #2
    Membre à l'essai
    Inscrit en
    Janvier 2011
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Janvier 2011
    Messages : 20
    Points : 10
    Points
    10
    Par défaut
    La seule explication que je vois, c'est que le lock depend de la vie d'un ResultSet ou PreparedStatement .... Ca serait très dommage car dans une utilisation multi thread avec un pool de connection, chacun à ses propres connection, PreparedStatement , et resultSet!

    Merci de votre aide..........

  3. #3
    Membre à l'essai
    Inscrit en
    Janvier 2011
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Janvier 2011
    Messages : 20
    Points : 10
    Points
    10
    Par défaut
    Même en faisant un appel doSelectLock() (Select avec SELECT FOR UPDATE) puis doSelect() (Select simple), ca ne fonctionne pas, le deuxieme select me renvoi des info! :

    1) Premier appel
    [OUTPUT FROM SELECT Lock]
    query==Select * from b2bicheckpoint where OID = ? FOR UPDATE
    oid/host==3001/UnknownHost

    2) Deuxieme appel
    [OUTPUT FROM SELECT]
    query==Select * from b2bicheckpoint where OID = ?
    oid/host==3001/UnknownHost

    Pour info transaction-isolation = READ-COMMITTED dans mon SGBD, mais la colonne HostName est un index et d'après le manual MySQL avec READ-COMMITTED seul les index de la ligne seront locké, ce que je veux aussi. Mais ca ne fonctionne pas ai je oublié quelques choses ?

  4. #4
    Membre à l'essai
    Inscrit en
    Janvier 2011
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Janvier 2011
    Messages : 20
    Points : 10
    Points
    10
    Par défaut
    J'utilise MySQL innodb

  5. #5
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Ton test n'est pas le bon, là, tu utilises la même connexion donc le problème ne se pose pas.
    Essayer de faire un executable et de le lancer 2 fois ou alors, fais l'acquisition de 2 connexions pour faire le test.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Membre à l'essai
    Inscrit en
    Janvier 2011
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Janvier 2011
    Messages : 20
    Points : 10
    Points
    10
    Par défaut
    Merci OButterlin,

    Oki, maintenant j'ai crée une methode qui n'utilise pas de connection pool, et qui crée directement des nouvelle connections,

    code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    private static Connection getNewConnection()
    {
          System.out.println("New connection..");
          final String url = "url";
            Connection conn=null;
            try 
            {
                conn = DriverManager.getConnection(url, "user", "pwd");
            }
            catch (SQLException e) 
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
     
          return conn;
      }
    Puis dans voici mes fonctions :

    code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
     
     public BasicJDBCDemo()
      {
            //SELECT FOR UPDATE
            doSelectLockTest();
            //Simple SELECT
            doSelectTest();
     
      }
     
      private void doSelectLockTest()
      {
        System.out.println("[OUTPUT FROM SELECT Lock]");
        PreparedStatement pst = null;
        ResultSet rs=null;
        Connection conn=null;
     
        try
        {
          String query = "Select * from b2bicheckpoint where OID = ? FOR UPDATE";
            System.out.println("query=="+query);
     
           //new jdbc connection;
           conn=getNewConnection();
           conn.setAutoCommit(false);
           pst = conn.prepareStatement(query);
           pst.setLong(1, 3001);
           //Le run reste bloqué ici à cause du 'FOR UPDATE'!!!!
           rs = pst.executeQuery();
     
           while (rs.next())
           {
            String s = rs.getString("HostName");
            long oid = rs.getLong("OID");
            System.out.println("oid/host=="+oid+"/"+s);
          }      
        }
        catch (SQLException ex)
        {
          ex.printStackTrace();
        }
        finally
        {
            DBUtil.close(pst);
            DBUtil.close(rs);
            DBUtil.close(conn);
        }
      }
     
      private void doSelectTest()
      {
        System.out.println("[OUTPUT FROM SELECT]");
        String query = "Select * from b2bicheckpoint where OID = ?";
        System.out.println("query=="+query);
        PreparedStatement pst = null;
        ResultSet rs=null;
        Connection conn=null;
     
        try
        {
          conn=getNewConnection();          
          conn.setAutoCommit(false);
            pst = conn.prepareStatement(query);
        pst.setLong(1, 3001);
        rs = pst.executeQuery();
     
          while (rs.next())
          {
            String s = rs.getString("HostName");
            long oid = rs.getLong("OID");
            System.out.println("oid/host=="+oid+"/"+s);        
          }      
        }
        catch (SQLException ex)
        {
          ex.printStackTrace();
        }
        finally
        {
            DBUtil.close(pst);
            DBUtil.close(rs);
            DBUtil.close(conn);
        }
      }
    L'éxecution reste bloqué sur executeQuery() à cause du 'FOR UPDATE' est ce que c'est normal ? dois je exécuter deux thread pour le test??

    MErci

  7. #7
    Membre à l'essai
    Inscrit en
    Janvier 2011
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Janvier 2011
    Messages : 20
    Points : 10
    Points
    10
    Par défaut
    oki maintenant en faisant rien, j'ai eu un timeout :
    java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1075)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3566)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3498)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1959)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2113)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2568)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2113)
    at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2275)
    at BasicJDBCDemo.doSelectTest(BasicJDBCDemo.java:215)
    at BasicJDBCDemo.<init>(BasicJDBCDemo.java:150)
    at BasicJDBCDemo.main(BasicJDBCDemo.java:28)
    Alors ceci est intéressant, mais le problème c'est que le 'Select For Update' est executé dans le même thread que celui de l'update donc je rsique d'être bloqué sans faire l'update!

    J'ai besoin de comprendre comment ça marche pour voir si ca reponds à mon besoin qui est assez simple, utilisation en multi thread et quand un thread fait select For update la ligne concerné doit être locké jusqu'à que le thread la debloque.... Donc les autres threads ne doivent pas pouvoir faire de traitement sur là même...

    Merci de m'éxpliquer comme ceci fonctionne SVP

  8. #8
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Tout ceci me paraît normal, tu fais une lecture en demandant de verrouiller en vue d'une mise à jour, du coup, les autres ne peuvent pas lire, d'où l'attente.
    Au bout d'un temps (qui se paramètre), un timeout est atteint provoquant une exception.

    Si tu veux que l'attente soit indéfinie, il existe une valeur spéciale pour ça.
    Si tu veux que l'erreur claque tout de suite, réduit le timeout.

    Donc, en résumé :
    - tu lis avec demande de verrouillage
    - un autre "job" lis avec demande de verrouillage (des mêmes enregistrements ou même page)
    ...-> se met en attente de la libération avec comme limite "timeout"
    ......-> le timeout est atteint => erreur
    ......-> les enregistrements sont libérés => la lecture aboutie
    - le premier traitement fait son update => libération des enregistrements
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

Discussions similaires

  1. select for update LOCK 3 10gR2
    Par petitfrere dans le forum Oracle
    Réponses: 1
    Dernier message: 01/12/2006, 18h52
  2. Select For Update Nowait
    Par e1lauren dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 28/09/2006, 22h04
  3. [FORMS PL/SQL] Select for Update
    Par taska dans le forum Forms
    Réponses: 3
    Dernier message: 30/08/2006, 10h33
  4. [MySql5]select ... for update
    Par melou dans le forum Requêtes
    Réponses: 1
    Dernier message: 20/04/2006, 11h11
  5. [Verrou] SELECT FOR UPDATE
    Par e1lauren dans le forum PostgreSQL
    Réponses: 10
    Dernier message: 13/10/2005, 17h06

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