(Parte 5 de 13)

ROLLBACK [WORK] TO [SAVEPOINT] <identificador>;

Esta declaração executa as seguintes operações: - Rollback das alterações executadas na transação após o SAVEPOINT

- Destrói todos os SAVEPOINTs criados após este SAVEPOINT. Este SAVEPOINT é mantido, para que você possa fazer um rollback para o mesmo SAVEPOINT múltiplas vezes. Os SAVEPOINTs anteriores a este também serão mantidos.

- Libera todos os locks obtidos implícita e explicitamente após o SAVEPOINT. Outras transações que tenham requerido acesso a linhas que estavam protegidas pelas alterações efetuadas após a criação do SAVEPOINT terão que continuar aguardando que a transação termine, por commit ou rollback. Outras transações, que não tivessem requerido ainda estas linhas, poderão requerer e acessa-las imediatamente. Nota: este comportamento pode ser alterado em futuras versões.

v.1.08 Notas da Versão Firebird 1.5 08 fevereiro 2004 Página 16

O “undo log” do SAVEPOINT pode consumir uma grande quantidade de memória do servidor, principalmente se forem feitas modificações sobre os mesmos registros múltiplas vezes na mesma transação. Utilize a declaração RELEASE SAVEPOINT para liberar os recursos consumidos para a manutenção do SAVEPOINT.

RELEASE SAVEPOINT <identificador> [ONLY];

A declaração RELEASE SAVEPOINT destrói o SAVEPOINT <identificador> do contexto da transação. A menos que especifique ONLY, todos os SAVEPOINTs criados desde o SAVEPOINT <identificador> serão também destruídos.

Exemplos de utilização de SAVEPOINTs create table test (id integer); commit; insert into test values (1); commit; insert into test values (2); SAVEPOINT y; delete from test; select * from test; -- não devolve nenhuma linha rollback to y; select * from test; -- devolve duas linhas rollback; select * from test; -- devolve uma linha

SAVEPOINTs internos Por padrão, o Servidor estabelece um SAVEPOINT de sistema automático para cada transação para possibilitar o seu ROLLBACK. Quando se executa um ROLLBACK, todas as alterações efetuadas na transação são desfeitas utilizando-se este SAVEPOINT de transação, e posteriormente é efetuado o COMMIT da mesma. Esta lógica permite reduzir a quantidade de “garbage collection” originada por transações “rolled back”.

Quando o volume de dados alterados a partir do SAVEPOINT de uma transação é demasiado grande (104-106 registros afetados) o Servidor libera o SAVEPOINT da transação, e utiliza o mecanismo TIP para, se necessário, executar um RollBack da transação. Se for prevista uma grande quantidade de alterações dentro de uma transação, pode se utilizar o TPB flag isc_tpb_no_auto para desabilitar o SAVEPOINT automático de transação.

SAVEPOINTs e PSQL Implementar SAVEPOINTs definidos pelo usuário em PSQL altera as regras de atomicidade para as declarações, incluindo as declarações de chamadas a procedures. O Firebird disponibiliza o tratamento de exceções em PSQL para reverter alterações efetuadas em Stored Procedures e Triggers. Cada declaração SQL/PSQL executada é assegurada por um SAVEPOINT interno automático, onde ou toda a declaração é executada com sucesso, ou TODAS as alterações efetuadas por ela são “rolled back” e uma exceção ocorre. Cada bloco de tratamento de exceções PSQL está também incluído em um sistema automático de SAVEPOINT.

(1.5) Locking Explicito Nickolay Samofatov v.1.08 Notas da Versão Firebird 1.5 08 fevereiro 2004 Página 17

O uso da cláusula adicional WITH LOCK oferece uma capacidade limitada de lock pessimista explícito, para um uso cuidadoso e em condições em que a quantidade de linhas afetadas seja a) extremamente pequena (idealmente apenas uma) e b) controlada com precisão a partir do código da aplicação.

NOTA: É raro que seja necessário o uso de lock pessimista no Firebird, e esta funcionalidade deve ser bem compreendida antes que seu uso seja considerado.

SELECTFROM <tabela>
[WHERE]
[FOR UPDATE [OF]]

Sintaxe WITH LOCK;

