2009-03-06 7 views
1

Je sélectionne un sous-ensemble de données à partir d'une base de données MS SQL à l'aide d'un PreparedStatement. Lors de l'itération du résultat, je souhaite également mettre à jour les lignes. En ce moment j'utiliser quelque chose comme ceci:Mise à jour d'une base de données lors de l'utilisation d'une instruction prepareStatement sélectionnez

prepStatement = con.prepareStatement(
        selectQuery, 
        ResultSet.TYPE_FORWARD_ONLY, 
        ResultSet.CONCUR_UPDATABLE); 


rs = prepStatement.executeQuery(); 

while(rs.next){ 
rs.updateInt("number", 20) 
rs.updateRow(); 
} 

La base de données est mise à jour avec les valeurs correctes, mais je reçois l'exception suivante:

Optimistic concurrency check failed. The row was modified outside of this cursor. 

Je l'ai googlé, mais n'a pas été capable de trouver de l'aide sur la question.

Comment empêcher cette exception? Ou puisque le programme fait ce que je veux faire, puis-je l'ignorer?

+0

Pouvez-vous nous dire quel niveau d'isolation de transaction est utilisé? – ordnungswidrig

+0

... et aussi ce que la requête exacte et la colonne exacte vous updateInt? – vladr

Répondre

2

L'enregistrement a été modifié entre le moment où il a été extrait de la base de données (via votre curseur) et le moment où vous avez tenté de le sauvegarder. Si la colonne number peut être en toute sécurité mis à jour indépendamment du reste du dossier ou indépendamment d'un autre processus ayant déjà mis la colonne number à une autre valeur, vous pourriez être tenté de le faire:

con.execute("update table set number = 20 where id=" & rs("id")) 

Cependant, la condition de concurrence persiste, et votre changement peut être à son tour écrasé par un autre processus.

La meilleure stratégie consiste à ignorer l'exception (le dossier n'a pas été mis à jour), poussant éventuellement le dossier a échoué à une file d'attente (en mémoire), puis faire une deuxième passe sur les dossiers ayant échoué (réévaluant les conditions dans query et la mise à jour le cas échéant - ajouter number <> 20 comme l'une des conditions dans query si ce n'est pas déjà le cas.) Répétez jusqu'à ce que plus d'enregistrements échouent. Finalement, tous les enregistrements seront mis à jour.

+0

En fait, l'enregistrement est mis à jour, en dépit de l'exception –

+0

Se pourrait-il que "l'autre personne" qui déclenche l'exception de verrouillage optimisitic de votre côté a effectivement effectué la mise à jour que vous voyez? :) – vladr

+0

Non, la mise à jour ne se passe que dans un seul endroit, mon processus est le seul à accéder à la base de données –

0

En supposant que vous savez exactement quelles lignes vous mettrez à jour, je ferais

  • SET votre AUTOCOMMIT OFF
  • SET ISOLEMENT Niveau à SERIALIZABLE
  • SELECT ligne1, row1 FROM table WHERE conditionquelconque FOR UPDATE
  • MISE À JOUR les lignes
  • COMMIT

Ceci est réalisé via un verrouillage pessimiste (et en supposant que le verrouillage des lignes est pris en charge dans votre base de données, cela devrait fonctionner)

Questions connexes