JPA Demonstração das Estratégias Optimistic Locking e Pessimistic Locking

Documentos relacionados
Criar uma aplicação JPA2 com EclipseLink e H2

JPA Java Persistence API. Prof. Ramon Chiara

Mapeamento Lógico/Relacional com JPA

Mapeamento da herança em JPA

Desenvolvimento para Web em Java. Profa Andréa Schwertner Charão DLSC/CT/UFSM Lamarck Heinsch Mestrando PPGI/CT/UFSM

Introdução. Configuração. Padrão POJO. Framework Pesistência de. Mapeamento Annotation. Objetos. Persistência. Java. Objetos. Prof.

Hibernate na sua aplicação JavaWeb

Sistemas de Bases de Dados 2.º teste (com consulta limitada: 2 folhas identificadas) - Duração: 2 horas

Conexão com Banco de Dados

JPA DAO Genérico e JPQL

Sistemas de Informação e Bases de Dados 2012/2013. Transações. Alberto Sardinha

JPA Com Hibernate. Paulo Ricardo Lisboa de Almeida. 1 Universidade Positivo

Agenda. Instalação e configuração. Processamento de comandos SQL com JDBC. Driver JDBC Criação da classe de conexão

Lock. Administração de Banco de Dados

Só podem ser executados por uma Thread que detenha o lock do objecto

UFG - Instituto de Informática

Java - Conexão ao Banco de Dados usando JDBC

Tecnologias Java JDBC. Marcio Seiji Oyamada

Instituto Federal de Educação, Ciência e Tecnologia de São Paulo - IFSP

Java Persistence Query Language JPQL

Vamos falar de Hibernate?

DATA ACCESS OBJECT (DAO)

GBC043 - Sistemas de Banco de Dados Lab8 : Transações no PostgreSql

JPA: Persistência padronizada em Java

De forma simples, para a execução de comandos SQL com JDBC, precisa-se da instancia de três classes Java. São elas: Nome da classe Função

Lista de Exercícios 12 Transações

Controle de Transação

BDII SQL TRANSAÇÃO Revisão 2


Modificadores de Acesso e Atributos de Classe

Padrão J2EE Data Access Object (DAO)

Sistemas Distribuídos Transações

Threads. O que é uma Thread? Paralelismo

Banco de Dados I 6 Transações e Controle de Concorrência

Orientação a Objetos Básica

Evento.java. package dominio;

Introdução à JPA-Java Persistence API

Introdução. Atributos em Java. Atributos. Acesso à atributos em Java. Atributo versus variável. Atributos, métodos e encapsulamento.

Utilizando Swing com Hibernate

Linguagem de Programação II Implementação

Criação de uma aplicação Web ASP.NET MVC 4

Antes de iniciar execute o script do banco de dados no SQLYOG ou outra ferramenta de sua preferência

Interfaces POO. Prof. Marcio Delamaro

ESQUEMA AULA PRÁTICA 0 Familiarização com o Ambiente de Desenvolvimento NetBeans Construção do primeiro programa em java.

Tipos de dados e comandos POO

CONEXÃO JAVA - BANCO DE DADOS

Introdução a classes e objetos. Prof. Marcelo Roberto Zorzan Prof a. Rachel Reis

Desenvolvimento Web com Java. Sérgio Lopes Caelum -

Programação Orientada a Objetos Classes Abstratas. Sérgio Soares

Simulado de Linguagem de Programação Java

Tratamento de Exceções

1) Responda de acordo com os conceitos de orientação a objetos (0,5).

Publicar uma aplicação ASP.NET Core com base de dados SqlServer no Azure usando Visual Studio e um perfil para publicação (publish profile)

OO Orientação a Objetos

Programação Orientada por Objectos 2010/11. 2º Exame 28 de Junho de 2011

Administração de Banco de Dados

Variáveis primitivas e Controle de fluxo

Array em Java. Figura 1 - Exemplo de um array de inteiros

Programação Estruturada e Orientada a Objetos

OO - Orientação a Objetos

UNIP - Ciência da Computação e Sistemas de Informação. Estrutura de Dados. AULA 5 Pilhas

Consistência e Replicação

Especificam quem tem acesso a cada entidade, isto é, quem tem acesso a. cada classe e cada membro da classe (dados e métodos)