Se a cláusula WITH LOCK for bem sucedida, será estabelecido um lock nas linhas selecionadas que impedirá que outras transações obtenham acessos de escrita a qualquer uma delas, ou de suas dependentes, até o fim da transação.

Se a cláusula FOR UPDATE for utilizada, o lock será aplicado a todas as linhas, uma a uma, tão logo a linha seja transferida para o cache do servidor. Assim, é possível que um lock que tenha sido bem sucedido ao ser requerido, falhe subsequentemente, quando for feita uma tentativa de carregar uma linha sobre a qual já tenha sido obtido um lock por uma outra transação.

É essencial que se compreenda os efeitos do isolamento de uma transação, assim como outros dos seus atributos, antes de se implementar um mecanismo de lock explicito em uma aplicação.

SELECTWITH LOCK está disponível em DSQL e PSQL. Pode ser bem sucedido apenas no primeiro

nível de um SELECT de uma só tabela. Não está disponível para uma sub-query, nem em joins. Não pode ser utilizado com o operador DISTINCT, ou com uma cláusula GROUP BY, nem com qualquer outro tipo de agregação. Não pode ser utilizado a partir de uma view, nem com uma tabela externa, ou no resultado de uma stored procedure selecionável.

Compreendendo a Clausula WITH LOCK

O Servidor considera cada registro contido numa declaração lock explícita, devolvendo ou a sua mais recente versão “commited”, qualquer que seja o estado da base de dados no momento em que a declaração foi submetida, ou uma exceção.

O comportamento do “Wait” e a notificação de conflito de lock dependerão dos parâmetros da transação especificados no bloco TPB.

Modo TPB Comportamento isc_tpb_consistency Locks explícitos são eliminados por locks implícitos ou explícitos da tabela e são ignorados.

v.1.08 Notas da Versão Firebird 1.5 08 fevereiro 2004 Página 18

Modo TPB Comportamento isc_tpb_concurrency + isc_tpb_nowait

Se um registro é modificado por alguma transação que foi “committed” depois que a transação, que está tentado adquirir o lock explicito, começou, ou alguma transação ativa modificou o registro, uma exceção de conflito ocorre imediatamente.

isc_tpb_concurrency + isc_tpb_wait

Se um registro é modificado por alguma transação que foi “committed” depois que a transação que está tentando adquirir o lock explicito começou, uma exceção de conflito é imediatamente retornada.

Se uma transação ativa mantém um lock do registro (através de um lock explicito ou de um lock normal de escrita), a transação, que requereu o lock explicito, aguarda pela sua resolução e, após o seu término, tenta novamente obter o lock do registro. Assim, se a transação que bloqueava o registro fizer o “commit” de uma versão modificada do registro, uma exceção de conflito será recebida.

isc_tpb_read_committed + isc_tpb_nowait

Se uma transação ativa bloqueia o registro (através de um lock explicito ou de um lock normal de escrita), uma exceção de conflito ocorre imediatamente.

isc_tpb_read_committed + isc_tpb_wait

Se uma transação ativa bloqueia o registro (via um lock explicito ou por um lock normal otimista de escrita), a transação, que requereu o lock explicito, aguarda pela sua resolução, e após o seu término, tenta novamente obter o lock do registro. Nunca acontecerá uma exceção de conflito neste modo de TPB.

Quando um comando UPDATE encontra um registro bloqueado por outra transação, ele ou recebe uma exceção de conflito, ou aguarda que a transação que possui o bloqueio termine, dependendo do modo TPB. O Comportamento do Servidor será o mesmo que seria caso o registro já tivesse sido modificado pela transação que estabeleceu o bloqueio. Nenhum código de erro especificado será retornado por conflitos de lock envolvendo locks explícitos ou pessimistas.

O Servidor garante que todos os registros recebidos por comando de bloqueio específico estão efetivamente bloqueados e que efetivamente todos os parâmetros da cláusula “where” foram avaliados, desde que a condição de procura não dependa de outras tabelas, via joins, subqueries, etc. Garante ainda que as linhas que não satisfazem a condição WHERE não serão bloqueadas pela transação. Porém, não pode garantir que não existam linhas que, embora satisfaçam a cláusula “where”, já estivessem bloqueadas. Esta situação pode acontecer caso alguma outra transação em paralelo tenha executado um “commit” durante o curso de execução do comando de bloqueio.

