This Banner is For Sale !!
Get your ad here for a week in 20$ only and get upto 15k traffic Daily!!!

3 dicas para uso eficiente de JPA/Hibernate


Trabalhar de maneira eficiente com o EntityManager pode parecer um pouco complexo caso você esteja iniciando agora sua jornada com JPA/Hibernate. Um dos motivos que corroboram essa complexidade é a maneira que estamos acostumados a pensar sobre Entidades.

Antes entendemos a entidade como uma tabela, e seus relacionamentos, e para cada alteração, inserção ou remoção somos obrigados a disparar uma operação de SQL.

Já ao trabalhar com JPA/Hibernate devemos colocar a entidade no estado MANAGED, utilizar os métodos que contém as regras de negócio, para que estes alterem os valores de cada atributo, e a JPA e Hibernate decidam quais as operações SQL devem ser geradas para sincronizar os valores com Banco de Dados (BD).



1. Conheça a EntityManager

A EntityManager é uma abstração que representa uma sessão com banco de dados, é através desta abstração que delegamos ao Hibernate a responsabilidade de sincronizar os dados da memória ao Banco de Dados (BD).

Isto significa que a cada sessão com BD, pode ser criado uma instância da EntityManager, e esta sessão sera responsável por gerenciar as entidades que estão estado MANAGED.

EntityManager também é chamada de Contexto de Persistência, ou Cache de primeiro nível, isto porque quando uma entidade é transitada ao estado MANAGED ela é armazenada em memória para otimizar o acesso à mesma.

Enquanto uma entidade esteja presente ao Contexto de Persistência as alterações dos valores de seus atributos serão propagados ao BD.



2. Domine os estados das Entidades

Uma entidade no decorrer do seu ciclo de vida pode transitar sobre os seguintes estados:

  • Transient ou New: É quando o objeto foi instânciado, porém, não possui um ID ou main key, ou seja, não está em sincronia com Banco de dados.

  • Managed: É quando a entidade em memória esta associada a uma linha da tabela no banco de dados, ou seja, ela possui um ID. Quando a entidade esta neste estado ela é gerenciada pelo Contexto de Persistência, e qualquer alteração feita nesta entidade é detectada pelo Hibernate que por sua vez traduz sincroniza com o BD através de comandos SQL.

  • Indifferent: É quando a entidade é removida do Contexto de Persistência, então a entidade não tem suas alterações em memoria propagadas ao BD.

  • Eliminated: É quando a entidade tem um agendamento para exclusão, ou seja, no momento oportuno o Hibernate irá propagar a operação SQL DELETE.

Para que uma entidade transite de um estado para outro devemos propagar as operações do EntityManger, observe o diagrama abaixo.

Entity State

Fonte: Vlad Mihalcea – A newbie’s information to entity state transitions with JPA and Hibernate

Em seguida será apresentado algumas maneiras de transitar uma entidade sobre cada um dos estados. Caso queria entender melhor como os testes foram criados pode acessar este repositorio no Github.



2.1 Transitando uma entidade para o estado managed

Dado que instanciamos uma entidade, a mesma nasce em estado new, ou seja, a mesma não referência um registro no BD, para que isto aconteça é necessário que a entidade esteja em estado managed, a transição pode ser feita dado que exista um contexto transacional aberto e que a operação de persist da EntityManager seja aplicado a entidade.

  @Check
  void deveTransitarDeTransientParaManaged() {

      Aluno aluno = new Aluno("Jordi H.");
      EntityTransaction transaction = entityManager.getTransaction();
      transaction.start();

      entityManager.persist(aluno);

      transaction.commit();

      assertTrue(
              entityManager.incorporates(aluno),
              "Esta entidade deveria estar no Contexto de Persistencia"
      );

    }
Enter fullscreen mode

Exit fullscreen mode

