• Nenhum resultado encontrado

Transações e concorrência

N/A
N/A
Protected

Academic year: 2022

Share "Transações e concorrência"

Copied!
37
0
0

Texto

(1)

Transações e concorrência

Jobson Ronan

{jrjs@cin.ufpe.br}

(2)

O que é uma transação?

Uma transação é uma unidade de trabalho que não pode ser dividida. É uma operação atômica.

Há dois níveis de granularidade em

aplicações corporativas

Transações de banco de dados

Transações longas (de aplicação): envolvem

várias transações de banco de dados

Uma transação ou termina com sucesso

(commit) ou desfaz todo o processo (rollback)

A maior parte da

complexidade de se lidar com transações é ocultada pelo sistema (Hibernate, servidor de aplicações, banco de dados)

O trabalho consiste,

geralmente, em demarcar o início e fim das transações

(3)

Transações em servidores

Demarcar transações em uma aplicação JDBC é fácil.

Basta configurar a Conexão conn com da seguinte forma

conn.setAutoCommit(false);

Os statements executados serão acumulados e só serão tornados definitivos no banco após um

conn.commit()

Ou serão desfeitos caso ocorra um conn.rollback()

Em servidores de aplicação, ou quando é preciso

realizar transações entre vários bancos, é preciso usar o protocolo Two-phase commit, que gerencia o

processo

Para isto existe a API JTA e a classe UserTransaction que encapsula transações distribuídas

(4)

Tratamento de transações em Hibernate

Session session = sessions.openSession();

Transaction tx = null;

try {

tx = session.beginTransaction();

concludeAuction();

tx.commit();

} catch (Exception e) { if (tx != null) { try {

tx.rollback();

} catch (HibernateException he) { //log he and rethrow e

} }

throw e;

} finally { try {

session.close();

} catch (HibernateException he) { throw he; } }

Executado dentro da transação

(5)

Transações no Hibernate

O Hibernate encapsula o sistema de transações do

banco (JDBC) ou servidor (ambiente gerenciado) usado

A transação começa na Session com uma chamada para session.beginTransaction()

Em um ambiente não gerenciado, isto inicia uma transação JDBC na conexão.

Em um ambiente gerenciado, inicia uma transação JTA ou une- se à transação existente.

Commit e rollback. Em uma transação Transaction tx:

tx.commit() sincroniza o estado da sessão com o banco de dados.

tx.rollback() ou desfaz imediatamente a transação ou marca a transação para rollback.

É importante fechar a sessão em um bloco finally para garantir que a conexão JDBC será liberada e retornada ao pool de conexões.

(6)

Flushing (descarregando)

O objeto Session implementa "transparent write behind“

Mudanças ao modelo de domínio não são imediatamente persistidas no banco (para reduzir acesso ao banco)

Gravação/sincronização transparente dos dados no final da transação.

Flushing é a sincronização da camada de objetos com a camada de dados. Ocorre quando

Uma transação é cometida

Às vezes, antes que uma query é executada

Quando a aplicação chama explicitamente

session.flush()

(7)

Isolamento

Bancos de dados e sistemas transacionais tentam garantir isolamento entre transações

Isolamento completo é uma utopia.

É muito caro em termos de escalabilidade da aplicação.

Bancos de dados fornecem vários graus de flexibilização de isolamento

Variam de isolamento completo a isolamento

praticamente inexistente (neste caso, cabe à aplicação lidar com os conflitos)

Para a maior parte das aplicações, isolamento

incompleto de uma transação é aceitável

(8)

Problemas de isolamento

O padrão ANSI SQL define os níveis de isolamento de transações em termos de fenômenos que podem ou não serem

permitidos. Os fenômenos são:

Update perdido (lost update)

Duas transações ambas atualizam um registro e a segunda transação aborta, fazendo com que as duas mudanças sejam perdidas.

As transações concorrentes não têm isolamento algum.

Leitura suja (dirty read)

Uma transação lê mudanças feitas por transação que ainda não cometeu os dados.

Essa mudança pode ser desfeita em um rollback.

(9)

Problemas de isolamento

Leitura não-repetível (unrepeatable read)

Uma transação lê um registro duas vezes e obtém um estado diferente em cada leitura.

Outra transação pode ter gravado dados e cometido mudanças entre as duas leituras

Leitura fantasma (phantom read)

Uma transação executa uma consulta duas vezes, e o segundo resultado inclui registros que não estavam na primeira consulta.

Novos registros foram inseridos por outra

transação entre as consultas.

(10)

Níveis de isolamento JDBC

JTA usa esses mesmos níveis de isolamento

Read uncommitted

Permite dirty reads mas não updates perdidos.

Uma transação não pode gravar em um registro se outra transação não cometida já gravou

dados nele.

