Transações com Spring e JPA

Transações com Spring e JPA

1. Visão geral

Este tutorial irá discutirthe right way to configure Spring Transactions, como usar a anotação@Transactional e armadilhas comuns.

Para uma discussão mais aprofundada sobre a configuração de persistência central, verifique oSpring with JPA tutorial.

Basicamente, existem duas maneiras distintas de configurar transações - anotações e AOP - cada uma com suas próprias vantagens. Vamos discutir a configuração de anotação mais comum aqui.

Leitura adicional:

Configurando o DataSource separado da Spring para testes

Um tutorial rápido e prático sobre como configurar uma fonte de dados separada para teste em um aplicativo Spring.

Read more

Guia rápido sobre o carregamento de dados iniciais com o Spring Boot

Um exemplo rápido e prático de uso dos arquivos data.sql e schema.sql no Spring Boot.

Read more

Mostrar instruções SQL Hibernate / JPA a partir do Spring Boot

Aprenda como você pode configurar o log das instruções SQL geradas no aplicativo Spring Boot.

Read more

2. Configurar transações sem XML

Spring 3.1 apresentathe @EnableTransactionManagement annotation que podemos usar em uma classe@Configuration e habilitar o suporte transacional:

@Configuration
@EnableTransactionManagement
public class PersistenceJPAConfig{

   @Bean
   public LocalContainerEntityManagerFactoryBean
     entityManagerFactoryBean(){
      //...
   }

   @Bean
   public PlatformTransactionManager transactionManager(){
      JpaTransactionManager transactionManager
        = new JpaTransactionManager();
      transactionManager.setEntityManagerFactory(
        entityManagerFactoryBean().getObject() );
      return transactionManager;
   }
}

No entanto, se estivermos usando um projeto Spring Boot e tivermos dependências spring-data- * ou spring-tx no classpath, o gerenciamento de transações será habilitado por padrão.

3. Configurar transações com XML

Antes de 3.1 ou se Java não for uma opção, aqui está a configuração XML, usandoannotation-drivene o suporte a namespace:


   

4. A anotação@Transactional

Com as transações configuradas, podemos agora anotar um bean com@Transactional no nível da classe ou do método:

@Service
@Transactional
public class FooService {
    //...
}

A anotação também suportafurther configuration:

  • oPropagation Type da transação

  • oIsolation Level da transação

  • aTimeout para a operação envolvida pela transação

  • areadOnly flag - uma dica para o provedor de persistência de que a transação deve ser somente leitura

  • as regrasRollback para a transação

Observe que - por padrão, a reversão ocorre no tempo de execução, apenas exceções não verificadas. The checked exception does not trigger a rollback da transação. Podemos, é claro, configurar esse comportamento com os parâmetros de anotaçãorollbackForenoRollbackFor.

5. Armadilhas potenciais

5.1. Transações e proxies

Em um nível alto,Spring creates proxies for all the classes annotated with @Transactional - na classe ou em qualquer um dos métodos. O proxy permite que a estrutura injete lógica transacional antes e depois do método em execução - principalmente para iniciar e confirmar a transação.

O que é importante ter em mente é que, se o bean transacional estiver implementando uma interface, por padrão, o proxy será um Java Dynamic Proxy. Isso significa que apenas as chamadas de método externo que chegam pelo proxy serão interceptadas. Any self-invocation calls will not start any transaction, mesmo se o método tiver a anotação@Transactional.

Outra advertência sobre o uso de proxies é queonly public methods should be annotated with @Transactional. Métodos de quaisquer outras visibilidades irão simplesmente ignorar a anotação silenciosamente, já que não são proxy.

5.2. Mudando o nível de isolamento

Também podemos alterar o nível de isolamento da transação:

@Transactional(isolation = Isolation.SERIALIZABLE)

Observe que na verdade foiintroduced no Spring 4.1; se executarmos o exemplo acima antes do Spring 4.1, isso resultará em:

org.springframework.transaction.InvalidIsolationLevelException: JPA padrão não suporta níveis de isolamento customizados - use umJpaDialect especial para sua implementação de JPA

5.3. Transações somente leitura

O sinalizadorreadOnly geralmente gera confusão, especialmente ao trabalhar com JPA; do Javadoc:

Isso serve apenas como uma dica para o subsistema de transação real; isso iránot necessarily causar falha nas tentativas de acesso de gravação. Um gerenciador de transações que não pode interpretar a dica somente leituranot lançará uma exceção quando solicitado para uma transação somente leitura.

O fato é quewe can’t be sure that an insert or update will not occur when the readOnly flag is set. Esse comportamento depende do fornecedor, enquanto JPA é independente do fornecedor.

Também é importante entender quethe readOnly flag is only relevant inside a transaction. Se uma operação ocorre fora de um contexto transacional, o sinalizador é simplesmente ignorado. Um exemplo simples disso chamaria um método anotado com:

@Transactional( propagation = Propagation.SUPPORTS,readOnly = true )

a partir de um contexto não transacional - uma transação não será criada e o sinalizadorreadOnly será ignorado.

5.4. Registro de transações

Um método útil para entender problemas relacionados à transação é o ajuste fino do log nos pacotes transacionais. O pacote relevante na primavera é “org.springframework.transaction”, which should be configured with a logging level of TRACE.

6. Conclusão

Cobrimos a configuração básica da semântica transacional usando Java e XML, como usar@Transactionale as melhores práticas de uma estratégia transacional.

Como sempre, o código apresentado neste artigo está disponívelover on Github.