O Servidor bloqueia as linhas na altura do “fetch”. Este mecanismo tem conseqüências importantes caso sejam bloqueadas várias linhas de uma só vez. Muitos métodos de acesso ao Firebird, por padrão, utilizam processos de obtenção de linhas através de pacotes de algumas centenas a cada acesso (“buffered fetches”). A maior parte dos componentes de acesso a dados não devolverá as linhas contidas no último pacote onde tenha ocorrido um erro.

A declaração FOR UPDATE oferece uma técnica que previne a utilização de “buffered fetches”, e ainda a opção OF <nome-das-colunas> para ativar UPDATEs posicionais. Alternativamente, pode ser possível configurar nos componentes de acesso o tamanho do buffer de “fetch” para 1. Isto permitirá que uma linha efetivamente bloqueada seja processada, antes que a próxima linha seja obtida e bloqueada, ou v.1.08 Notas da Versão Firebird 1.5 08 fevereiro 2004 Página 19 que um eventual erro seja devidamente tratado, sem a necessidade de se efetuar um “rollback” da transação.

O Rollback de um SAVEPOINT implícito ou explicito libera os bloqueios de registros que tenham sido adquiridos nesse SAVEPOINT, mas não notifica outras transações que possam estar aguardando esta liberação. As aplicações não devem basear-se neste comportamento, pois é provável que ele seja modificado no futuro.

Embora os locks explícitos possam ser utilizados para prevenir ou processar erros de conflitos pouco comuns, o volume de erros de deadlock irá aumentar a menos que se estabeleça uma estratégia cuidadosa e rigorosamente controlada. A maior parte das aplicações não deveriam precisar usar locks explícitos. Os principais objetivos dos locks explicitos são (1) evitar custosos processamentos de um grande volume de erros de conflitos de atualização, em aplicações de grande carga de processamento e (2) manter a integridade de objetos mapeados em uma base de dados relacional, em ambientes de clusters. Se o seu uso de locks explícitos estive fora destas duas categorias, então a forma usada não é correta para executar essa tarefa no Firebird.

O lock explícito é uma “Funcionalidade Avançada”, não a use inadequadamente ! Embora soluções obtidas através do seu uso sejam importantes para web sites que lidam com milhares de escritas concorrentes, ou para aplicações ERP/CRM em uso em grandes empresas, a maior parte das aplicações não precisam operar nestas condições.

Exemplos i) (simples) SELECT * FROM DOCUMENT WHERE ID=? WITH LOCK i) (múltiplas linhas, processamento com cursor DSQL um-por-um) SELECT * FROM DOCUMENT WHERE PARENT_ID=? FOR UPDATE WITH LOCK

(1.5) Melhorias no tratamento de agregados Arno Brinkman

Originalmente, o agrupamento era permitido apenas por colunas nomeadas. No Firebird 1.0, já era possível o agrupamento por uma expressão UDF. Na versão 1.5, várias extensões foram implementadas para permitir a processamento de funções agregadas na cláusula GROUP BY, que permite agora o uso da posição da coluna na cláusula (a posição base-1 da esquerda para a direita, como na cláusula ORDER BY), ou por uma variedade de expressões. NOTA: Nem todas as expressões são permitidas dentro de uma claúsula GROUP BY. Por exemplo, a concatenação não é ainda permitida.

SELECTFROM .... [GROUP BY lista_group_by]

Sintaxe do Group By lista_group_by: item_group_by [,lista_group_by]; item_group_by: nome_coluna | grau (ordinal)

| udf

| função_group_by; v.1.08 Notas da Versão Firebird 1.5 08 fevereiro 2004 Página 20 função_group_by : função_valor_numérico | função_valor_texto

| expressão_case ; função_valor_numérico: EXTRACT '(' parte_timestamp FROM valor ')'; função_valor_texto: SUBSTRING '(' valor FROM posição_inteiro ')'

| SUBSTRING '(' valor FROM posição_inteiro FOR inteiro ')'

| KW_UPPER '(' valor ')' ;

(Parte 5 de 13)

Comentários