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.
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.
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.
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.
This article discusses further proxying pitfalls em grande detalhe aqui.
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.