Este nível de isolamento pode ser implementado com locks de gravação exclusiva.

Read committed

Permite unrepeatable reads mas não dirty reads.

Transação de gravação não cometida impede que outras transações acessem registro.

Transações de leitura não bloqueiam o sistema.

(11)

Níveis de isolamento JDBC

Repeatable read

Não permite unrepeatable reads nem dirty reads.

Podem ocorrer phantom reads.

Transações de leitura bloqueiam transações de gravação (mas não outras transações de

leitura) e transações de gravação bloqueiam todas as outras.

Serializable

Fornece o isolamento mais rigoroso.

Emula execução em série de transações (em

vez de concorrentemente).

(12)

Qual nível de isolamento?

A escolha do nível de isolamento depende do cenário onde a aplicação executa.

Não existe uma regra que sirva para todas as situações.

Qual um nível razoável de isolamento para aplicações típicas?

Isolamento excessivo geralmente não é aceitável, devido ao alto custo quanto à escalabilidade (crítica nas aplicações típicas do Hibernate), portanto o isolamento serializable não deve ser usado

O isolamento read uncommitted é perigoso, e não deve ser usado se houver opções melhores no banco

Suporte a versioning (travas otimistas) e uso do cache de segundo nível (por classe) do Hibernate já alcançam a maior parte dos benefícios de um isolamento do tipo repeatable read, usando read committed.

Portanto, read committed é uma boa opção com o Hibernate.

(13)

Como mudar o nível de isolamento default?

É preciso definir uma propriedade no

hibernate.properties ou hibernate.cfg.xml. Use:

hibernate.connection.isolation=numero

onde número é 1, 2, 4 ou 8. Exemplo:

hibernate.connection.isolation = 4

O número refere-se a um dos quatro níveis:

1—Read uncommitted isolation

2—Read committed isolation

4—Repeatable read isolation

8—Serializable isolation

Só é possível fazer esse controle em ambientes não gerenciados

Servidores de aplicação têm configuração própria.

(14)

Estratégias de isolamento locais

Nível de isolamento global afeta todas as conexões

Read committed é um bom isolamento default para aplicações Hibernate

Mas pode ser desejável utilizar travas mais rigorosas para transações específicas

Existem duas estratégias

Travas pessimistas (evita colisões entre

transações bloqueando totalmente o acesso de outras transações)

Travas otimistas (onde o sistema flexibiliza o

isolamento mas lida com eventuais colisões)

(15)

Travas pessimistas

Uma trava pessimista é adquirida quando dados são lidos e mantidos isolados de outras transações até que a sua transação complete.

Em modo read-committed, o banco de dados nunca adquire travas pessimistas a não ser que sejam requisitadas

explicitamente

Classe LockMode

Permite a solicitação de uma trava pessimista em um objeto

Considere a seguinte transação

Transaction tx = session.beginTransaction(); Category cat = (Category) session.get(Category.class, catId); cat.setName("New Name");

tx.commit();

Uma trava pessimista pode ser obtida da seguinte forma:

Transaction tx = session.beginTransaction(); Category cat = (Category) session.get(Category.class, catId, LockMode.UPGRADE); cat.setName("New Name");

tx.commit();

(16)

Controle de LockMode

Os modos suportados para LockMode são:

NONE - Só vai ao banco se o objeto não estiver no cache.

Default em load() e get()

READ - Ignora cache e faz verificação de versão para assegurar-se que o objeto na memória é o mesmo que está no banco.

UPDGRADE - Ignora cache, faz verificação de versão (se aplicável) e obtém trava pessimista (se suportada).

UPDGRADE_NOWAIT - Mesmo que UPGRADE, mas desabilita a espera por liberação de travas, e provoca exceção de locking se a trava não puder ser obtida.

WRITE - Obtida automaticamente quando Hibernate grava em um registro na transação atual

(17)

Controle de LockMode

Sincronização de objeto desligado se registro não foi alterado por outra

transação.

Item item = ... ; Bid bid = new Bid();

item.addBid(bid);

...

Transaction tx = session.beginTransaction();

session.lock(item, LockMode.READ);

tx.commit(); Caching é

considerada uma solução melhor que travas pessimistas.

Evite usar LockMode explícito a não ser que realmente seja necessário.

(18)

Transações longas (de aplicação)

Processos de negócio

Podem ser consideradas uma única unidade de trabalho do ponto de vista de um usuário.

Transação de baixa granularidade.

Uma noção mais abrangente da unidade de trabalho.

Exemplo de cenário típico

1) Dados são recuperados e mostrados na tela em uma primeira transação do banco

2) O usuário tem uma oportunidade de visualizar e modificar os dados, fora de uma transação

3) As modificações são feitas persistentes em uma segunda transação de banco de dados

(19)

