Skip to content

1. Introdução

O PDF deste documento está disponível |AQUI|.

Os exemplos deste documento estão disponíveis |AQUI|.

1.1. Índice

Neste documento, propomos estudar diferentes configurações de implementação de bases de dados. Considere a seguinte arquitetura em camadas:

O fluxo de execução decorre da esquerda para a direita:

  • uma das classes na camada [ui] (Interface do Utilizador) é executada primeiro. Esta instancia as camadas [business] e [DAO]. Se a camada [ui] for uma interface gráfica do utilizador, aguarda então as ações do utilizador. Uma ação do utilizador pode desencadear a execução de métodos em todas as camadas da arquitetura, até ao banco de dados. O resultado destas execuções é devolvido ao utilizador de uma forma ou de outra;

As funções das diferentes camadas podem ser as seguintes:

  • A camada [JDBC] (Java Database Connectivity) é uma interface universal de acesso a bases de dados. Apresenta sempre a mesma interface à camada [DAO]. Se mudar de SGBD, basta alterar o controlador JDBC. A camada [DAO] permanece inalterada se tiver tido o cuidado de seguir um determinado conjunto de regras. No entanto, é difícil garantir 100% de portabilidade entre SGBDs, pois estes frequentemente contêm uma quantidade significativa de SQL proprietário que é difícil de ignorar, uma vez que muitas vezes proporciona ganhos de desempenho. Assim que se utiliza SQL proprietário, a portabilidade entre SGBDs deixa de ser possível. Além disso, os SGBDs têm frequentemente políticas diferentes para a geração automática de chaves primárias, bem como palavras-chave reservadas que variam de um sistema para outro. Neste documento, conseguimos, no entanto, portar a arquitetura JDBC estudada para seis SGBDs diferentes, aceitando que é necessário um projeto de configuração para cada um deles;
  • a camada [DAO] expõe uma interface para aceder aos dados da base de dados específica que está a ser utilizada (a distinguir da interface JDBC, que expõe métodos válidos para qualquer SGBD);
  • a camada [business] implementa as regras de gestão da aplicação ou regras de negócio.
    • Os seus dados de entrada consistem em dados do banco de dados via a camada [DAO] e/ou entradas do usuário transmitidas a ela pela camada [UI];
    • Produz dados que pode guardar na base de dados através da camada [DAO] e/ou devolver à camada [UI] que os solicitou, para apresentação ao utilizador;
  • A camada [UI] é a camada que executa as ações do utilizador e devolve os resultados dessas ações ao utilizador;

Acima, a camada [DAO] envia consultas SQL à camada [JDBC] para execução no SGBD. Nos últimos anos (desde 2006), esta arquitetura evoluiu da seguinte forma:

Agora é a camada JPA (Java Persistence API) que envia consultas SQL para a camada JDBC e recebe os resultados. A camada [JPA] apresenta operações à camada [DAO] para persistir, modificar, eliminar e recuperar objetos. A camada [DAO] já não emite comandos SQL. Esta abordagem é mais portátil porque as implementações JPA lidam com as diferenças entre os DBMS, mas é mais lenta do que a tecnologia JDBC. Iremos realizar testes de desempenho para demonstrar isto. A tecnologia JPA formaliza o trabalho realizado pela estrutura Hibernate [http://hibernate.org/] há anos.

Iremos examinar duas camadas [DAO] utilizando uma das duas arquiteturas seguintes:

Exigiremos que as camadas [DAO1] e [DAO2] implementem a mesma interface [IDAO]. Assim, o teste [JUnitTestsDao] será o mesmo para ambas as configurações e permitir-nos-á comparar o desempenho. A camada [DAO1] será implementada com o Spring JDBC e a camada [DAO2] com o Spring JPA;

Assim que isto estiver feito, iremos expor a interface [IDAO] na web da seguinte forma:

  • Em [1], a camada [IDAO] é exposta na Web através de uma camada Web [2] implementada pelo Spring MVC. É, de facto, a interface [IDAO] que é exposta, e iremos construir duas versões do serviço Web, dependendo de esta interface ser implementada utilizando uma arquitetura [DAO-JDBC] ou [DAO-JPA-JDBC];
  • Em [B], um cliente remoto utiliza as URLs expostas pelo serviço web, que fornecem acesso aos métodos da camada [IDAO-server]. Iremos garantir que a camada [DAO-Client] [3] implementa a interface [IDAO-server] [1]. Isto permitir-nos-á utilizar o mesmo teste [JUnitTestsDao] que já foi utilizado duas vezes [4];
  • Em [3], a camada [DAO-Client] será implementada utilizando o Spring RestTemplate;

Assim que isto estiver feito, iremos proteger o acesso ao serviço web:

  • em [5], o pedido HTTP do cliente passa por uma camada de autenticação implementada com o Spring Security;

Assim que isso estiver feito, evoluiremos a arquitetura anterior para a seguinte:

  • Em [3], a aplicação cliente é, ela própria, uma aplicação web. Incluirá um formulário [5] que permite aos utilizadores consultar os URLs do serviço web seguro. O acesso HTTP ao serviço web seguro será tratado através de uma camada [DAO-client-js] implementada em JavaScript. Esta arquitetura utiliza o que se designa por pedidos entre domínios:
    • o serviço web [2] fornece URLs do tipo [http://machine1:port1/];
    • a aplicação web cliente [3] é descarregada a partir de um URL [http://machine2:port2/]. Se [http://machine2:port2/] não for idêntico a [http://machine1:port1/] (mesma máquina, mesma porta), então o navegador do cliente bloqueará as chamadas HTTP da camada [DAO-client-js]. Para resolver esta questão, o serviço web deve permitir pedidos entre domínios. Veremos como;

Os projetos apresentados foram testados com os seguintes seis SGBDs:

  • MySQL 5 Community Edition;
  • SQL Server 2014 Express;
  • PostgreSQL 9.4;
  • Oracle Express 11g Release 2;
  • IBM DB2 Express-C 10.5;
  • Firebird 2.5.4;

Para cada um destes SGBDs, desenvolvemos quatro camadas [DAO] diferentes:

  • uma camada implementada com Spring JDBC;
  • uma camada implementada com Spring JPA e o provedor Hibernate JPA;
  • uma camada implementada com Spring JPA e o provedor EclipseLink JPA;
  • uma camada implementada com Spring JPA e o provedor OpenJPA JPA;

Assim, é aqui apresentado um conjunto de vinte e quatro configurações diferentes. Envidámos um esforço significativo para factorizar o código:

  • a maior parte do código é escrita apenas uma vez. Baseia-se em dois projetos de configuração do Maven:
    • um configura a camada JDBC;
    • o outro configura a camada JPA;

O projeto de configuração Maven para a camada JDBC [1] de um SGBD específico consiste em duas etapas:

  • importar o arquivo do driver JDBC;
  • definir as credenciais de acesso para a base de dados em uso e as várias instruções SQL que a camada [DAO1] enviará ao controlador JDBC. Embora o SQL seja padronizado, deparámo-nos com problemas de portabilidade, principalmente devido à presença nas consultas de nomes de tabelas/colunas que se revelaram palavras-chave proibidas em determinados SGBDs (a tabela ROLES para o DB2, a coluna PASSWORD para o Firebird). Além disso, embora um nome de coluna seja normalmente insensível a maiúsculas e minúsculas, deparámo-nos com um problema no PostgreSQL relativamente à coluna ID da chave primária nas tabelas. Era necessário que fosse nomeada «id» em minúsculas. Estes são exemplos típicos de problemas de portabilidade inesperados;

Os três projetos Maven para configurar a camada JPA [2] de um SGBD específico também consistem em duas etapas:

  • importar o arquivo de implementação do JPA;
  • configurar a implementação JPA utilizada para o SGBD específico conectado. Na verdade, é a camada JPA que emite comandos SQL para a camada JDBC. Para ser eficaz, ela deve conhecer o SGBD a fim de enviar-lhe comandos SQL que ele reconheça. Esses comandos podem utilizar o SQL proprietário desse SGBD, bem como as suas características específicas (tipos de dados, sequências, gatilhos, procedimentos, geração automática de chaves primárias, etc.);

Isto resulta em vinte e quatro projetos de configuração Maven (4 configurações × 6 SGBDs) nos quais todos os outros projetos de operação de bases de dados se basearão. Nos diagramas acima, uma vez que as camadas [DAO1] e [DAO2] fornecem a mesma interface, as 24 configurações das duas arquiteturas acima serão testadas utilizando uma única classe de teste [JUnitTestsDao]. Uma vez verificadas estas arquiteturas, não há mais dificuldades:

  • o projeto Maven para publicar a base de dados na web baseia-se nestas duas arquiteturas. Existem, portanto, também 24 configurações possíveis aqui;
  • o projeto Maven para proteger o acesso ao serviço web baseia-se no projeto anterior e também tem 24 configurações possíveis;
  • Por fim, o projeto Maven que permite pedidos entre domínios para o serviço web seguro baseia-se no projeto anterior e também dispõe de 24 configurações possíveis;

O estudo é realizado utilizando o SGBD MySQL5 e a implementação JPA do Hibernate. Em seguida, portamos o código para as implementações JPA do Eclipselink e do OpenJPA. Por fim, portamo-lo para outras bases de dados (PostgreSQL, Oracle, SQL Server, DB2, Firebird).

Este curso destina-se a principiantes. A maioria dos conceitos utilizados é explicada. Não é necessário ter conhecimentos prévios de programação de bases de dados ou de programação web. No entanto, é necessário um conhecimento sólido da linguagem SQL, uma vez que as consultas SQL utilizadas não são explicadas.

Para compreender os exemplos, é necessário um conhecimento básico da linguagem Java, que pode ser adquirido em qualquer curso introdutório sobre a linguagem. Os dois primeiros capítulos do documento [Introdução à Linguagem Java] serão suficientes. Trata-se de um documento mais antigo (1998, revisto em 2002), mas os fundamentos estão lá. Para um curso abrangente, pode-se ler o extenso livro de Jean-Marie Doudoux [http://www.jmdoudoux.fr/java].

Este documento não é, de forma alguma, exaustivo. Destina-se exclusivamente a fornecer uma metodologia e código que possam ser reutilizados em contextos semelhantes. O documento foi escrito de forma a poder ser lido sem um computador à mão. Por isso, estão incluídas muitas capturas de ecrã.

Embora não abranja todas as capacidades da linguagem Java nem todas as suas áreas de aplicação, este documento pode ser utilizado como recurso de aprendizagem da linguagem. Ao seguir este documento — mesmo que não na sua totalidade —, um leitor iniciante alcançará um nível de «Java avançado» tanto na utilização da linguagem como na estrutura Spring. Poderá então continuar a sua formação em Java com os seguintes livros:

  • [Spring MVC and Thymeleaf by Example] [https://stahe.github.io/pt-springmvc-thymeleaf-janv-2015/], que dá continuidade à exploração do ecossistema Spring ao apresentar o seu ramo de “programação web MVC”;
  • [Tutorial AngularJS / Spring MVC] [https://stahe.github.io/pt-spring-angular1.x-juillet-2014/], que apresenta uma arquitetura web cliente/servidor, em que o cliente é implementado utilizando a estrutura [AngularJS] e o servidor utilizando [Spring MVC];
  • [Introdução ao Java EE], que se afasta do ecossistema Spring para uma arquitetura web baseada em JSF (Java Server Faces) e EJB (Enterprise JavaBeans);
  • [Introdução à Programação para Tablets Android] [https://stahe.github.io/pt-android-aout-2016/], que descreve uma arquitetura cliente/servidor, em que o cliente é um tablet Android e o servidor é um serviço web implementado pelo Spring MVC;

1.2. Fontes

Este documento tem duas fontes principais:

  • [ ref1]: [Spring MVC e Thymeleaf por Exemplo] na URL [https://stahe.github.io/pt-springmvc-thymeleaf-janv-2015/]. Este documento revisita o trabalho realizado e apresentado em [ref1] utilizando uma base de dados diferente. Em termos simples, retira-o do contexto da programação web com Spring MVC. Decidi criar um documento separado porque considerei que o código e a metodologia utilizados em [ref1] para expor uma base de dados na web eram reutilizáveis;
  • [ ref2]: [Java Persistence in Practice] na URL [https://stahe.github.io/pt-jpa-juin-2007/];

Para saber mais sobre o Spring, pode utilizar as seguintes referências:

Os leitores com conhecimentos insuficientes de SQL podem aprender os conceitos básicos no livro [Introdução ao SQL com o SGBD Firebird] no URL [https://stahe.github.io/pt-sql-firebird-janv-2006/].

1.3. Ferramentas utilizadas

Os exemplos a seguir foram testados no seguinte ambiente:

Nota relativa ao JDK 1.8: Um método no estudo de caso utiliza um método do pacote [java.lang] no Java 8.

A maioria dos exemplos são projetos Maven que podem ser abertos no Eclipse, IntelliJ IDEA ou NetBeans. A seguir, as capturas de ecrã são do IDE Spring Tool Suite, uma variante do Eclipse.

1.4. Os exemplos

Os exemplos estão disponíveis |AQUI| como um ficheiro ZIP para download.

  • Em [1], as pastas de exemplos;
  • em [2], a pasta [spring-core] contém os projetos de aprendizagem do Spring;
  • em [3], a pasta [spring-database-config] contém os projetos de configuração JDBC e JPA para as seis bases de dados;
  • em [4], a configuração do SGBD Oracle. Contém três pastas:
    • [databases] contém os scripts SQL para gerar as duas bases de dados utilizadas no documento;
    • [jdbc-driver] contém o controlador JDBC do Oracle, bem como um script para o instalar no repositório local do Maven;
    • [eclipse] contém [5] os quatro projetos de configuração Oracle:
      • [oracle-config-jdbc] configura a camada JDBC para aceder ao SGBD;
      • [oracle-config-jpa-hibernate] configura a camada JPA para aceder ao SGBD utilizando o fornecedor JPA do Hibernate;
      • [oracle-config-jpa-eclipselink] configura a camada JPA para acesso à base de dados utilizando o fornecedor JPA Eclipselink;
      • [oracle-config-jpa-openjpa] configura a camada JPA para acesso à base de dados utilizando o fornecedor JPA OpenJPA;
  • em [6], a pasta [eclipse config / launch configurations] contém as configurações de lançamento que o leitor pode importar para o Eclipse e, em seguida, adaptar ao seu próprio ambiente;
  • em [7], a pasta [spring-database-generic] contém todo o código de acesso à base de dados comum aos seis SGBDs e aos três fornecedores JPA;
  • Em [8], [spring-jdbc] contém quatro projetos que demonstram a API JDBC, bem como o Spring JDBC;
  • Em [9], [spring-jpa / spring-jpa-generic] é o projeto que utiliza uma camada JPA para aceder a uma base de dados. Os projetos [generic-create-db*] são projetos JPA utilizados para criar as bases de dados utilizadas pela camada JPA;
  • Em [10], a pasta [spring-webjson] contém os projetos que expõem a base de dados na Web;
    • [spring-webjson-server-jdbc-generic] é o serviço web que expõe a base de dados acedida através do Spring JDBC;
    • [spring-webjson-server-jpa-generic] é o serviço web que expõe a base de dados acedida através do Spring JPA;
    • [spring-webjson-client-generic] é o único cliente que permite o acesso aos dois serviços web anteriores;
  • em [11], a pasta [spring-security] contém os projetos que expõem a base de dados na Web com acesso seguro;
    • [spring-security-server-jdbc-generic] é o serviço web seguro que expõe a base de dados acedida através do Spring JDBC;
    • [spring-security-server-jpa-generic] é o serviço web seguro que expõe a base de dados acedida através do Spring JPA;
    • [spring-security-client-generic] é o único cliente que permite o acesso aos dois serviços web seguros anteriores;
  • em [12], a pasta [spring-cors] contém os projetos que expõem a base de dados na Web com acesso seguro, permitindo o acesso entre domínios, como o proveniente do código JavaScript de um navegador;
    • [spring-cors-server-jdbc-generic] é o serviço web seguro que permite o acesso entre domínios e expõe a base de dados acedida através do Spring JDBC;
    • [spring-cors-server-jpa-generic] é o serviço web seguro que permite o acesso entre domínios e expõe a base de dados acedida através do Spring JPA;
    • [spring-cors-client-generic] é uma aplicação web que consulta os dois serviços web anteriores;