A transição feita no teste acima pode ser resumida aos seguintes passos:

  1. É criado uma instância da entidade Aluno, que esta em estado transient ou new.
  2. É solicitado uma Transaction ao Contexto de Persistência, que é aberta na próxima linha.
  3. Dado que a Transaction esta aberta, é disparado a operação de persist, que transita a entidade para o estado managed.
  4. Após a transação ser confirmada, e os dados serem sincronizados ao banco, a EntityManager continua aberta, isto significa que a entidade ainda deve pertencer ao Contexto de Persistência.
  5. É provado que a entidade existe no Contexto de Persistência quando o método assertTrue é chamado.



2.2 Transitando uma entidade para managed para indifferent

Dado que uma entidade esteja no estado managed uma das formas de transita-la para indifferent é aplicar a operação detach da EntityManager.

@Check
void deveTransitarDeManagedParaDetached() {
    Aluno aluno = new Aluno("Jordi H.");
    EntityTransaction transaction = this.supervisor.getTransaction();
    transaction.start();

    supervisor.persist(aluno);
    transaction.commit();

    this.supervisor.detach(aluno);
    assertFalse(
            supervisor.incorporates(aluno),
            "esta entidade não deve participar do contexto de persistencia"
    );
}
Enter fullscreen mode

Exit fullscreen mode

Observamos que no teste acima, que dado uma entidade esteja no estado managed, não é necessário que contenha uma Transaction aberta para transitar a entidade para indifferent. No método assertFalse provamos que após aplicação da operação detach, a entidade aluno não faz mais parte do Contexto de Persistência.



2.3 Transitando uma entidade managed para eliminated

Dado que existe uma entidade esta managed transita-la para eliminated é possivel caso seja aplicado a operação take away da EntityManager.

@Check
void deveTransitarDeManagedParaRemoved() {
    Aluno aluno = new Aluno("Jordi H.");
    EntityTransaction transaction = this.supervisor.getTransaction();
    transaction.start();

    supervisor.persist(aluno);

    supervisor.take away(aluno);

    transaction.commit();

    assertFalse(
              supervisor.incorporates(aluno),
              "esta entidade não deveria pertencer ao Contexto de Persistencia"
      );
    assertNull(
            supervisor.discover(Aluno.class,aluno.getId()),
            "Não deveria existir registro para este id"
    );
}
Enter fullscreen mode

Exit fullscreen mode

No teste acima é possivel observar que dado que exista uma Transaction aberta, podemos agendar a exclusão da entidade, que é realizado no momento do commit. Então primeiro garantimos que a entidade não pertence ao Contexto de Persistência no método assertFalse. O método assertNull prova que não existe registro de entidade para o id informado.



2.4 Transitando uma entidade indifferent para managed

Dado que exista uma entidade em estado indifferent e seja necessário transita-la para managed é possivel através da aplicação da operação merge da EntityManager.

@Check
void deveTransitarDeDetachedParaManaged() {
    Aluno aluno = new Aluno("Jordi H.");
    EntityTransaction transaction = this.supervisor.getTransaction();
    transaction.start();

    supervisor.persist(aluno);
    transaction.commit();

    this.supervisor.detach(aluno);
    assertFalse(
            supervisor.incorporates(aluno),
            "esta entidade não deve participar do Contexto de Persistencia"
    );


    aluno.setNome("Yuri Matheus");

    transaction.start();
    Aluno alunoAposMerge = supervisor.merge(aluno);
    transaction.commit();

    assertTrue(
            supervisor.incorporates(alunoAposMerge),
            "esta entidade deve pertencer ao estado Contexto de Persistencia"
    );

}
Enter fullscreen mode

Exit fullscreen mode

O teste acima pode ser resumido no seguintes passos:

  1. É criado uma entidade Aluno, que é movida para o estado managed após a aplicação da operação de persist.
  2. Entidade Aluno é movida para o estado indifferent após a operação detach, e através do assertFalse provamos que a mesma não pertence ao Contexto de Persistência.
  3. Entidade tem uma alteração de valor em um dos seus atributos.
  4. É aberto uma nova Transaction e a operação de merge é aplicada, movimentando a entidade para o estado managed.
  5. O método assertTrue prova que a entidade pertence ao Contexto de Persistência.