Transcrição:

JPA Demonstração das Estratégias Optimistic Locking e Pessimistic Locking Locking é uma técnica para tratamento de concorrência em transações em bases de dados. Quando duas ou mais transações em bases de dados acedem ao mesmo dado, locking permite assegurar que apenas uma transação de cada vez consegue mudar esse dado. Em JPA há duas estratégias para tratar o locking: optimistic locking pessimistic locking. Como exemplo vamos considerar as atualizações do saldo de uma conta após dois depósitos realizados aproximadamente ao mesmo tempo. programa1 programa2 Inicia transação Inicia transação Lê objeto Lê objeto Efetua depósito 1 Efetua depósito 2 Efetua commit Efetua commit Quando dois programas podem modificar o mesmo dado, se ambos os programas realizam a sequência ler-modificar-escrever de um modo intercalado podem corromper esse dado. Só o último depósito afeta o saldo perdendo-se a primeira modificação. No exemplo que vamos apresentar, uma conta tem o saldo inicial de 100. O programa1 efetua um depósito de 20 e o programa2 efetua um depósito de 30 na mesma conta, realizando as sequências ler-modificar-escrever de um modo intercalado. A primeira modificação do saldo perde-se e só o último depósito afeta o saldo, obtendose o saldo final de 130.

Setup 1. H2 em modo servidor para permitir múltiplas ligações simultâneas Configurar driver na Unidade de Persistência Configurar h2 para modo Servidor preencher JDBC URL com JDBC URL: jdbc:h2:tcp://localhost/~/bd/contas Ficheiro persistence.xml: <?xml version="1.0" encoding="utf-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="jpa2pu" transaction-type="resource_local"> <provider>org.eclipse.persistence.jpa.persistenceprovider</provider> <class>conta</class> <properties> <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/bd/contas"/> <property name="javax.persistence.jdbc.user" value=""/> <property name="javax.persistence.jdbc.driver" value="org.h2.driver"/> <property name="javax.persistence.jdbc.password" value=""/> <property name="javax.persistence.schema-generation.database.action" value="create"/> <property name="eclipselink.logging.level.sql" value="fine"/> <property name="eclipselink.logging.parameters" value="true"/> </properties> </persistence-unit> </persistence> 2. Criar as classes Conta, Iniciar, Util, UtilizadorA e UtilizadorB @Entity public class Conta { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private double saldo; private Conta() { public Conta(double depositoinicial) { this.saldo = depositoinicial; public double getsaldo() { return saldo; public void depositar(double deposito) { saldo += deposito;

