Post on 26-Dec-2015
description
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 1/23
www.devmedia.com.br [versão para impressão]Link original: http://www.devmedia.com.br/articles/viewcomp.asp?comp=29114
Introdução a Multi-Tenancycom Hibernate 4
Este artigo apresenta a funcionalidade, do Hibernate, queprovê mecanismos de suporte à arquitetura Multi-Tenant.
Artigo do tipo Tutorial
Recursos especiais neste artigo:
Conteúdo sobre Novidades
Autores: Marcos de Melo Siega e Everton Coimbra de Araújo
Suporte a Multi-Tenancy com Hibernate 4
Este artigo apresenta a funcionalidade, agregada à versão 4 do framework Hibernate, que
provê mecanismos de suporte à arquitetura Multi-Tenant (vários clientes, logicamente
isolados, utilizando os mesmos recursos físicos). Além de demonstrar os aspectos deste
novo recurso, expõe-se uma contextualização sobre Hibernate e Multi-Tenancy, e então,
ao final, implementa-se um exemplo prático utilizando esta nova funcionalidade.
Em que situação o tema é útil
Arquitetos de software encontram grandes desafios ao construir modelos arquiteturais
SaaS (Software como serviço, do inglês Software as a Service) que apresentem uma
infraestrutura de dados diferenciada, podendo não contar com servidores locais e
infraestrutura própria, tendo que dispor todos os dados em um espaço compartilhado.
Fatores como estes influenciam diretamente na capacidade de gerência, monitoramento e
até mesmo na segurança dos dados.
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 2/23
Na medida em que a linguagem Java começou a ganhar destaque em ambientes
corporativos, notou-se rapidamente que um tempo excessivo era gasto com a
codificação de instruções SQL e com código JDBC capaz de interpretá-las.
O processo de desenvolvimento sofre influência direta deste aspecto negativo, pois há
uma imensa queda de produtividade quando o desenvolvedor torna-se responsável por
criar tais instruções manualmente, cabendo a ele tratar da mudança do paradigma
orientado a objetos para o mapeamento objeto relacional e vice-versa. Este
procedimento implica na necessidade de escrita de muitas linhas de código, criando um
enorme obstáculo para o desenvolvedor, que ficará encarregado de tratar da persistência
e recuperação de seus objetos utilizando uma linguagem de consulta estruturada.
A existência desta divergência entre o modelo orientado a objetos e o modelo relacional
estimulou o desenvolvimento de mecanismos que contornassem este problema. Uma das
principais ferramentas que surgiram, buscando resolver esta incompatibilidade, foi o
Hibernate. Este framework aplica técnicas de mapeamento objeto relacional para resolver
a dissonância entre os modelos.
Os frameworks de mapeamento objeto relacional, como o Hibernate, permitem mapear a
representação dos dados de um modelo de objeto para um modelo de dados relacional e
seu respectivo esquema de banco de dados, utilizando arquivos de configuração no
formato XML e anotações Java.
Tais ferramentas de ORM, além de tratar da persistência e recuperação dos dados,
devem garantir que as informações permaneçam íntegras e seguras, seja qual for a
arquitetura de software adotada para a solução. Diante da constante necessidade de
garantia destes fatores nos mais variados contextos, a versão 4 do Hibernate oferece
suporte para uma das arquiteturas que tem ganhado bastante destaque, denominada
Multi-Tenancy. Este novo recurso vai de encontro ao aumento do número de aplicações
que estão sendo desenvolvidas voltadas para a nuvem, ou ambientes onde os recursos
disponíveis são compartilhados.
Com base nisso, este artigo aborda as principais características deste recurso adicionado
ao Hibernate, suas possíveis aplicações e um exemplo simples de como empregá-lo.
Hibernate
O Hibernate é um framework para mapeamento objeto relacional e consulta a bases de
dados de código aberto e que é distribuído sob a licença LGPL. Ele assegura a
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 3/23
transparência no processo de armazenamento de objetos em bancos de dados
relacionais para o desenvolvedor, tirando dele a necessidade de se preocupar com a
forma com que estes objetos serão persistidos ou recuperados. Esta transparência
permite que o desenvolvedor concentre-se somente nas características e nos problemas
a serem resolvidos pela aplicação.
O Hibernate possibilita que os desenvolvedores utilizem a convenção POJO (Objetos
Simples em Java, do inglês Plain Old Java Objects) para construir a camada de modelo
das aplicações. No entanto, ele não é apenas uma solução ORM, mas sim uma coleção de
projetos que fornecem funcionalidades que vão além do mapeamento objeto relacional.
Uma dessas funcionalidades é o suporte ao isolamento de dados para os vários clientes
de uma aplicação, também conhecido como Multi-Tenancy, sobre o qual abordaremos a
partir de agora.
O que é Multi-Tenancy?
Em uma aplicação que atende diversos clientes simultaneamente, é fundamental que uma
possível falha na operação de um cliente não afete os demais. Desta maneira, em
modelos onde os recursos computacionais são amplamente compartilhados, este cenário
requer uma atenção especial.
Para as organizações, mecanismos que garantam a integridade dos dados, seu mais
importante acervo, são extremamente importantes. Por este motivo, elas preferem
manter seus softwares e bancos de dados instalados em hardwares pertencentes à
própria organização, a ter que confiá-los a estruturas inadequadas de fornecedores de
hospedagem.
Com o advento da computação em nuvem, e a tendência de novas aplicações operarem e
serem disponibilizadas, cada vez mais, por esta tecnologia, modelos arquiteturais
adequados que forneçam apoio à integridade dos dados se tornam imprescindíveis.
Diante deste cenário, onde a utilização dos recursos físicos é feita de maneira
compartilhada e a garantia de integridade e segurança dos dados é vital, uma solução
tem ganhado destaque por permitir o isolamento lógico dos recursos. Esta solução é o
modelo chamado de Multi-Tenancy.
O termo Multi-Tenancy é aplicado ao desenvolvimento de software para indicar uma
arquitetura na qual uma única instância de determinada aplicação serve simultaneamente
a vários clientes (tenants). Cada um dos clientes pode receber a habilidade de customizar
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 4/23
partes da aplicação, tais como a cor da interface com o usuário ou as regras de negócio
(por meio de configurações), porém, não são capazes de modificar o código do aplicativo.
Este modelo arquitetural é comumente utilizado em soluções SaaS para isolar as
informações (dados, armazenados em um banco de dados, e customizações, por
exemplo) dos diferentes clientes. O uso desse modelo para tal propósito é comumente
chamado de “Multi-Tenant de dados”.
Multi-Tenancy no Hibernate
Como de costume, o Hibernate se esforça para manter a API simples e isolada de
qualquer detalhe da complexidade de sua implementação. Neste sentido, o uso deste
novo recurso resume-se basicamente a especificar o identificador do cliente no processo
de abertura de uma nova sessão (session) e indicar, no processo de configuração do
framework, a estratégia que será adotada para isolar os dados.
Entre as diferentes estratégias de implementação do Multi-Tenancy, estão as seguintes:
1. Criar um banco de dados ou esquema de dados exclusivo para cada cliente;
2. Usar o mesmo banco de dados ou esquema para todos os clientes, mas com uma
coluna adicional em todas as tabelas (um id_tenant, por exemplo) para filtrar os dados.
O Hibernate, em sua versão 4, suporta apenas o primeiro item. O suporte para o
segundo está planejado para acompanhar a versão 5.0 do framework.
Banco de dados exclusivo por cliente
Nesta abordagem, os dados de cada cliente são mantidos em uma instância de banco de
dados separada fisicamente, como demonstra a Figura 1.
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 5/23
Figura 1. Base de dados exclusiva por cliente.
Neste modelo, conexões JDBC apontam especificamente para cada banco de dados.
Deste modo, cada cliente utilizará apenas a conexão que lhe pertence, e as modificações
feitas por cada um dos inquilinos não afetará os dados e configurações dos demais.
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 6/23
Adota-se este modelo através da definição de um pool de conexões JDBC por cliente, de
modo que a seleção do pool a ser utilizado ocorre com base em um identificador
associado ao usuário logado.
Esquema exclusivo por cliente
Nesta abordagem, os dados de cada cliente são mantidos em diferentes esquemas de
uma instância compartilhada de banco de dados, conforme ilustra a Figura 2.
Figura 2. Base de dados compartilhada por vários clientes com separação por
esquemas.
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 7/23
Ao empregar este modelo, teremos duas maneiras distintas para definir as conexões
JDBC:
1. As conexões podem apontar especificamente para cada esquema, de maneira análoga
ao modelo de banco de dados exclusivo por cliente. Contudo, este método só pode ser
adotado se o driver de conexão com a base de dados suportar a nomeação do esquema
padrão por meio de sua URL, ou se o mecanismo de pooling suportar a nomeação de um
esquema para utilizar suas conexões. Ao empregar este método, haverá um pool de
conexões JDBC distinto por cliente, onde o pool a ser utilizado é selecionado com base
no identificador associado ao cliente logado;
2. As conexões poderiam apontar para a própria base de dados (utilizando algum
esquema padrão), e a mudança de esquema ocorreria através do uso do comando SQL
SET SCHEMA (ou similar) pela aplicação. Ao utilizar esta técnica, apenas um pool de
conexões JDBC é delegado para atender a todos os clientes, e antes de ocorrer o
consumo da conexão, haveria a alteração para o esquema nomeado com o identificador
associado ao cliente logado na aplicação.
Implementação do modelo Multi-Tenancy comHibernate
A fim de ilustrar o suporte ao modelo Multi-Tenancy, propõe-se a criação de uma
aplicação de exemplo, onde a abordagem adotada será a de esquema exclusivo por
cliente. A solução proposta terá como finalidade realizar a persistência de dados de
acordo com tal separação e apresentar os resultados obtidos. Antes de começar a
desenvolver esta solução, no entanto, faz-se necessário obter todos os arquivos citados
a seguir.
Para contar com o Hibernate é preciso baixar os arquivos do framework e colocá-los no
classpath da aplicação. Tais arquivos podem ser obtidos no site oficial da ferramenta (ver
seção Links). Lá se encontram também instruções sobre como utilizá-la adequadamente.
No exemplo trabalhado, optou-se pelo uso do MySQL, mas nada impede que o
desenvolvedor utilize outro SGBD. A adoção do MySQL cria a necessidade de obter e
adicionar o arquivo JAR correspondente ao seu driver no diretório lib, além de incluí-lo no
classpath, do mesmo modo como foram adicionados os arquivos do Hibernate.
Assim, com o ambiente de desenvolvimento instalado e corretamente configurado, pode
ser dado início ao processo de implementação da aplicação exemplo.
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 8/23
Criação dos esquemas e tabelas
Antes de começar a implementação do projeto, utiliza-se a ferramenta MySQL Command
Line Client para criar dois esquemas na instância do MySQL. Cada um dos esquemas
definidos pertencerá exclusivamente ao cliente cujo nome lhe identifica. A Listagem 1
demonstra os comandos utilizados para este processo.
Listagem 1. Instruções utilizadas para a criação dos esquemas.
mysql> CREATE SCHEMA cliente1;
mysql> CREATE SCHEMA cliente2;
Após a definição dos esquemas, vamos criar uma tabela em cada um deles. Para o
exemplo, nomearemos estas tabelas como Pessoa, e ambas terão a mesma estrutura.
A Listagem 2 apresenta as instruções utilizadas na criação das tabelas. Cada uma
possui, basicamente, dois atributos, um identificador e um nome. Decidiu-se por replicar
a estrutura nos dois esquemas apenas para facilitar a apresentação do exemplo.
Listagem 2. Instruções utilizadas na criação das tabelas.
mysql> CREATE TABLE ‘cliente1’.’pessoa’ ( ‘id’ INT NOT NULL, ‘nome’ VARCHAR(45)
NULL, PRIMARY KEY(‘id’));
mysql> CREATE TABLE ‘cliente2’.’pessoa’ ( ‘id’ INT NOT NULL, ‘nome’ VARCHAR(45)
NULL, PRIMARY KEY(‘id’));
Com a base de dados configurada e seus esquemas definidos, pode-se iniciar o
desenvolvimento da aplicação que utilizará a funcionalidade de Multi-Tenancy.
Criação do projeto
Para começar, é preciso criar um novo projeto do tipo Java Project no Eclipse e definir
algumas características da aplicação. Assim, deve-se nomear o projeto, definir sua
localização, o ambiente de execução e optar por um layout para separar adequadamente
os arquivos de extensão .class e .java, como demonstrado na Figura 3.
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 9/23
Figura 3. Janela do wizard para criação de um novo projeto.
Para finalizar este processo, especifique as bibliotecas que serão adicionadas ao
classpath, a fim de atender os requisitos de dependência da nova aplicação, como
realizado na Figura 4. Caso as bibliotecas não estejam disponíveis para seleção, o
desenvolvedor pode facilmente configurá-las utilizando a opção User Libraries.
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 10/23
Figura 4. Janela do wizard para definição das configurações de construção do projeto.
Além de adicionar as bibliotecas no classpath, também é importante colocar tais arquivos
(JARs do Hibernate e do MySQL) na pasta lib do projeto. Caso a IDE não crie tal pasta
automaticamente, o desenvolvedor deve criá-la manualmente.
O processo de adição de tais arquivos pode ser realizado por meio da técnica de Drag-
and-Drop (Arrastar e Soltar). O resultado de tal procedimento é apresentado na Figura
5.
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 11/23
Figura 5. Resultado da adição dos arquivos de dependência no projeto.
Neste momento, após ter criado o projeto, faz-se necessário definir uma faceta para ele.
Facetas permitem que projetos Java EE obtenham, através de configuração, suporte para
várias outras tecnologias. O uso deste recurso deve-se pelo emprego da IDE Eclipse,
sendo que outros ambientes de desenvolvimento não agregam tal conceito. A este
exemplo foi adicionada a faceta JPA, como exposto na Figura 6.
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 12/23
Figura 6. Janela do wizard de configuração das propriedades do projeto.
A seleção desta faceta obriga o desenvolvedor a realizar algumas configurações básicas,
tais como, indicar a biblioteca que contém os arquivos de implementação do JPA e ajustar
a conexão com a base de dados utilizada. Um link (Further configuration required...)
emitido pela própria IDE e que estará disponível, em destaque, na parte inferior da janela
do Wizard de ajustes das propriedades do projeto, dá acesso às propriedades da
conexão, que deve ser configurada. O resultado dessa etapa pode ser observado na
Listagem 3.
Listagem 3. Arquivo persistence.xml gerado automaticamente após o processo de
configuração da faceta JPA.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 13/23
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="MultiTenancyApp">
</persistence-unit>
</persistence>
Como resultado do processo de configuração o arquivo persistence.xml é gerado, e deve
ser modificado de acordo com as propriedades do banco de dados e seguindo o padrão
definido pelo provedor de persistência. A Listagem 4 apresenta o resultado de tal
procedimento.
Listagem 4. Configuração do arquivo persistence.xml.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="MultiTenancyApp"
transaction-type="RESOURCE_LOCAL">
<provider>
org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.connection.driver_class"
value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url"
value="jdbc:mysql://localhost:3306/cliente1" />
<property name="hibernate.connection.username" value="user" />
<property name="hibernate.connection.password" value="password" />
<property name="hibernate.multiTenancy" value="SCHEMA" />
</properties>
</persistence-unit>
</persistence>
Implementação da aplicação exemplo
Tendo criado o projeto e realizadas as devidas configurações, dá-se início ao
desenvolvimento da classe que demonstrará o uso do suporte ao modelo Multi-Tenant, e
das demais classes necessárias para compor a solução.
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 14/23
Para começar, uma nova classe Java, denominada Pessoa, deve ser criada. Esta classe
terá a finalidade de representar a tabela presente em ambos os esquemas do banco de
dados. Feito isto, faz-se necessário implementá-la, definindo seus atributos, métodos
“acessores” e mapeando-a com anotações, conforme realizado na Listagem 5. E válido
lembrar também de mapeá-la no arquivo persistence.xml, para que a unidade de
persistência consiga gerenciá-la.
Listagem 5. Implementação da classe Pessoa.
package br.edu.utfpr.modelo;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
//Mapeamento da classe com sua representação na base de dados
@Entity(name = "Pessoa")
public class Pessoa implements Serializable {
private static final long serialVersionUID = 1L;
//Definição de atributo identificador
@Id
private Long id;
private String nome;
// Métodos get/set omitidos
}
Após realizar a implementação da classe Pessoa, é preciso criar um arquivo XML de
configurações para o Hibernate. Este arquivo é similar ao persitence.xml quanto a
finalidade, variando apenas na sintaxe e possuindo alguns recursos extras de
configuração específicos do Hibernate. O arquivo dever ser criado na pasta src e
nomeado como hibernate.cfg.xml. O corpo deste arquivo pode ser visto na Listagem 6.
Listagem 6. Arquivo de configurações do Hibernate – hibernate.cfg.xml.
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.ejb.naming_strategy">
org.hibernate.cfg.ImprovedNamingStrategy"</property>
<property name="hibernate.connection.driver_class">
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 15/23
com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/cliente1</property>
<property name="hibernate.connection.username">
user</property>
<property name="hibernate.connection.password">
Password</property>
<property name="hibernate.hbm2ddl.auto">
create-drop</property>
<property name="hibernate.show_sql">
true</property>
<property name="hibernate.format_sql">
true</property>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.multiTenancy">
schema</property>
<property name="hibernate.multi_tenant_connection_provider">
br.edu.utfpr.application.MultiTenantConnectionProviderImpl</property>
<mapping class="br.edu.utfpr.modelo.Pessoa" />
</session-factory>
</hibernate-configuration>
Neste arquivo existem duas propriedades que são extremamente importantes, pois são
elas que determinam o modelo de abordagem Multi-Tenancy que será utilizada pela
aplicação. A primeira é a hibernate.multiTenancy, que é responsável por definir que o
modelo que será utilizado será baseado em um esquema exclusivo por cliente, e a outra
propriedade é a hibernate.multi_tenant_connection_provider, que define qual será a
classe responsável por obter as conexões de acordo com o identificador do cliente. As
demais propriedades devem ser configuradas de acordo com a base de dados utilizada,
com as classes de modelo que estarão passiveis de persistência, e outras preferências do
desenvolvedor.
Tendo configurado o arquivo XML com as propriedades do Hibernate, realiza-se então a
criação das demais classes que compõem o projeto. Estas classes são responsáveis por
utilizar efetivamente o recurso de Multi-Tenancy baseado no esquema exclusivo por
cliente.
A Listagem 7 apresenta a classe ConnectionProviderBuilder com alguns comentários
sobre algumas das suas características. Ela disponibiliza dois métodos que, em conjunto,
são responsáveis por fornecer conexões configuradas para o SGBD escolhido. O método
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 16/23
getConnectionProviderProperties(), por exemplo, se encarregará de construir e
devolver um arquivo de propriedades com todos os parâmetros necessários para
estabelecer tais conexões, enquanto o método buildConnectionProvider() utilizará
este recurso para criar uma instância da classe
DriverManagerConnectionProviderImpl, que tem como papel fornecer conexões
valendo-se dos recursos da classe DriverManager.
Listagem 7. Classe construtora de provedores de conexões –
ConnectionProviderBuilder.
package br.edu.utfpr.application;
import java.util.Properties;
import org.hibernate.cfg.Environment;
import org.hibernate.service.jdbc.connections.internal
.DriverManagerConnectionProviderImpl;
//Classe responsável por prover conexão com o banco de dados a partir de
//configurações e propriedades
public class ConnectionProviderBuilder {
//Constantes utilizadas para configuração da conexão com a base de dados.
public static final String DRIVER = "com.mysql.jdbc.Driver";
//Para este exemplo assumiu-se o esquema “cliente1” como default.
public static final String URL =
"jdbc:mysql://localhost:3306/cliente1";
public static final String USER = "user";
public static final String PASS = "password";
public static Properties getConnectionProviderProperties
(String dbName) {
Properties props = new Properties(null);
props.put(Environment.DRIVER, DRIVER);
props.put(Environment.URL, String.format(URL, dbName));
props.put(Environment.USER, USER);
props.put(Environment.PASS, PASS);
return props;
}
private static DriverManagerConnectionProviderImpl
buildConnectionProvider(
Properties props, final boolean allowAggressiveRelease) {
DriverManagerConnectionProviderImpl connectionProvider =
new DriverManagerConnectionProviderImpl() {
public boolean supportsAggressiveRelease() {
return allowAggressiveRelease;
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 17/23
}
};
connectionProvider.configure(props);
return connectionProvider;
}
}
Concluída a implementação de ConnectionProviderBuilder, deve-se criar uma nova
classe para que seja possível obter conexões baseadas em identificadores. Seu nome,
acompanhado de sua localização no projeto, devem ser atribuídos à propriedade
hibernate.multi_tenant_connection_provider, definida no XML de configurações do
Hibernate.
Esta nova classe, em nosso exemplo, receberá o nome de
MultiTenantConnectionProviderImpl, e será responsável por prover conexões de
acordo com o identificador do inquilino, sendo esta uma das características essenciais na
implementação do modelo arquitetural Multi-Tenant. Para que isso seja possível o
Hibernate fornece a interface MultiTenantConnectionProvider, que define uma série de
métodos necessários para obtenção e liberação do acesso à fonte de dados e que devem
ser implementados. Detalhes de sua implementação estão apresentados na Listagem 8.
Listagem 8. Classe provedora de conexões baseadas em identificadores –
MultiTenantConnectionProviderImpl.
package br.edu.utfpr.application;
import java.sql.Connection;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider;
//Classe responsável por prover conexões baseadas nos identificadores
// dos clientes
public class MultiTenantConnectionProviderImpl implements
MultiTenantConnectionProvider {
//Definição da instância da classe construtora de provedores de conexão
private final ConnectionProvider connectionProvider =
ConnectionProviderBuilder
.buildConnectionProvider("cliente1");
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 18/23
//Método que permite o acesso à base de dados em situações onde não há
//identificadores para os clientes
@Override
public Connection getAnyConnection() throws SQLException {
return connectionProvider.getConnection();
}
//Método de libera uma conexão obtida através do método
// getAnyConnection()
@Override
public void releaseAnyConnection(Connection connection)
throws SQLException {
connectionProvider.closeConnection(connection);
}
//Método que obtém uma conexão de acordo com o identificador do cliente
//(esquema)
@Override
public Connection getConnection(String tenantIdentifier)
throws SQLException {
final Connection connection = getAnyConnection();
try {
connection.createStatement().execute("USE " +
tenantIdentifier);
} catch (SQLException e) {
throw new HibernateException(
"Não pode alterar a conexão para o esquema especificado ["
+ tenantIdentifier + "]", e);
}
return connection;
}
//Método que libera uma conexão obtida através do método
// getConnection()
@Override
public void releaseConnection(String tenantIdentifier,
Connection connection)
throws SQLException {
try {
connection.createStatement().execute("USE " +
tenantIdentifier);
} catch (SQLException e) {
throw new HibernateException(
" Não pode alterar a conexão para o esquema especificado ["
+ tenantIdentifier + "]", e);
}
connectionProvider.closeConnection(connection);
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 19/23
}
//Métodos não utilizados neste exemplo, mas que precisam ser sobrescritos.
@Override
public boolean isUnwrappableAs(@SuppressWarnings("rawtypes")
Class arg0) {…
@Override
public <T> T unwrap(Class<T> arg0) {…
@Override
public boolean supportsAggressiveRelease() {…
}
Para finalizar, propõe-se a criação de uma classe para inserir alguns registros na base de
dados, apenas para demonstrar o uso da funcionalidade de Multi-Tenancy. A
implementação desta visa obter sessões de acordo com o inquilino desejado e realizar
inserções utilizando a sessão adquirida. A Listagem 9 apresenta o código dessa classe.
Um detalhe importante nesta classe é a definição do método
configureSessionFactory(), que segue o novo modelo definido pelo Hibernate para
obtenção de uma SessionFactory. Seu funcionamento baseia-se essencialmente na
utilização do arquivo XML de propriedades para configurar novas fábricas de sessão.
Listagem 9. Código da classe de testes MultiTenancyEsquemaExclusivo.
package br.edu.utfpr.application;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import br.edu.utfpr.modelo.Pessoa;
public class MultiTenancyEsquemaExclusivo {
// Fábrica de sessões
private static SessionFactory sessionFactory;
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 20/23
public static void main(String[] args) {
sessionFactory = configureSessionFactory();
//Obtenção de sessão através do identificador do cliente1
Session session = sessionFactory.withOptions()
.tenantIdentifier("cliente1").openSession();
session.beginTransaction();
Pessoa pessoa = new Pessoa();
pessoa.setId(1L);
pessoa.setNome("Tenant One");
session.save(pessoa);
session.getTransaction().commit();
//Encerrando sessão do cliente1
session.close();
//Obtenção de sessão através do identificador do cliente2
session = sessionFactory.withOptions().tenantIdentifier("cliente2")
.openSession();
session.beginTransaction();
Pessoa pessoa2 = new Pessoa();
pessoa2.setId(1L);
pessoa2.setNome("Tenant Two");
session.save(pessoa2);
session.getTransaction().commit();
//Encerrando sessão do cliente2
session.close();
}
// Método que realiza as configurações da fábrica de sessões
private static SessionFactory configureSessionFactory()
throws HibernateException {
Configuration configuration = new Configuration().configure();
ServiceRegistryBuilder serviceRegistryBuilder =
new ServiceRegistryBuilder();
serviceRegistryBuilder.applySettings
(configuration.getProperties());
ServiceRegistry serviceRegistry =
serviceRegistryBuilder.buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory
(serviceRegistry);
return sessionFactory;
}
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 21/23
}
A Listagem 10 apresenta o resultado obtido após a execução da classe de testes
MultiTenancyEsquemaExclusivo. Esse resultado demonstra que o processo de
inserção seguiu a definição do cliente, conforme os parâmetros utilizados na obtenção de
novas sessões, e que os dados foram armazenados de acordo com a separação por
esquema.
Listagem 10. Resultado da execução da aplicação.
Mar 10, 2013 3:53:07 AM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
Hibernate:
insert
into
Pessoa
(nome, id)
values
(?, ?)
Hibernate:
insert
into
Pessoa
(nome, id)
values
(?, ?)
A Listagem 11 apresenta duas consultas feitas nas tabelas para checar os resultados
das inserções. Como pode ser visto a partir dos registros retornados, as ações de
inserção foram bem sucedidas.
Listagem 11. Resultado das consultas realizadas nas tabelas de cada cliente.
mysql> USE cliente1;
mysql> SELECT * FROM Pessoa;
+----+------------+
| id | nome |
+----+------------+
| 1 + Tenant One |
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 22/23
+----+------------+
mysql> USE cliente2;
mysql> SELECT * FROM Pessoa;
+----+------------+
| id | nome |
+----+------------+
| 1 + Tenant Two |
+----+------------+
Conclusão
Este artigo apresentou as opções de suporte que o framework Hibernate, na versão 4,
oferece ao modelo arquitetural Multi-Tenant. Foram descritas algumas das características
presentes na nova versão da ferramenta e um dos recursos adicionados foi trabalhado
em um exemplo prático.
Além de expor variações do modelo Multi-Tenant, foi construída uma aplicação a fim de
exemplificar a atuação do framework sobre uma destas alternativas. O modelo escolhido
define que cada cliente possui um esquema exclusivo em uma base de dados
compartilhada.
O exemplo abordado serve para compreender e aplicar a solução em um dos possíveis
modelos de arquitetura, porém, cabe ao arquiteto do sistema optar pela opção que
melhor se ajusta às necessidades do projeto, levando em consideração os fatores
positivos e negativos relacionados à sua adoção.
Dentre as principais vantagens associadas ao emprego de uma solução Multi-Tenant,
destacam-se a significativa redução de custos com recursos físicos, devido ao
compartilhamento e reutilização de infraestrutura de hardware, e a integridade dos dados
dos diversos clientes, garantida pelo isolamento que os modelos proporcionam.
Em contrapartida, podem ser considerados aspectos negativos: a dificuldade de calcular
os recursos necessários para cada novo cliente, garantindo que os demais inquilinos não
sofram influência negativa desta inclusão, e o risco associado a uma possível falha nos
recursos de uso compartilhado, que pode acabar afetando vários clientes e ocasionar
uma perda de grandes volumes de dados.
29/7/2014 Introdução a Multi-Tenancy com Hibernate 4
http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=29114 23/23
Links
Hibernate – Community Documentation – Multi-Tenancy
http://docs.jboss.org/hibernate/core/4.1/devguide/en-US/html/ch16.html
Hibernate 4: multitenancy, extensões, OSGI e uma entrevista com o líder do
projeto
http://www.infoq.com/br/news/2012/01/hibernate-4
Multi-Tenant Data Architecture
http://msdn.microsoft.com/en-us/library/aa479086.aspx
Using Hibernate to Implement Multi-Tenant Cloud Architecture
http://www.devx.com/Java/Article/47817/0/page/2
What is Hibernate
http://onjava.com/pub/a/onjava/2005/09/21/what-is-hibernate.html
Hibernate JavaDoc 4.1
http://docs.jboss.org/hibernate/orm/4.1/javadocs/
Hibernate – JBoss Community
http://www.hibernate.org
DevMedia - Equipe De Moderação
A DevMedia é um portal para analistas, desenvolvedores de sistemas, gerentes e DBAs com milhares de
artigos, dicas, cursos e videoaulas gratuitos e exclusivos para assinantes.