Como lidar com as colisões?

Três estratégias

Último commit ganha - os dois updates funcionam, mas o segundo sobrescreve as alterações do primeiro. Nenhuma mensagem de erro é mostrada.

Primeiro commit ganha - a primeira modificação é feita persistente, e o usuário que envia a segunda recebe uma mensagem de erro. Optimistic locking.

Mesclar updates conflitantes - A primeira modificação é persistida, e a segunda pode ser aplicada seletivamente pelo usuário.

A primeira opção é problemática para várias aplicações

É importante que o usuário pelo menos saiba do erro

Acontece por default.

Hibernate ajuda a implementar as outras duas estratégias usando controle de versões e travas otimistas.

(20)

Uso de managed versioning (controle de versão)

Depende de que um número seja incrementado sempre que um objeto é modificado.

public class Comment { ...

private int version; ...

void setVersion(int version) {this.version = version;}

int getVersion() {return version;}

}

No arquivo de mapeamento, <version> vem logo depois de <id>

<class name="Comment" table="COMMENTS">

<id ...

<version name="version" column="VERSION"/>

...

</class>

O número de versão é só um contador. Não tem outra utilidade.

Uma alternativa é usar um timestamp

(21)

Timestamp

Alternativa ao <version>. Exemplo:

public class Comment { ...

private Date lastUpdated;

void setLastUpdated(Date lastUpdated) { this.lastUpdated = lastUpdated;

}

public Date getLastUpdated() {return lastUpdated;}

}

Mapeamento

<class name="Comment" table="COMMENTS">

<id .../>

<timestamp name="lastUpdated" column="LAST_UPDATED"/>

...

</class>

Em tese, um timestamp é menos seguro pois

duas transações concorrentes poderiam tentar

load e update no mesmo milisegundo.

(22)

Travas otimistas

O Hibernate controla a inicialização e

gerenciamento de

<version>

e

<timestamp>

automaticamente.

Esses recursos permitem o eficiente gerenciamento de colisões que implementam a estratégia de trava otimista.

StaleObjectStateException

é lançado em caso de inconsistência

Otimistas versus Pessimistas

Enfoque pessimista assume que serão constantes

os conflitos e o ideal é bloquear completamente o acesso. Não ultrapassa os limites de uma sessão

Enfoque otimista assume que conflitos serão

raros e quando eles acontecerem, é possível lidar

com eles. Garante maior escalabilidade e suporta

transações longas.

(23)

Granularidade de uma Sessão

Session-per-request

Uma sessão tem a mesma granularidade de uma

transação

Session-per-request-with- detached-objects

Objetos são modificados entre duas sessões

Uma transação por sessão

Objetos desligados

Session-per-application- transaction

Sessão longa

Objetos mantêm-se persistentes

(24)

Cache

O cache é uma cópia local dos dados.

Fica entre sua aplicação e o banco de dados.

O cache evita acesso ao banco sempre que

A aplicação faz uma pesquisa por chave primária ou

A camada de persistência resolve uma associação usando estratégia lazy

Podem ser classificados quanto ao escopo:

Escopo de transação - cada unidade de trabalho tem seu próprio cache; vale enquanto a transação está

rodando.

Escopo de processo - o cache é compartilhado entre transações (há implicações quanto ao isolamento)

Escopo de cluster - compartilhado entre processos na mesma máquina ou entre múltiplas máquinas de um cluster.

(25)

Cache no Hibernate

Dois níveis

Primeiro nível tem escopo de transação.

Segundo nível é opcional e tem nível de processo ou cluster.

O primeiro nível é a Session.

Uma session ou tem a duração de uma transação de banco de dados ou de uma transação de aplicação longa.

Não pode ser desligada.

Garante identidade do objeto dentro da transação.

O segundo nível é cache de estado (valores; não instâncias)

É opcional

Pode ser configurado por classe ou por associação.

(26)

Primeiro e segundo cache

Cache de primeiro nível

Automático (Session)

Usado sempre que se passa um objeto para save(), update(), saveOrUpdate() ou quando ele é requisitado com load(),

find(), list(), iterate(), ou filter()

Garante que quando uma aplicação requisita o mesmo objeto persistente duas vezes numa sessão, ela recebe de volta a mesma instância.

Cache de segundo nível

Instâncias persistentes são desmontadas (é como serialização, mas o algoritmo é mais rápido).

Requer conhecimento sobre os dados para uso eficiente (não é automático – as classes são mapeadas ao cache uma por uma)

Se dados são mais freqüentemente atualizados que lidos, não habilite o cache de segundo nível

Requer configuração fina em gerente de cache para melhor performance

(27)

Resumo: tags de mapeamento

 <version>

Usado em implementação de

transações longas, para sinalizar que uma tabela/objeto está sendo alterada

 <cache>