public class Iniciar { public static void main(string[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPA2PU"); EntityManager em = emf.createentitymanager(); em.gettransaction().begin(); Conta conta = new Conta(100); em.persist(conta); em.gettransaction().commit(); em.close(); emf.close(); public class Util { public static void parar(string msg) { try { System.out.println(msg); System.in.read(); catch (Exception e) { public class UtilizadorA { public static void main(string[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPA2PU"); EntityManager em = emf.createentitymanager(); em.gettransaction().begin(); Conta conta = em.find(conta.class, 1); Util.parar("A: Saldo=" + conta.getsaldo() + " Continuar?"); conta.depositar(20); Util.parar("A: Saldo=" + conta.getsaldo() + " Continuar?"); em.gettransaction().commit(); em.close(); emf.close(); System.out.println("A (Fim) - Saldo: " + conta.getsaldo()); public class UtilizadorB { public static void main(string[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPA2PU"); EntityManager em = emf.createentitymanager(); em.gettransaction().begin(); Conta conta = em.find(conta.class, 1); Util.parar("B: Saldo=" + conta.getsaldo() + " Continuar?"); conta.depositar(30); Util.parar("B: Saldo=" + conta.getsaldo() + " Continuar?"); em.gettransaction().commit(); em.close(); emf.close(); System.out.println("B (Fim) - Saldo: " + conta.getsaldo());

3. Iniciar h2 em modo servidor h2: h2\bin\h2.bat 4. Executar o método main da classe Iniciar A base de dados é criada. 5. Inspecionar a base de dados criada usando a página H2 Console Sem Locking 6. Executar intercaladamente os métodos main da classe UtilizadorA e da classe UtilizadorB. Aplicação funciona incorretamente: Só o último depósito afeta o saldo perdendo-se a primeira modificação. Numa conta com o saldo de 100 são efetuados dois depósitos, um de 20 e outro de 30, resultando num saldo final de apenas 130.

Com Optimistic Locking Para usar a estratégia otimista é necessário adicionar uma propriedade dedicada à persistência para guardar na base de dados o número da versão da entidade. @Entity public class Conta { @Version private int versionid = 1; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private double saldo; private Conta() { public Conta(double depositoinicial) { this.saldo = depositoinicial; public double getsaldo() { return saldo; public void depositar(double deposito) { saldo += deposito; Este campo de dados versão: Não deve ser modificado pela aplicação Pode ser numérico ou timestamp mas um valor numérico é recomendado É definido pela anotação @Version No commit da transação a coluna versão da entidade: Na estratégia optimistic é incrementada se o estado da entidade mudou durante a transação Na estratégia optimistic_force_increment é incrementada mesmo se o estado da entidade não mudou durante a transação Em qualquer uma das duas estratégias otimistas, se no commit da transação, a entidade tem na base de dados uma versão diferente da versão que tinha quando foi carregada, uma exceção OptimisticLockException é lançada, significando que outro programa entretanto modificou a entidade. Podemos apanhar esta exceção e decidir o que fazer. O locking otimista deixa transações concorrentes processar simultaneamente, permitindo ler e atualizar uma entidade, mas deteta colisões, verificando no commit se a versão foi atualizada na base de dados desde que a entidade foi lido, caso em que lança uma exceção.

A estratégia otimista deve ser usada quando se assume que a maior parte das transações concorrentes não entram em conflito. As vantagens desta estratégia são não necessitar de colocar locks na base de dados o que dá melhor escalabilidade. A desvantagem é que a aplicação deve refrescar e voltar a tentar atualizações que falhem. Locking de uma entidade Existem 5 tipos de locking: OPTIMISTIC OPTIMISTIC_FORCE_INCREMENT PESSIMISTIC_READ PESSIMISTIC_WRITE PESSIMISTIC_FORCE_INCREMENT 7. Classe Conta com atributo version Alteração apenas da classe Conta para inclusão do atributo version. Sem try catch Necessário criar novamente a base de dados porque agora a tabela Conta tem mais uma coluna (versionid) Executar intercaladamente os métodos main da classe UtilizadorA e da classe UtilizadorB Aplicação funciona incorretamente Programa termina com exceção lançada.

Método main do UtilizadorB: UPDATE CONTA SET SALDO =?, VERSIONID =? WHERE ((ID =?) AND (VERSIONID =?)) bind => [130.0, 2, 1, 1] Este método main termina com exceção lançada: The object [jpa2.conta@d109c4f] cannot be updated because it has changed or been deleted since it was last read. Só o primeiro depósito afeta o saldo perdendo-se a última modificação. Nesta versão do programa duas transações concorrentes tentam atualizar o saldo de um objeto conta. No commit da primeira transação JPA incrementa o atributo versionid da conta na base de dados. Quando a segunda transação efetua o commit, JPA lança uma exceção OptimisticLockException porque o atributo versionid da entidade conta é diferente do valor que tinha quando a entidade conta foi lida, e a transação é rolled back. A aplicação deve refrescar e voltar a tentar efetuar updates que falham. Com try catch public class UtilizadorC { public static void main(string[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPA2PU"); EntityManager em = emf.createentitymanager();

boolean depositado = false; do { try { em.gettransaction().begin(); Conta conta = em.find(conta.class, 1); Util.parar("C: Saldo=" + conta.getsaldo() + " Continuar?"); conta.depositar(20); Util.parar("C: Saldo=" + conta.getsaldo() + " Continuar?"); em.gettransaction().commit(); depositado = true; catch (final Exception e) { System.out.println("Saldo mudou desde que foi lido. Tente outra vez."); while (!depositado); em.close(); emf.close(); public class UtilizadorD { public static void main(string[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPA2PU"); EntityManager em = emf.createentitymanager(); boolean depositado = false; do { try { em.gettransaction().begin(); Conta conta = em.find(conta.class, 1); Util.parar("C: Saldo=" + conta.getsaldo() + " Continuar?"); conta.depositar(30); Util.parar("C: Saldo=" + conta.getsaldo() + " Continuar?"); em.gettransaction().commit(); depositado = true; catch (final Exception e) { System.out.println("Saldo mudou desde que foi lido. Tente outra vez."); while (!depositado); em.close(); emf.close(); Executar intercaladamente os métodos main da classe UtilizadorC e da classe UtilizadorD Aplicação funciona corretamente

Output do método main de UtilizadorD: SELECT ID, SALDO, VERSIONID FROM CONTA WHERE (ID =?) bind => [1] C: Saldo=100.0 Continuar? C: Saldo=130.0 Continuar? UPDATE CONTA SET SALDO =?, VERSIONID =? WHERE ((ID =?) AND (VERSIONID =?)) bind => [130.0, 2, 1, 1] org.eclipse.persistence.exceptions.optimisticlockexception Exception Description: The object [jpa2.conta@3023df74] cannot be updated because it has changed or been deleted since it was last read. Saldo mudou desde que foi lido. Tente outra vez. SELECT ID, SALDO, VERSIONID FROM CONTA WHERE (ID =?) bind => [1] C: Saldo=120.0 Continuar? C: Saldo=150.0 Continuar? UPDATE CONTA SET SALDO =?, VERSIONID =? WHERE ((ID =?) AND (VERSIONID =?)) bind => [150.0, 3, 1, 2] A aplicação funciona corretamente. O primeiro depósito é efetuado, o segundo depósito lança a exceção OptimisticLockException, mas a aplicação volta a tentar e efetua corretamente o segundo depósito. Ao adicionar o atributo version a uma entidade, JPA usa, por omissão, a estratégia Optimistic Locking, se nenhuma outra estratégia é configurada.

Com Pessimistic Locking 8. Configurar as aplicaçãoes com a estratégia pessimistic locking O lock numa entidade é colocado pelo EntityManager (em). Pode ser especificado com um dos seguintes valores: LockModeType.OPTIMISTIC LockModeType.OPTIMISTIC_FORCE_INCREMENT LockModeType.PESSIMISTIC_READ LockModeType.PESSIMISTIC_WRITE LockModeType.PESSIMISTIC_FORCE_INCREMENT Pode ser colocado: Quando a entidade é carregada da base de dados através do método find Conta conta = em.find(conta.class, contapk, LockModeType.PESSIMISTIC_WRITE); Através do método refresh em.refresh(conta, LockModeType.PESSIMISTIC_WRITE); Quando carregada através de uma query: Query query = em.createquery(...); query.setlockmode(lockmodetype.pessimistic_write); Depois de ser carregada da base de dados: em.lock(conta, LockModeType. PESSIMISTIC_WRITE); O modo lock de uma entidade pode ser obtido: LockModeType modolock = em.getlockmode(entity); No locking pessimistic, em vez de esperar até ao commit da transação, na esperança de que nenhuma outra transação tenha mudado os dados, um lock na base de dados é obtido imediatamente. Assim a transação nunca falha, contudo também não permite execução paralela de transações. O locking pessimistic é efetuado ao nível da base de dados enquanto o locking optimistic é efetuado ao nível da entidade. Locks pessimistas são propagados para a base de dados usando queries SQL. Se existe um lock pessimista, a aplicação espera pela base de dados até o lock ser liberto, não lançando exceção. public class UtilizadorA { public static void main(string[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPA2PU");

EntityManager em = emf.createentitymanager(); em.gettransaction().begin(); Conta conta = em.find(conta.class, 1); em.lock(conta, LockModeType.PESSIMISTIC_WRITE); Util.parar("A: Saldo=" + conta.getsaldo() + " Continuar?"); conta.depositar(20); Util.parar("A: Saldo=" + conta.getsaldo() + " Continuar?"); em.gettransaction().commit(); em.close(); emf.close(); public class UtilizadorB { public static void main(string[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPA2PU"); EntityManager em = emf.createentitymanager(); em.gettransaction().begin(); Conta conta = em.find(conta.class, 1); em.lock(conta, LockModeType.PESSIMISTIC_WRITE); Util.parar("B: Saldo=" + conta.getsaldo() + " Continuar?"); conta.depositar(30); Util.parar("B: Saldo=" + conta.getsaldo() + " Continuar?"); em.gettransaction().commit(); em.close(); emf.close(); Executar intercaladamente os métodos main da classe UtilizadorA e da classe UtilizadorB UtilizadorA: SELECT ID, SALDO, VERSIONID FROM CONTA WHERE (ID =?) FOR UPDATE bind => [1] UtilizadorB: SELECT ID, SALDO, VERSIONID FROM CONTA WHERE (ID =?) FOR UPDATE bind => [1] org.h2.jdbc.jdbcsqlexception: Timeout trying to lock table. Caused by: org.h2.jdbc.jdbcsqlexception: Concurrent update in table "CONTA": another transaction has updated or deleted the same row [90131-194] Caused by: java.lang.illegalstateexception: Entry is locked [1.4.194/101]

O método main da classe UtilizadorB termina com exceção lançada devido a Timeout. A ligação (EntityManager) deste programa não consegue obter um lock na base de dados porque outra ligação (EntityManager de UtilizadorA) mantém o lock. Para obter o lock seria necessário que a ligação do utilizadora libertasse o lock durante o lock timeout cujo valor, por omissão, é 1000 ms. O lock timeout pode ser colocado individualmente para cada ligação ou para toda a aplicação na Persistence Unity : <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/bd/contas;lock_timeout=80000"/> Ficheiro persistence.xml: <?xml version="1.0" encoding="utf-8"?> <persistence version="2.1"... > <persistence-unit name="jpa2pu" transaction-type="resource_local"> <provider>org.eclipse.persistence.jpa.persistenceprovider</provider> <class>jpa2.conta</class> <properties> <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/bd/contas;lock_timeout=80000"/> <property name="javax.persistence.jdbc.user" value=""/> <property name="javax.persistence.jdbc.driver" value="org.h2.driver"/>... </properties> </persistence-unit> </persistence> Agora as aplicações funcionam corretamente Começamos por executar a classe Iniciar para colocar o objeto conta com a versão 1

Em seguida executamos intercaladamente os métodos main da classe UtilizadorA e da classe UtilizadorB, mas a classe UtilizadorB não consegue avançar porque não consegue obter um lock na base de dados UtilizadorA: SELECT ID, SALDO, VERSIONID FROM CONTA WHERE (ID =?) FOR UPDATE bind => [1] UPDATE CONTA SET SALDO =?, VERSIONID =? WHERE ((ID =?) AND (VERSIONID =?)) bind => [120.0, 2, 1, 1] Após a ligação do UtilizadorA libertar o lock na base de dados, o programa do UtilizadorB avança. UtilizadorB: SELECT ID, SALDO, VERSIONID FROM CONTA WHERE (ID =?) FOR UPDATE bind => [1] UPDATE CONTA SET SALDO =?, VERSIONID =? WHERE ((ID =?) AND (VERSIONID =?)) bind => [150.0, 3, 1, 2]

A principal vantagem de usar pessimistic locking é a garantia de que, uma vez o lock obtido, a edição terá sucesso. Útil em aplicações altamente concorrentes nas quais optimistic locking poderia causar muitos erros de locking optimistic. Uma desvantagem de usar pessimistic locking é que necessita de recursos adicionais da base de dados, obrigando a transação e a ligação à base de dados serem mantidas durante a edição. Locking na base de dados H2 H2 permite múltiplas ligações concorrentes à mesma base de dados. Para garantir que todas as ligações vejam sempre os dados consistentes, H2 usa, por omissão, locking ao nível da tabela. H2 usa 2 tipos de locks: read locks ou shared locks write locks ou exclusive locks Geração de locks: Instruções SELECT geram locks read Instruções que modificam os dados geram locks write A instrução SELECT FOR UPDATE coloca um lock write na tabela sem modificar os dados As instruções COMMIT e ROLLBACK libertam todos os locks Antes da leitura de um ou mais registos de uma tabela, a base de dados tenta adicionar um shared lock à tabela, o que só é possível se a tabela não tem um exclusive lock. Se o shared lock é adicionado com sucesso, a tabela pode ser lida. Outras ligações podem também obter um shared lock na mesma tabela. Se há um lock exclusive (write) na tabela, então a ligação que quer ler da tabela espera até que a outra ligação liberte o lock exclusive.

Antes da escrita numa tabela (atualizar ou apagar uma linha) é necessário obter um exclusive lock. Para obter um exclusive lock, nenhuma outra ligação pode ter qualquer lock na tabela. Se uma ligação não consegue obter o lock durante um tempo específico, então uma exceção timeout é lançada. O timeout por omissão é 1 segundo (1000 ms). Por omissão H2 usa o nível de isolamento transacional read committed : os locks read são libertos imediatamente após cada instrução os locks write são libertos quando a transação efetua o commit ou o rollback Resumo: Na estratégia otimista, que obriga a entidade a ter versão, JPA compara o número da versão desse objeto na base de dados com o número da versão do objeto em memória. Se os números das versões são diferentes, o que indica que o objeto já foi modificado por outro EntityManger, a transação falha e uma exceção OptimisticLockException é lançada. Para evitar corrupção dos dados é necessário verificar se há colisões entre programas, isto é, se há sequências ler, modificar, escrever intercaladas. Versão na entidade Lock Colisão entre programas Sem lock, lock NONE Não há verificação Exceção Sem versão PersistenceException Com versão Lock OPTIMISTIC, OPTIMISTIC_FORCE_INCREMENT, PESSIMISTIC_FORCE_INCREMENT Lock PESSIMISTIC_READ, PESSIMISTIC_WRITE Sem lock, lock NONE, OPTIMISTIC, OPTIMISTIC_FORCE_INCREMENT Lock PESSIMISTIC_READ, PESSIMISTIC_WRITE, PESSIMISTIC_FORCE_INCREMENT Nunca há colisão Exceção OptimisticLockException Nunca há colisão Mensagens das exceções: PersistenceException: Invalid lock mode type on for an entity that does not have a version locking index. Only a PESSIMISTIC lock mode type can be used when there is no version locking index. OptimisticLockException Exception Description: The object [model.conta@229c0fa6] cannot be updated because it has changed or been deleted since it was last read.

Resumo dos passos na execução da Demonstração das Estratégias Optimistic Locking e Pessimistic Locking Numa conta com o saldo de 100 são efetuados dois depósitos. Um programa efetua um depósito de 20 e outro programa efetua um depósito de 30. As sequências ler-modificarescrever são realizadas intercaladamente. 1 Classe Conta sem atributo Version. Programas sem qualquer estratégia de locking. Aplicação funciona incorretamente. A primeira modificação do saldo perde-se e só o último depósito afeta o saldo, obtendo-se o saldo final de 130. 2 Classe Conta com atributo Version. Programas sem qualquer estratégia de locking. JPA usa, por omissão, a estratégia Optimistic Locking. Aplicação funciona incorretamente. A primeira modificação do saldo é efetuada, mas a execução do segundo depósito lança a exceção OptimisticLockException. 3 Classe Conta com atributo Version. Programas sem qualquer estratégia de locking mas com try catch. Aplicação funciona corretamente. O primeiro depósito é efetuado, o segundo depósito lança a exceção OptimisticLockException, mas a aplicação volta a tentar e efetua corretamente o segundo depósito. 4 Classe Conta com ou sem atributo Version. Programas com a estratégia Pessimistic Locking e sem try catch. Aplicação funciona incorretamente. O primeiro depósito é efetuado porque obtém um lock exclusivo na tabela da base de dados. O segundo depósito tenta obter um lock exclusivo, pelo que espera até o lock da tabela ser liberto. Como o lock timeout, por omissão, é 1 segundo, ao fim deste tempo a execução do segundo depósito lança a exceção JdbcSQLException. 5 Classe Conta com ou sem atributo Version. Programas com a estratégia Pessimistic Locking e sem try catch. Lock Timeout colocado com o valor de 80 segundos na Persistence Unity. Aplicação funciona corretamente. O primeiro depósito é efetuado porque obtém um lock exclusivo na tabela da base de dados. O segundo depósito tenta obter um lock exclusivo, pelo que espera até o lock da tabela ser liberto. Obtém o lock exclusivo e efetua o depósito.