2009-05-07 9 views
4

J'ai un MDB (Message bean) qui reçoit des messages avec chaîne qui représentent un mot. J'ai aussi une table dans la base de données. Le MDB devrait stocker dans la table, les mots et le nombre de fois que chaque mot a été reçu (compteur).Java EE concurrence et verrouillage

Le problème est que pour obtenir de meilleures performances du MDB a commencé dans de nombreux cas et lorsque le même nouveau mot est reçu par différentes instances deux créent la même ligne avec le nombre de 1.

Pour résoudre ce que je devrais faire le mot champ unique et ensuite la deuxième instance échouera sur commit, retransmettant le message, ce qui fonctionnera, mais peut être problématique. Est-ce une bonne pratique?

Une autre solution consiste à fusionner ces lignes après addition du compteur. Mais que se passe-t-il si une autre instance augmente le compteur au milieu de la mise à jour.

Que faire si deux instances tentent d'augmenter le compteur? @Version devrait être suffisant?

Je ne suis pas sûr de savoir quelle est la bonne solution ici. Comment géreriez-vous de tels cas?

Aussi pouvez-vous suggérer quelques livres sur les pratiques de concurrence (pas sur l'utilisation de synchronized comme j'ai besoin de soutenir Java EE et peut courir un groupe de serveurs d'application)?


Mise à jour: Après avoir lu plus sur EJB et JPA je suppose que je veux quelque chose comme une entité de verrouillage. Par exemple, je peux créer une nouvelle table avec seulement id et les colonnes clés et des données comme ceci:

ID | KEY 
1 | WORDS_CREATE_LOCK 

Alors que quand je dois gérer un nouveau mot que je vais faire quelque chose comme ça (code ne exact, pas sûr qu'il va même compiler):

// MAIN FUNCTION 
public void handleWord(String wordStr) { 
    Word w = getWord(wordStr); 

    if (w == null) 
    w = getNewOrSychronizedWord(wordStr); 

    em.lock(w); 
    w.setCounter(w.getCounter() + 1); 
    em.unlock(w); 
} 

// Returns Word instance or null if not found 
private Word getWord(String wordStr) { 
    Word w = null; 

    Query query = em.createQuery("select w from words as w where w.string = :wordStr order by w.id asc"); 
    query.setParameter("wordStr", wordStr); 
    List<Word> words = query.getResultList(); 

    if (words.getSize() > 0) 
    w = words.get(0); 

    return w; 
} 

// Handles locking to prevent duplicate word creation 
private Word getNewOrSynchronizedWord(String wordStr) { 
    Word w = null; 
    Locks l = em.find(WORDS_CREATE_LOCK_ID, Locks.class); 
    em.lock(l); 

    Word w = getWord(wordStr); 

    if (w == null) { 
    w = new Word(wordStr); 
    em.persist(w); 
    } 

    em.unlock(l); 
    return w; 
} 

la question est-il efficace de cette façon? Et puis-je faire de même sans maintenir une table DB avec des lignes de verrouillage? Peut-être un mécanisme de verrouillage de conteneur Java EE?

Si ça aide, j'utilise JBoss 4.2.


J'ai une nouvelle idée pour cela. Je peux créer deux BDM:

1er MDB avec de nombreux cas autorisés, qui va gérer tous les messages et si le mot ne se trouve pas envoie le mot à la deuxième MDB

2ème MDB avec une seule instance autorisée, traitera les messages en série et permettra la création de nouveaux mots

La meilleure partie: aucune table entière/méthode/verrouillage de processus, la ligne de verrouillage uniquement sur le comptoir mise à jour

Quelle est ça?

Merci.

Répondre

2

Si vous recherchez des performances, pas de verrouillage, etc. Je suggère d'avoir une autre table: (mot, horodatage). Vos MDB insèrent simplement le mot et l'horodatage. Un autre processus compte et met à jour le tableau avec les totaux.

1

Cela ressemble à ce qu'il doit être résolu dans la base de données en choisissant le bon niveau transaction isolation - lecture répétable devrait être suffisant.

Vous avez besoin d'un livre sur les bases de données, axé sur les transactions.

+0

Le niveau d'isolation de REPEATABLE READ n'est pas la solution, car lorsque les deux instances s'exécutent, les requêtes select pour le même mot inexistant retournent toutes deux des lignes zéro et rien n'est verrouillé. Après chaque instance fera insérer avec le même mot. Le niveau d'isolation SERIALIZABLE est préférable car il verrouille les lignes inexistantes (incertaines) avec le nouveau mot mais cela a un impact important sur les performances et peut avoir des problèmes avec Oracle DB. –

1

Voulez-vous dire que plusieurs instances traitent le même message ou que le même mot est utilisé dans différents messages? Si c'est le même message, vous devriez utiliser une file d'attente au lieu d'un sujet. Ceci, bien sûr, ne résout pas la question du même mot dans plusieurs messages. Pour ce cas, vous pouvez suivre les conseils de @Michael Borgwardt et @Vitaly Polonetsky.

Une autre option, en dehors de la base de données, consisterait à faire en sorte que différentes instances MDB gèrent des mots commençant par un ensemble de lettres. Cela pourrait être facilement accompli avec des sélecteurs. Ensuite, il n'y aurait qu'un seul MDB traitant un mot particulier, mais le traitement est toujours réparti entre plusieurs instances pour augmenter les performances. Je ne prétends pas que c'est une meilleure alternative, mais juste une autre qui supporte un traitement basé sur une file d'attente assez simple.

+0

J'ai voulu dire le même mot dans différents messages et c'est une file d'attente MDB. Le "autre avis" est génial, mais existe-t-il une façon J2EE de faire des sélecteurs sur MDB? Je sais que je peux utiliser un sélecteur MDB qui transmettra aux MDB plus spécifiques. Mais encore une fois, je dois être sûr que le MDB spécifique n'a qu'une seule instance (comment? Fonctionne dans un cluster?). –

+0

@ Vitaly Polonetsky - Le sélecteur est un aspect de configuration du déploiement de la MDB, tout comme le nombre d'instances (sessions simultanées de threads) qu'il permettra. Vous pouvez déployer la même MDB plusieurs fois (différents fichiers EAR), mais simplement avoir un sélecteur différent pour chacun d'entre eux et configuré pour n'autoriser qu'une seule session. – Robin

+0

@Robin merci, mais puis-je avoir une instance par sélecteur avec de nombreux sélecteurs sur le même mdb? Ou je dois avoir autant de cours que de sélecteurs? –