Um guia para hibernar OGM
1. Visão geral
Neste tutorial, vamos passar pelo básico deHibernate Object/Grid Mapper (OGM).
O Hibernate OGM fornece suporte à API de persistência Java (JPA) para datastores NoSQL. NoSQL é um termo abrangente que abrange uma ampla variedade de armazenamento de dados. Por exemplo, isso inclui datastores de valor-chave, documento, coluna e gráfico.
2. A arquitetura do Hibernate OGM
Hibernate traditionally offers an Object Relational Mapping (ORM) engine para bancos de dados relacionais. Hibernate OGM engine extends its functionality to support NoSQL datastores. O principal benefício de usá-lo é a consistência da interface JPA em datastores relacionais e NoSQL.
O Hibernate OGM é capaz de fornecer abstração sobre vários datastores NoSQL por causa de duas interfaces chave,DatastoreProvidereGridDialect. Portanto, cada novo armazenamento de dados NoSQL que ele suporta vem com uma implementação dessas interfaces.
A partir de hoje, ele não oferece suporte a todos os datastores NoSQL, mas é capaz de trabalhar com muitos deles como Infinispan e Ehcache (valor-chave), MongoDB e CouchDB (documento) e Neo4j (gráfico).
It also fully supports transactions and can work with standard JTA providers. Em primeiro lugar, isso pode ser fornecido por meio do contêiner Java EE sem qualquer configuração explícita. Além disso, podemos usar um gerenciador de transações JTA independente, como Narayana, no ambiente Java SE.
3. Configuração
Para este tutorial, usaremos o Maven para extrair as dependências necessárias para trabalhar com o Hibernate OGM. Também usaremosMongoDB.
Para esclarecer, vamos ver como configurá-los para o tutorial.
3.1. Dependências do Maven
Vamos ver as dependências necessárias para trabalhar com Hibernate OGM e MongoDB:
org.hibernate.ogm
hibernate-ogm-mongodb
5.4.0.Final
org.jboss.narayana.jta
narayana-jta
5.9.2.Final
Aqui estamos puxando as dependências necessárias por meio do Maven:
-
Narayana Transaction Manager (provedor real do JTA)
3.2. Unidade de persistência
Também teremos quedefine datastore details no Hibernatepersistance.xml:
org.hibernate.ogm.jpa.HibernateOgmPersistence
Observe as definições que fornecemos aqui:
-
o valor do atributo transaction-type como "JTA" (isso implica que queremos um gerenciador de entidade JTA doEntityManagerFactory)
-
o provedor, que éHibernateOgmPersistence para Hibernate OGM
-
alguns detalhes adicionais relacionados ao banco de dados (normalmente variam entre diferentes fontes de dados)
A configuração assume que o MongoDB está em execução e acessível nos padrões. Se não for esse o caso, podemos sempreprovide details as necessary. Um de nossos artigos anteriores também cobresetting up MongoDB in detail.
4. Definição de entidade
Agora que já passamos pelo básico, vamos definir algumas entidades. If we worked with Hibernate ORM or JPA before, this has nothing more to add. Esta é a premissa fundamental do Hibernate OGM. Épromises to let us work with different NoSQL datastores with just the knowledge of JPA.
Para este tutorial, definiremos um modelo de objeto simples:
Ele define as classesArticle,AuthoreEditor junto com seus relacionamentos.
Vamos também defini-los em Java:
@Entity
public class Article {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
private String articleId;
private String articleTitle;
@ManyToOne
private Author author;
// constructors, getters and setters...
}
@Entity
public class Author {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
private String authorId;
private String authorName;
@ManyToOne
private Editor editor;
@OneToMany(mappedBy = "author", cascade = CascadeType.PERSIST)
private Set authoredArticles = new HashSet<>();
// constructors, getters and setters...
}
@Entity
public class Editor {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
private String editorId;
private String editorName;
@OneToMany(mappedBy = "editor", cascade = CascadeType.PERSIST)
private Set assignedAuthors = new HashSet<>();
// constructors, getters and setters...
}
Agora definimos as classes de entidade e as anotamos com as anotações padrão JPA:
-
@Entity para estabelecê-los como entidades JPA
-
@Id para gerar chaves primárias para as entidades com UUIDs
-
@OneToMany e@ManyToOne para estabelecer relações bidirecionais entre as entidades
5. Operações
Agora que criamos nossas entidades, vamos ver se podemos realizar algumas operações nelas. Como primeira etapa, teremos que gerar alguns dados de teste. Aqui, criaremos umEditor, algunsAuthor e algunsArticle.. Também estabeleceremos seus relacionamentos.
Depois disso, antes de realizarmos qualquer operação, precisaremos de uma instância deEntityManagerFactory.. Podemos usar isso para criarEntityManager. Junto com isso, precisamos criarTransactionManager para lidar com os limites da transação.
Vamos ver como podemos usá-los para persistir e recuperar as entidades que criamos anteriormente:
private void persistTestData(EntityManagerFactory entityManagerFactory, Editor editor)
throws Exception {
TransactionManager transactionManager =
com.arjuna.ats.jta.TransactionManager.transactionManager();
transactionManager.begin();
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.persist(editor);
entityManager.close();
transactionManager.commit();
}
Aqui, estamos usandoEntityManager para persistir a entidade raiz, que se espalha para todas as suas relações. Também estamos realizando esta operação dentro de um limite de transação definido.
Agora estamos prontos para carregar a entidade que acabamos de persistir e verificar seu conteúdo. Podemos executar um teste para verificar isso:
@Test
public void givenMongoDB_WhenEntitiesCreated_thenCanBeRetrieved() throws Exception {
EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("ogm-mongodb");
Editor editor = generateTestData();
persistTestData(entityManagerFactory, editor);
TransactionManager transactionManager =
com.arjuna.ats.jta.TransactionManager.transactionManager();
transactionManager.begin();
EntityManager entityManager = entityManagerFactory.createEntityManager();
Editor loadedEditor = entityManager.find(Editor.class, editor.getEditorId());
assertThat(loadedEditor).isNotNull();
// Other assertions to verify the entities and relations
}
Aqui, estamos usandoEntityManager novamente para encontrar os dados e realizar asserções padrão sobre eles. Quando executamos esse teste, ele instancia o armazenamento de dados, persiste as entidades, as recupera e verifica.
Novamente, temosjust used JPA to persist the entities along with their relationship. Da mesma forma,we use JPA to load the entities backe tudo funciona bem, mesmo quando nossa escolha de banco de dados é MongoDB em vez de um banco de dados relacional tradicional.
6. Comutação de back-end
Também podemos mudar nosso back-end. Vamos descobrir agora como será difícil fazer isso.
Vamos mudar nosso back-end paraNeo4j, which happens to be a popular graph-oriented datastore.
Em primeiro lugar, vamos adicionar oMaven dependency for Neo4j:
org.hibernate.ogm
hibernate-ogm-neo4j
5.4.0.Final
Em seguida, teremos que adicionar a unidade de persistência relevante em nossopersistence.xml:
org.hibernate.ogm.jpa.HibernateOgmPersistence
Em resumo, essas são as configurações básicas necessárias para o Neo4j. Isso pode serdetailed further as required.
Bem, isso é basicamente o que precisa ser feito. Quando executamos o mesmo teste com o Neo4j como o armazenamento de dados de back-end, ele funciona perfeitamente.
Observe que mudamos nosso back-end de MongoDB, que por acaso é um armazenamento de dados orientado a documentos, para Neo4j, que é um armazenamento de dados orientado a gráficos. And we did all this with minimal changes and without needing any changes in any of our operations.
7. Conclusão
Neste artigo, examinamos os fundamentos do Hibernate OGM, incluindo sua arquitetura. Posteriormente, implementamos um modelo de domínio básico e executamos várias operações usando vários bancos de dados.
Como sempre, o código dos exemplos está disponívelover on GitHub.