OptimisticLockException dans le code de mise à jour Java SE simple


Je rencontre un problème que je ne sais pas résoudre (et, comme d'habitude, c'est probablement une faute stupide de mon côté). J'écris une application Java SE Swing en utilisant Derby intégré et JPA (EclipseLink). Pas de multi-utilisateur, bien que je puisse ouvrir plusieurs tabbedpanes pour effectuer différentes opérations. Cependant, dans ce problème, j'utilise un seul volet pour reproduire le problème.

Dans ce panneau de test, chaque fois que je l'ajoute en tant que volet à onglets, j'exécute ce code:

public void onTabPanelAdded() {
    if (entityManager == null) {
        // emf is a static property in the Main class
        // so I just create one EntityManagerFactory,
        // but one EntityManager for each JPanel
        entityManager = emf.createEntityManager();
    }

    selectedL10n = entityManager.find(L10n.class, 1);
    l10nCodeField.setText(selectedL10n.getCode());
    descripField.setText(selectedL10n.getName());
    l10nCodeField.requestFocusInWindow();
}

Chaque fois que je ferme le volet à onglets (cachant le JPanel), j'exécute ce code:

public void onTabPanelRemoved() {
    if (entityManager.getTransaction().isActive()) {
        entityManager.flush();
        entityManager.getTransaction().commit();
    }
    entityManager.close();
    entityManager = null;
}

Bien que l'erreur se produise avant de fermer/cacher le JPanel (juste pour vous soulager de penser que cela a à voir avec la non-libération de l'EntityManager).

Maintenant, le panneau de test, comme vous le voyez dans le premier bloc de code, récupère une entité persistante de la base de données et remplit les champs de texte dans le panneau. Après avoir fait un simple changement dans les données et cliqué sur le bouton Enregistrer que j'y ai mis, ce code est exécuté:

private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {
    entityManager.getTransaction().begin();
    selectedL10n = entityManager.merge(selectedL10n);
    selectedL10n.setCode(l10nCodeField.getText());
    selectedL10n.setName(descripField.getText());
    try {
        entityManager.getTransaction().commit();
    } catch (Exception ex) {
        Logger.getLogger(L10nGUIManager.class.getName()).log(
            Level.SEVERE, null, ex);
    }
}

Comme vous le voyez, j'ouvre la transaction, fusionnez l'entité pour vous assurer qu'elle est gérée (j'ai vérifié cela en utilisant entityManager.contient(selectedL10n)), appliquer les modifications et valider. Et pourtant, malgré aucune autre partie de l'application et aucune autre instance/utilisateur ne l'utilise, j'obtiens une exception OptimisticLockException. Je n'ai tout simplement pas le comprendre.

L'entité a un champ version annotée:

@Entity
public class L10n implements Serializable, Comparable<L10n> {
@Version
private int entityVersion;
...

Avec son getter/setter correspondant. Je suis absolument perdu sur la raison.

TIA

Author: Ricardo Palomares Martínez, 2015-09-07