Usado para definir política de cache de

segundo nível

(28)

Propriedades: transação e cache

hibernate.cache.provider_class=nome.da.Classe

Usa um cache provider próprio em substituição ao nativo usado pelo Hibernate (implementação de

org.hibernate.cache.CacheProvider)

hibernate.transaction.factory_class=nome.da.Classe

Para definir um gerente de transações próprio, ou

org.hibernate.transaction

.<nome> para usar uma implementação disponível, onde <nome> pode ser

JBossTransactionManagerLookup

WeblogicTransactionManagerLookup

WebSphereTransactionManagerLookup

OrionTransactionManagerLookup

ResinTransactionManagerLookup

JOTMTransactionManagerLookup

JOnASTransactionManagerLookup

...

Propriedades para

hibernate.prop erties ou

hibernate.cfg.x ml

(29)

Boas Práticas

Usar sempre o padrão facade

...mas como englobar várias operações a

a vários DAOs em uma transação?

(30)

Classe utilitária simples

public class HibernateUtil {

private static final SessionFactory sessionFactory;

static { try {

Configuration cfg = new Configuration();

sessionFactory =

cfg.configure().buildSessionFactory();

} catch (Throwable ex) {

ex.printStackTrace(System.out);

throw new ExceptionInInitializerError(ex);

} }

//...

}

(31)

Classe utilitária simples

//..

private static Session session;

public static Session getSession() { try {

if (session == null || !session.isOpen()) {

SessionFactory factory = getSessionFactory();

session = factory.openSession();

}

return session;

} catch (Exception e) {

throw new RuntimeException(e);

} } //...

(32)

Classe utilitária simples

 Suporte transacional

//..

private static Transaction transaction;

public static void beginTransaction() {

transaction = getSession().beginTransaction();

}

public static void commit() { if (transaction != null) transaction.commit();

}

public static void rollback() { if (transaction != null)

transaction.rollback();

} //...

(33)

Usando

Todo DAO, quando precisar de uma Sessão, irá obte-la através do

getSession()

Para que vários DAOs obtenham a mesma sessão, basta não fecha-la

A fachada pode gerencar a transação

com os metodos begin, commit e rollback

Os DAOs não gerencia, mais as transações

...Mas se a houver acesso concorrente

(34)

Classe utilitária com suporte a concorrencia

//..

private static final ThreadLocal<Session> localSession = new ThreadLocal<Session>();

public static Session getSession() { try {

Session session = localSession.get();

if (session == null || !session.isOpen()) {

SessionFactory factory = getSessionFactory();

session = factory.openSession();

localSession.set(session);

}

return session;

} catch (Exception e) {

throw new RuntimeException(e);

} } //...

(35)

Classe utilitária com suporte a concorrencia

//..

private static final ThreadLocal<Transaction> localTx = new ThreadLocal<Transaction>();

public static void beginTransaction() {

localTx.set(getSession().beginTransaction());

}

public static void commit() { if (localTx.get() != null) localTx.get().commit();

}

public static void rollback() { if (localTx.get() != null) localTx.get().rollback();

} //...

(36)

Exercício

Criar o modelo de Objetos analisando o schema do banco legado

script.sql

Criar criar DAOs e fachada para a aplicação

Criar methodos de negício para

Realizar uma reserva

Agendar uma reserva

Cancelar uma reserva

(37)

Transações e concorrência

Jobson Ronan

{jrjs@cin.ufpe.br}

Referências

Documentos relacionados

A pesquisa de caráter qualitativo, permeada pelo estudo exploratório, analisa o texto prefacial com amparo de Bardin (2004), identificando as inserções no prefácio direcionadas

Pulgão: iniciar os tratamentos preventivamente ou após surgirem os primeiros pulgões, fazendo no máximo 2 aplicações com intervalos de 7 dias, procurando sempre

A aprovação de contra reformas no atual governo, medidas e projetos aprovados pelo congresso nacional e pelo poder judiciário com a aplicação da contrarreforma

A presente Seleção Interna visa ao provimento do cargo de Assistente Técnico – (código DAS 102.1) da Coordenação-Geral de Despesas com Pessoal e Sentenças - CGDPS, vinculada

Miguel e Lobo, Fernando da Graça Editorial Presença, 1993. Integrais em Variedades

 10 – Aglomerações Industriais: Vantagens e desvantagens: A existência de infraestrutura de serviços públicos, transporte, suprimentos de energia e outros

Primeiro Ministro muito especialmente, associar a presença do Chefe do Governo nesta cerimónia à qualidade e ao mérito do caminho que o Ensino Superior Português vem traçando:

Na [figura 2], os macro componentes da prática são conceitualizados como os discursos dominantes e estruturas da estratégia que podem ser considerados como provedores do