As seções a seguir descrevem alguns dos cenários de conflitos mais comuns e sugestões sobre como evitá-los.
A seguinte exceção é exibida como resultado:
com.ibm.websphere.objectgrid.plugins.LockDeadlockException: Message
Essa mensagem representa a cadeia que é transmitida como um parâmetro
quando a exceção é criada e emitida.Descrição: Quando uma transação ou cliente solicita que um bloqueio seja concedido para uma entrada de mapa específica, a solicitação sempre aguarda o cliente atual liberar o bloqueio antes que a solicitação seja enviada. Se a solicitação de bloqueio permanecer inativa por um longo período de tempo, e o bloqueio nunca for concedido, a exceção LockTimeoutException será criada para evitar um conflito, que é descrito com mais detalhes na seção a seguir. É mais provável que esta exceção seja exibida quando usar uma estratégia de bloqueio pessimista porque o bloqueio nunca é liberado antes que transação seja confirmada.
Recuperar mais detalhes:
A exceção LockTimeoutException contém o método getLockRequestQueueDetails, que retorna uma sequência. Este método pode ser usado para ver uma descrição detalhada da situação que aciona a exceção. A seguir há um exemplo de código que captura a exceção e exibe uma mensagem de erro.
try {
...
}
catch (LockTimeoutException lte) {
System.out.println(lte.getLockRequestQueueDetails());
}
lock request queue
−>[TX:163C269E−0105−4000−E0D7−5B3B090A571D, state =
Granted 5348 milli−seconds ago, mode = U]
−>[TX:163C2734−0105−4000−E024−5B3B090A571D, state =
Waiting for 5348 milli−seconds, mode = U]
−>[TX:163C328C−0105−4000−E114−5B3B090A571D, state =
Waiting for 1402 milli−seconds, mode = U]
try {
...
}
catch (ObjectGridException oe) {
Throwable Root = findRootCause( oe );
if (Root instanceof LockTimeoutException) {
LockTimeoutException lte = (LockTimeoutException)Root;
System.out.println(lte.getLockRequestQueueDetails());
}
}
Solução: Uma uma exceção LockTimeoutException evita possíveis conflitos em seu aplicativo. Uma exceção desse tipo resulta quando a exceção aguarda uma quantidade de tempo configurada. É possível configurar a quantidade de tempo que a exceção aguarda usando o método setLockTimeout(int), que está disponível para o BackingMap. Se um conflito não existir realmente no aplicativo, ajuste o tempo limite de bloqueio para evitar a LockTimeoutException.
ObjectGrid objGrid = new ObjectGrid();
BackingMap bMap = objGrid.defineMap("MapName");
bMap.setLockTimeout(30);
Use o exemplo codificado permanentemente para configurar as propriedades do ObjectGrid e do mapa. Se você criar o ObjectGrid a partir de um arquivo XML, configure o atributo LockTimeout dentro do elemento backingMap. A seguir há um exemplo de um elemento backingMap que configura um valor LockTimeout do mapa para 30 segundos.
<backingMap name="MapName" lockStrategy="PESSIMISTIC" lockTimeout="30">
Descrição: Os seguintes cenários descrevem como podem ocorrer conflitos quando uma única chave é acessada utilizando um bloqueio S e posteriormente atualizada. Quando isto acontece em duas transações simultaneamente, o resultado é um conflito.
Encadeamento 1 | Encadeamento 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Cada encadeamento estabelece uma transação independente. |
2 | map.get(key1) | map.get(key1) | O bloqueio S é concedido a ambas as transações para key1. |
3 | map.update(Key1,v) | Nenhum bloqueio U. A atualização é executada no cache transacional. | |
4 | map.update(key1,v) | Nenhum bloqueio U. A atualização é executada no cache transacional | |
5 | session.commit() | Bloqueado: O bloqueio S para key1 não pode ser atualizado para um bloqueio X porque o Encadeamento 2 possui um bloqueio S. | |
6 | session.commit() | Conflito: O bloqueio S para key1 não pode ser atualizado para um bloqueio X porque T1 possui um bloqueio S. |
Encadeamento 1 | Encadeamento 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Cada encadeamento estabelece uma transação independente. |
2 | map.get(key1) | Bloqueio S concedido para key1 | |
3 | map.getForUpdate(key1,v) | O bloqueio S é atualizado para um bloqueio U para key1. | |
4 | map.get(key1) | Bloqueio S concedido para key1. | |
5 | map.getForUpdate(key1,v) | Bloqueado: T1 já possui um bloqueio U. | |
6 | session.commit() | Conflito: O bloqueio U para key1 não pode ser atualizado. | |
7 | session.commit() | Conflito: O bloqueio S para key1 não pode ser atualizado. |
Encadeamento 1 | Encadeamento 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Cada encadeamento estabelece uma transação independente |
2 | map.get(key1) | Bloqueio S concedido para key1. | |
3 | map.getForUpdate(key1,v) | O bloqueio S é atualizado para um bloqueio U para key1 | |
4 | map.get(key1) | O bloqueio S é concedido para key1. | |
5 | map.getForUpdate(key1,v) | Bloqueado: O Encadeamento 1 já possui um bloqueio U. | |
6 | session.commit() | Conflito: O bloqueio U para key1 não pode ser atualizado para um bloqueio X porque o Encadeamento 2 possui um bloqueio S. |
Encadeamento 1 | Encadeamento 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Cada encadeamento estabelece uma transação independente. |
2 | map.getForUpdate(key1) | Bloqueio U concedido para o encadeamento 1 para key1. | |
3 | map.getForUpdate(key1) | O pedido do bloqueio U é bloqueado. | |
4 | map.update(key1,v) | <blocked> | |
5 | session.commit() | <blocked> | O bloqueio U para key1 pode ser atualizado com êxito para um bloqueio X. |
6 | <liberado> | O bloqueio U é finalmente concedido para key1 para o encadeamento 2. | |
7 | map.update(key2,v) | Bloqueio U concedido ao encadeamento 2 para key2. | |
8 | session.commit() | O bloqueio U para key1 pode ser atualizado com êxito para um bloqueio X. |
Descrição: Este cenário descreve o que acontece se duas transações tentarem atualizar a mesma entrada diretamente e manter bloqueios S com outras entradas.
Encadeamento 1 | Encadeamento 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Cada encadeamento estabelece uma transação independente. |
2 | map.get(key1) | map.get(key1) | O bloqueio S é concedido a ambas as transações para key1. |
3 | map.get(key2) | map.get(key2) | Bloqueio S concedido para ambas as transações para key2. |
4 | map.update(key1,v) | Nenhum bloqueio U. Atualização executada no cache transacional. | |
5 | map.update(key2,v) | Nenhum bloqueio U. A atualização é executada no cache transacional. | |
6. | session.commit() | Bloqueado: O bloqueio S para key 1 não pode ser atualizado para um bloqueio X porque o encadeamento 2 possui um bloqueio S. | |
7 | session.commit() | Conflito: O bloqueio S para key 2 não pode ser atualizado porque o encadeamento 1 possui um bloqueio S. |
Encadeamento 1 | Encadeamento 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Cada encadeamento estabelece uma transação independente. |
2 | map.getForUpdate(key1) | Bloqueio U concedido para a transação T1 para key1. | |
3 | map.getForUpdate(key1) | O pedido do bloqueio U é bloqueado. | |
4 | map.get(key2) | <blocked> | Bloqueio S concedido para T1 para key2. |
5 | map.update(key1,v) | <blocked> | |
6 | session.commit() | <blocked> | O bloqueio U para key1 pode ser atualizado com êxito para um bloqueio X. |
7 | <liberado> | O bloqueio U finalmente é concedido para key1 para T2 | |
8 | map.get(key2) | Bloqueio S concedido para T2 para key2. | |
9 | map.update(key2,v) | Bloqueio U concedido para T2 para key2. | |
10 | session.commit() | O bloqueio U para key1 pode ser atualizado com êxito para um bloqueio X. |
Encadeamento 1 | Encadeamento 2 | ||
---|---|---|---|
1 | session.begin() | session.begin() | Cada encadeamento estabelece uma transação independente. |
2 | map.getforUpdate(key1) | map.getForUpdate(key2) | Bloqueios U concedidos com êxito para key1 e key2. |
3 | map.get(key2) | map.get(key1) | Bloqueio S concedido para key1 e key2. |
4 | map.update(key1,v) | map.update(key2,v) | |
5 | session.commit() | O bloqueio U não pode ser atualizado para um bloqueio X porque T2 possui um bloqueio S. | |
6 | session.commit() | O bloqueio U não pode ser atualizado para um bloqueio X porque T1 possui um bloqueio S. |