3. Tenha um controle Transacional bem definido

O Contexto de Persistência está intimamente relacionado a transação (Transaction), isto significa que enquanto uma transação estiver aberta as entidades permaneceram em estado MANAGED, ou seja, as alterações de valores serão propagados ao banco.

Outra vantagem de manter uma transação aberta é que todas as operações no escopo do método, se tornam uma única unidade de processamento, caso uma das operações falhe, todas as outras iram falhar junto, deixando nosso método atômico.



3.1 Definindo um controle Transacional

Uma transação é composta por uma ou mais operações que devem ser confirmadas (commit) ou revertidas (rollback) juntas. Isto porque se caso uma destas operações falhar e as demais prosseguirem pode causar inconsistência aos dados. Os fluxos de negócio seguem a mesma filosofia, um único erro deve invalidar todas as alterações que façam parte deste fluxo.

Sabe-se que grande parcela do mercado utiliza as Exceções não checadas para delimitar um erro no fluxo de negócio. E caso seu projeto siga esta metodologia, pode-se favorecer o uso destas exceções como um ponto para reversão (rollback) de transação.



3.1.1 Criando um Controle Transacional com JPA/Hibernate

Caso seu projeto não make the most of nenhuma biblioteca ou framework para delimitar o controle trasacional, você pode implementá-lo apenas com JPA/Hibernate.

A EntityManager oferece através de sua API um método para solicitar uma Transaction, representada pela abstração EntityTransaction.

A EntityTransaction oferece através de seus métodos, mecanismos para controle de transacional, e é através destes métodos que podemos abrir uma transaction, realizar commit ou rollback, e até verificar se determinada transaction ainda esta ativa.

Utilizando a implementação da EntityTransaction podemos implementar um componente para gerenciar as transações, vamos chama-lo de TransactionManager.

public class TransactionManager{
    personal EntityManagerFactory managerFactory;

    public TransactionManager(EntityManagerFactory managerFactory) {
        this.managerFactory = managerFactory;
    }

    public void executa(Shopper<EntityManager> acao) {

        EntityManager supervisor = null;
        EntityTransaction transaction = null;

        strive {
            supervisor = managerFactory.createEntityManager();
            transaction = supervisor.getTransaction();
            transaction.start();

            acao.settle for(supervisor);

            transaction.commit();
        } catch (Exception e) {
            if (transaction != null && transaction.isActive()) {
                transaction.rollback();
            }

            throw new RuntimeException(e);
        } lastly {
            if (supervisor != null) {
                supervisor.shut();
            }
        }
    }
}
Enter fullscreen mode

Exit fullscreen mode

Na implementação acima definimos que caso qualquer exceção seja lançada no fluxo de negócio, automaticamente todas alterações serão revertidas.



3.1.2 Utilizando Controle Transactional com Spring e JPA/Hibernate

Spring oferece transações de maneira declarativa através da anotação @Transactional. Caso um bean seja anotado a nível de classe cada método publico receberá uma transação. Caso um método publico de um bean seja anotado, o escopo deste método sera executado em uma transação, ou seja, o COMMIT sera feito ao fim do método.

@Service
public class MeuService{
    @Autowired
    personal EntityManager supervisor;

    @Transactional
    public void executa(){
        //logica de negocio
    }
}
Enter fullscreen mode

Exit fullscreen mode

E caso uma exceção seja lançada no escopo do método executa() qual o comportamento da transação?

Automaticamente o Spring cuidara de indicar para EntityManager reverter a transação, caso qualquer exceção a partir de RunTimeException seja lançada e não tratada.



Referências



The Article was Inspired from tech community site.
Contact us if this is inspired from your article and we will give you credit for it for serving the community.

This Banner is For Sale !!
Get your ad here for a week in 20$ only and get upto 10k Tech related traffic daily !!!

Leave a Reply

Your email address will not be published. Required fields are marked *

Want to Contribute to us or want to have 15k+ Audience read your Article ? Or Just want to make a strong Backlink?