A Data Geekery liberou a versão 3.9.0 do jOOQ, sua ferramenta de mapeamento objeto-relacional (ORM) para Java que gera código a partir de bancos de dados para consultas type-safe. O projeto foi lançado originalmente em 2010. As novas funcionalidades desse release incluem:
- Um parser experimental:
- Converte comandos SQL em expressões hierárquicas do jOOQ.
- Integração com um framework verificador:
- Validação adicional de tipos de dados para o jOOQ.
- Melhorias na integração com Oracle 12c e PL/SQL:
- Suporte a novas funcionalidades no Oracle 12c.
- Suporte à API Java Time da JSR-310:
- Uma única API que suporta tipos de dados de data e hora tradicionais do JDBC e a API Java Time.
A versão open source do jOOQ suporta os seguintes bancos de dados:
- MySQL 5.5, 5.6, 5.7, 8.0
- PostgreSQL 9.3 e posteriores
- MariaDB 5.2 e posteriores
- CUBRID 8.4 e posteriores
- Apache Derby 10.10 e posteriores
- Firebird 2.5, 3.0
- H2 1.3, 1.4
- HSQLDB 2.2 e posteriores
- SQLite 3
Uma variedade de opções de licenciamento estão disponíveis na página 'Licenses' do site do projeto.
Primeiros passos
Para desenvolver uma aplicação com o jOOQ, considere o diagrama abaixo de entidades e relacionamentos, de um banco de dados de publicações chamado 'pubs':
Para começar a usar o JOOQ, inclua as dependências do driver do banco de dados e do gerador de código do jOOQ (usando o Maven):
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.3</version> </dependency> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq</artifactId> <version>3.9.0</version> </dependency> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq-meta</artifactId> <version>3.9.0</version> </dependency> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq-codegen</artifactId> <version>3.9.0</version> </dependency> </dependencies>
As configurações de conexão ao banco de dados são definidas na seção <profile> do POM do Maven e serão referenciadas posteriormente nas configurações do plugin do jOOQ.
<profile> <id>default</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <jdbc.user>root</jdbc.user> <jdbc.password></jdbc.password> <jdbc.url>jdbc:mysql://localhost:3306/pubs</jdbc.url> <jdbc.driver>com.mysql.cj.jdbc.Driver</jdbc.driver> </properties> </profile>
O exemplo abaixo de consulta SQL será modelado com a API fluente do jOOQ:
SELECT title, publish_date, authors.last_name, types.type, publishers.publisher FROM publications INNER JOIN authors ON authors.id = publications.author_id INNER JOIN types ON types.id = publications.type_id INNER JOIN publishers ON publishers.id = publications.publisher_id;
Usando o código gerado pelo jOOQ, é possível desenvolver uma aplicação para acessar o banco de dados utilizando consultas type-safe.
public class Application { public static void main(String[] args) throws Exception { String user = System.getProperty("jdbc.user"); String password = System.getProperty("jdbc.password"); String url = System.getProperty("jdbc.url"); String driver = System.getProperty("jdbc.driver"); Class.forName(driver).newInstance(); try(Connection connection = DriverManager.getConnection(url,user,password)) { DSLContext dslContext = DSL.using(connection,SQLDialect.MYSQL); Result<Record> result = dslContext.select() .from(PUBLICATIONS) .join(AUTHORS) .on(AUTHORS.ID.equal(PUBLICATIONS.AUTHOR_ID)) .join(TYPES) .on(TYPES.ID.equal(PUBLICATIONS.TYPE_ID)) .join(PUBLISHERS) .on(PUBLISHERS.ID.equal(PUBLICATIONS.PUBLISHER_ID)) .fetch(); for(Record record : result) { Long id = record.getValue(PUBLICATIONS.ID); String title = record.getValue(PUBLICATIONS.TITLE); Long authorID = record.getValue(PUBLICATIONS.AUTHOR_ID); String lastName = record.getValue(AUTHORS.LAST_NAME); String firstName = record.getValue(AUTHORS.FIRST_NAME); String type = record.getValue(TYPES.TYPE); String publisher = record.getValue(PUBLISHERS.PUBLISHER); Date publishDate = record.getValue(PUBLICATIONS.PUBLISH_DATE); } } catch(Exception exception) { exception.printStackTrace(); } } }
Note o uso de minúsculas para os nomes de tabelas e de campos gerados pelo jOOQ. O código do exemplo pode ser obtido no GitHub.
O InfoQ entrevistou Lukas Eder, fundador e CEO da Data Geekery sobre a nova versão do jOOQ.
InfoQ: Quais são as suas responsabilidades na Data Geekery?
Eder: Além de liderar a empresa, trabalho com consultoria em SQL e PL/SQL, principalmente com otimização e performance. Também ministramos treinamentos em SQL e pretendo escrever um livro sobre SQL ainda este ano.
InfoQ: Quais sãos os diferenciais do jOOQ com relação a outros frameworks de ORM para Java como Hibernate, Speedment e Apache Torque?
Eder: Na minha opinião é mais interessante comparar filosofias e abordagens do que implementações individuais. Acredito que existem basicamente cinco abordagens para se trabalhar com bancos relacionais. Para cada uma delas vou listar alguns produtos como exemplo (sem pretender mencionar todos):
- Manter a lógica SQL fora do código Java:
- MyBatis, stored procedures específicas de cada banco, views, stored procedures do jOOQ
- Codificar a lógica SQL como strings no código Java:
- Codificar a lógica SQL como uma linguagem específica a domínio (DSL) focada em SQL:
- jOOQ, Criteria API (para o JPQL, não SQL)
- Codificar a lógica SQL como uma API de coleções 'idiomática':
- Codificar a lógica SQL em Java através de mapeamentos objeto-relacionais ou registros ativos:
- JPA e suas implementações, incluindo Hibernate, jOOQ UpdatableRecords, Active JDBC
Todas essas abordagens têm suas vantagens e desvantagens. O jOOQ tem foco maior nas três primeiras, pois são focadas em SQL. A linguagem SQL é um aspecto importante de como os usuários interagem com seus bancos de dados. Para estes usuários, é proibitivo o peso cognitivo imposto por APIs de coleções 'idiomáticas' ou mapeamento objeto-relacional. Eles só querem escrever SQL.
A funcionalidade principal do jOOQ é a sua API fluente, que é suportada pela geração automática de código e possibilita que desenvolvedores tenham acesso à validação de tipos de dados em tempo de compilação, sem comprometer demais a natureza da linguagem SQL. Escrevi sobre esta técnica de DSL no nosso blog.
Além disso, o jOOQ encoraja desenvolvedores a:
- Levar a lógica de negócio para dentro do banco de dados, através de views e stored procedures, que também são fáceis de utilizar com jOOQ.
- Utilizar SQL avançado e específico a cada banco, que são úteis principalmente para o desenvolvimento de relatórios e análise de dados.
- Pensar de forma centrada no banco de dados, o que é uma ótima maneira de se trabalhar quando seu sistema cresce além de um banco trivial com um único cliente e dez tabelas.
As abordagens diferentes não precisam necessariamente competir entre si. Vários usuários do jOOQ, por exemplo, também usam Hibernate, na mesma aplicação. Por exemplo, usam o jOOQ para análise, ETL, relatórios e consultas complexas; e o Hibernate para CRUDs complexos ao persistir várias entidades em uma única transação
Quanto à implementação, o jOOQ enfatiza a importância da linguagem SQL para os clientes que buscam por isso. Eu diria que o jOOQ ajuda os clientes a compreender que SQL é geralmente uma alternativa melhor para vários problemas enfrentados.
InfoQ: Fale um pouco sobre os parceiros e clientes que utilizam o jOOQ
Nossa base base de clientes é muito diversificada. Originalmente desenvolvemos o jOOQ para empresas que trabalham e pensam de forma parecida com a nossa. Antes de fundar a Data Geekery, trabalhei para um grande banco suíço em um projeto de e-banking. Atualmente, ainda os ajudo a resolver problemas de performance com SQL no Oracle com o jOOQ. O sistema tem cerca de 500 tabelas, algumas com bilhões de linhas; milhares de views, centenas de packages PL/SQL e muito código Java. Existe muita lógica de negócio implementada em views e stored procedures complexas. Claro que o sistema poderia ter sido construído de várias outras formas, mas o foco em SQL leva a um projeto bem elegante, e que tem performance muito boa no Oracle.
Nem todas as empresas têm bancos de dados complexos como no caso acima. De qualquer maneira, o diferencial do jOOQ para essas empresas é a simplicidade que o traz para o desenvolvimento Java/SQL. O SQL é uma linguagem antiga e às vezes peculiar, com suas múltiplas palavras chave e sintaxe interessante (escrevi recentemente sobre isso.)
Mas existe uma grande beleza na programação declarativa, que foi inspirada pela álgebra relacional. A possibilidade de se escrever comandos SQL de forma simples e intuitiva com jOOQ inspira os desenvolvedores. O melhor comentário que eu ouvi (de vários clientes) é como jOOQ tem ajudados eles a descobrir o mundo vasto e empolgante do SQL.
InfoQ: O que está planejado para o jOOQ?
Eder: Adoramos tudo relacionado a SQL. Atualmente estamos testando um parser SQL embutido (adicionado na versão 3.9). O jOOQ é apenas uma API hierárquica para expressões SQL: usuários que constroem comandos SQL com jOOQ não escrevem strings; eles criam expressões hierárquicas que então geram o comandos SQL.
Por que não fazer o inverso e transformar um comando SQL em uma expressão hierárquica do jOOQ? Isso permitiria usuários a traduzir de uma string SQL (por exemplo do DB2) para outra string SQL (por exemplo do PostgreSQL) - uma ferramenta ótima para migrar bancos de dados legados.
O jOOQ já possui uma SPI (Service Provider Interface) de transformação de SQL embutida que permite transformar a expressão hierárquica em algo diferente. As possíveis funcionalidades seriam multi-tenancy, segurança em nível de linhas, otimizações e mais. Essas funcionalidades estão disponíveis em bancos comerciais caros, mas não em vários BDs open source. Nós já temos o framework; no futuro ofereceremos essas funcionalidades prontas para uso.
Uma das funcionalidades mais interessantes do padrão SQL:2011 é a possibilidade de escrever consultas temporais. Imagine uma companhia de seguros, onde uma certa regra é modificada. Diferentemente do SQL clássico, com o SQL:2011 não alteramos um registro com UPDATE; criamos um novo registro que contém uma validade temporal diferente.
O SQL:2011 permite fazer (de forma transparente) um UPDATE temporal que é internamente traduzido em vários comandos UPDATE e INSERT. O mesmo ocorre para comandos DELETE temporais. Estamos tentando emular essa funcionalidade para todos os bancos de dados, incluindo os que não suportam comandos temporais (ou seja, a maioria, exceto Oracle e DB2).
Recursos adicionais
Veja outros recursos sobre o jOOQ (todos em inglês):