Banco de dados MySQL com Spring Boot
Pré-requisitos
Conhecimentos básicos em:
-
Maven/Gradle
-
JPA
-
Spring Boot
-
Spring Data
-
Docker
Introdução sobre o MySQL
MySQL é um sistema de gerenciamento de banco de dados relacional de código aberto sob os termos da Licença Pública Geral GNU, mas também tem inúmeras licenças proprietárias.
Um banco de dados relacional organiza dados em uma ou mais tabela de dados em que os tipos de dados podem estar relacionados entre si. Essas relações ajudam a estruturar os dados.
O MySQL era de propriedade e patrocinado pela empresa sueca MySQL AB, que foi comprada pela antiga Sun Microsystem, qual foi incorporada pela Oracle.
Segundo a DB-engines, o MySQL é o segundo banco de dados mais popular do mundo, e para chegar a esta conclusão eles levaram em conta os seguinte fatores:
-
Número de menções do sistema em sites;
-
Interesse geral no sistema;
-
Frequência de discussões técnicas sobre o sistema;
-
Número de ofertas de emprego;
-
Relevância nas redes sociais;

Sem mais delongas, vamos ao exemplo prático.
Subir o serviço do MySQL no Docker
Como o objetivo do post é a configuração do MySQL em projetos Spring Boot, não vamos perder tempo instalando o MySQL na máquina, então vamos subir o MySQL em um container Docker.
Para isso execute o seguinte comando no seu terminal.
docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0.23
O comando acima, basicamente sobe o serviço do MySQL na versão 8.0.23
em um container Docker, definindo a senha do banco de dados como root
, mapeando acesso a porta 3306
.
Configurando o MySQL em projetos Spring Boot
Considerando o seu conhecimento em Maven, basta adicionar as seguintes dependências no seu projeto.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
Após efetuar o download das dependências, vamos configurar as propriedades do MySQL e do JPA no projeto.
Para isso edite o arquivo de configuração application.properties
e adicione o seguinte conteúdo.
# usuário e senha de conexão com o banco de dados
spring.datasource.username=root
spring.datasource.password=root
# url de conexão do banco de dados
spring.datasource.url=jdbc:mysql://localhost:3306/blog?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&useSSL=false&useUnicode=yes&characterEncoding=UTF-8&useLegacyDatetimeCode=true&createDatabaseIfNotExist=true&useTimezone=true&serverTimezone=UTC
# apontamos para o JPA e Hibernate qual é o Dialeto do banco de dados
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
# deixamos o hibernate responsável por ler nossas entidades e criar as tabelas do nosso banco de dados automaticamente
spring.jpa.hibernate.ddl-auto=create
# configuração do Hibernate para reconhecer o nome de tabelas em caixa alta
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
# configurações de log
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
Para um melhor entendimento as explicações sobre as properidades de configurações estão comentadas no próprio arquivo.
Demonstração
Como demonstração vamos criar entidades para representar o relacionamento de tabelas de um Blog. Onde teremos as tabelas de autores, tags e posts, onde vários autores podem escrever um post, e o post pode ter relação com várias tags.
Mapeamento das tabelas em classes
Aqui vamos aplicar a técnica de Mapeamento objeto-relacional (ORM), que é utilizada para reduzir a impedância da programação orientada aos objetos utilizando bancos de dados relacionais. Mas não entrarei em detalhes sobre a implementação das classes a seguir, para não fugir escopo desse post.
package com.gasparbarancelli.mysql.entity;
import com.sun.istack.NotNull;
import javax.persistence.*;
import java.util.Objects;
@Entity
@Table(name = "TAG")
public class Tag {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
private Long id;
@Column(name = "DESCRIPTION", nullable = false, length = 100)
private String description;
@Deprecated
public Tag() {
}
private Tag(@NotNull String description) {
this.description = Objects.requireNonNull(description, "description must not be null");
}
public static Tag of(@NotNull String description) {
return new Tag(description);
}
public Long getId() {
return id;
}
public String getDescription() {
return description;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Tag tag = (Tag) o;
return Objects.equals(description, tag.description);
}
@Override
public int hashCode() {
return Objects.hash(description);
}
}
package com.gasparbarancelli.mysql.entity;
import com.sun.istack.NotNull;
import javax.persistence.*;
import java.util.Objects;
@Entity
@Table(name = "AUTHOR")
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
private Long id;
@Column(name = "NAME", nullable = false, length = 50)
private String name;
@Column(name = "LINKEDIN", length = 100)
private String linkedIn;
@Column(name = "FACEBOOK", length = 100)
private String faceBook;
@Column(name = "TWITTER", length = 100)
private String twitter;
@Column(name = "SUMMARY")
private String summary;
@Deprecated
public Author() {
}
private Author(@NotNull String name) {
this.name = Objects.requireNonNull(name, "name must not be null");
}
public static AuthorBuilder builder(@NotNull String name) {
return new AuthorBuilder(name);
}
public static class AuthorBuilder {
private final Author author;
public AuthorBuilder(@NotNull String name) {
this.author = new Author(name);
}
public AuthorBuilder linkedIn(String linkedIn) {
this.author.linkedIn = linkedIn;
return this;
}
public AuthorBuilder faceBook(String faceBook) {
this.author.faceBook = faceBook;
return this;
}
public AuthorBuilder twitter(String twitter) {
this.author.twitter = twitter;
return this;
}
public AuthorBuilder summary(String summary) {
this.author.summary = summary;
return this;
}
public Author build() {
return this.author;
}
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public String getLinkedIn() {
return linkedIn;
}
public String getFaceBook() {
return faceBook;
}
public String getTwitter() {
return twitter;
}
public String getSummary() {
return summary;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Author author = (Author) o;
return name.equals(author.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
package com.gasparbarancelli.mysql.entity;
import com.sun.istack.NotNull;
import org.springframework.data.annotation.LastModifiedDate;
import javax.persistence.*;
import java.time.LocalDate;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@Entity
@Table(name = "POST")
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
private Long id;
@Column(name = "TITLE", nullable = false, length = 100)
private String title;
@LastModifiedDate
@Column(name = "LAST_MODIFIED", nullable = false)
private LocalDate lastModified;
@Column(name = "SUMMARY", nullable = false)
private String summary;
@Column(name = "DESCRIPTION", nullable = false)
private String description;
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private final Set<PostTag> tags = new HashSet<>();
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private final Set<PostAuthor> authors = new HashSet<>();
@Deprecated
public Post() {
}
private Post(@NotNull String title, @NotNull String summary, @NotNull String description) {
this.title = Objects.requireNonNull(title, "title must not be null").trim();
this.summary = Objects.requireNonNull(summary, "summary must not be null");
this.description = Objects.requireNonNull(description, "description must not be null");
this.lastModified = LocalDate.now();
}
public static Post of(@NotNull String title, @NotNull String summary, @NotNull String description) {
return new Post(title, summary, description);
}
public Long getId() {
return id;
}
public String getTitle() {
return title;
}
public LocalDate getLastModified() {
return lastModified;
}
public String getSummary() {
return summary;
}
public String getDescription() {
return description;
}
public Set<PostTag> getTags() {
return Collections.unmodifiableSet(tags);
}
public Post addTag(Tag tag) {
this.tags.add(PostTag.of(tag, this));
return this;
}
public Post addTags(Iterable<Tag> tags) {
tags.forEach(this::addTag);
return this;
}
public Set<PostAuthor> getAuthors() {
return Collections.unmodifiableSet(authors);
}
public Post addAuthor(Author author) {
this.authors.add(PostAuthor.of(author, this));
return this;
}
public Post addAuthors(Iterable<Author> authors) {
authors.forEach(this::addAuthor);
return this;
}
@PreUpdate
public void preUpdate() {
lastModified = LocalDate.now();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Post post = (Post) o;
return Objects.equals(title, post.title);
}
@Override
public int hashCode() {
return Objects.hash(title);
}
}
package com.gasparbarancelli.mysql.entity;
import com.sun.istack.NotNull;
import javax.persistence.*;
import java.util.Objects;
@Entity
@Table(name = "POST_TAG")
public class PostTag {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
private Long id;
@ManyToOne(optional = false)
@JoinColumn(name = "ID_TAG")
private Tag tag;
@ManyToOne(optional = false)
@JoinColumn(name = "ID_POST")
private Post post;
@Deprecated
public PostTag() {
}
private PostTag(@NotNull Tag tag, @NotNull Post post) {
this.tag = Objects.requireNonNull(tag, "tag must not be null");
this.post = Objects.requireNonNull(post, "post must not be null");
}
public static PostTag of(@NotNull Tag tag, @NotNull Post post) {
return new PostTag(tag, post);
}
public Long getId() {
return id;
}
public Tag getTag() {
return tag;
}
public Post getPost() {
return post;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PostTag postTag = (PostTag) o;
return Objects.equals(tag, postTag.tag) && Objects.equals(post, postTag.post);
}
@Override
public int hashCode() {
return Objects.hash(tag, post);
}
}
package com.gasparbarancelli.mysql.entity;
import com.sun.istack.NotNull;
import javax.persistence.*;
import java.util.Objects;
@Entity
@Table(name = "POST_AUTHOR")
public class PostAuthor {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
private Long id;
@ManyToOne(optional = false)
@JoinColumn(name = "ID_AUTHOR")
private Author author;
@ManyToOne(optional = false)
@JoinColumn(name = "ID_POST")
private Post post;
@Deprecated
public PostAuthor() {
}
private PostAuthor(@NotNull Author author, @NotNull Post post) {
this.author = Objects.requireNonNull(author, "author must not be null");
this.post = Objects.requireNonNull(post, "post must not be null");
}
public static PostAuthor of(@NotNull Author author, @NotNull Post post) {
return new PostAuthor(author, post);
}
public Long getId() {
return id;
}
public Author getAuthor() {
return author;
}
public Post getPost() {
return post;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PostAuthor that = (PostAuthor) o;
return Objects.equals(author, that.author) && Objects.equals(post, that.post);
}
@Override
public int hashCode() {
return Objects.hash(author, post);
}
}
Teste
Para garantirmos se a configuração e o mapeamento foram feitos de forma correta, vamos criar algumas interfaces que serão responsáveis por todas as operações das nossas tabelas com o banco de dados.
package com.gasparbarancelli.mysql.repository;
import com.gasparbarancelli.mysql.entity.Author;
import org.springframework.data.jpa.repository.JpaRepository;
public interface AuthorRepository extends JpaRepository<Author, Long> {
}
package com.gasparbarancelli.mysql.repository;
import com.gasparbarancelli.mysql.entity.Tag;
import org.springframework.data.jpa.repository.JpaRepository;
public interface TagRepository extends JpaRepository<Tag, Long> {
}
package com.gasparbarancelli.mysql.repository;
import com.gasparbarancelli.mysql.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PostRepository extends JpaRepository<Post, Long> {
}
Ao herdarmos JpaRepository
o Spring Data será responsável por criar uma implementação das nossas interfaces em tempo de execução, e com isso ganhamos produtividade, pois essas interfaces vão prover inúmeros métodos para manipular os objetos diretamente no banco de dados.
Agora vamos criar uma classe que vai popular nosso banco de dados e por fim realizar algumas consultas.
import com.gasparbarancelli.mysql.entity.Author;
import com.gasparbarancelli.mysql.entity.Post;
import com.gasparbarancelli.mysql.entity.Tag;
import com.gasparbarancelli.mysql.repository.AuthorRepository;
import com.gasparbarancelli.mysql.repository.PostRepository;
import com.gasparbarancelli.mysql.repository.TagRepository;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class Demo implements ApplicationRunner {
private final TagRepository tagRepository;
private final AuthorRepository authorRepository;
private final PostRepository postRepository;
public Demo(TagRepository tagRepository, AuthorRepository authorRepository, PostRepository postRepository) {
this.tagRepository = tagRepository;
this.authorRepository = authorRepository;
this.postRepository = postRepository;
}
@Override
public void run(ApplicationArguments args) throws Exception {
var post = Post.of(
"Banco de dados MySQL com Spring Boot",
"O MySQL é um sistema de gerenciamento de banco de dados...",
"O MySQL é um sistema de gerenciamento de banco de dados, que utiliza a linguagem SQL como interface. É atualmente um dos sistemas de gerenciamento de bancos de dados mais populares..."
);
var author = Author.builder("Gaspar Barancelli Junior")
.linkedIn("https://www.linkedin.com/in/gaspar-barancelli-junior-77681881/")
.twitter("https://twitter.com/gasparbjr")
.faceBook("https://www.facebook.com/gaspar.barancelli/")
.summary("Senior software engineer at Dextra, passionate about technology, because I understand that through it we can bring people together and make our world a better")
.build();
authorRepository.save(author);
post.addAuthor(author);
var tag = Tag.of("Java");
tagRepository.save(tag);
post.addTag(tag);
var tags = List.of(
Tag.of("Mysql"),
Tag.of("Banco de Dados"),
Tag.of("JPA")
);
tagRepository.saveAll(tags);
post.addTags(tags);
postRepository.save(post);
postRepository.findAll().forEach(it -> {
System.out.printf("Post - ID[%d], TITLE[%s]%n", it.getId(), it.getTitle());
it.getAuthors().forEach(postAuthor -> {
System.out.printf("PostAuthor - ID[%d], AUTHOR_NAME[%s]%n", postAuthor.getId(), postAuthor.getAuthor().getName());
});
it.getTags().forEach(postTag -> {
System.out.printf("PostTag - ID[%d], TAG_DESCRIPTION[%s]%n", postTag.getId(), postTag.getTag().getDescription());
});
});
authorRepository.findAll().forEach(it -> {
System.out.printf("Author - ID[%d], NAME[%s]%n", it.getId(), it.getName());
});
tagRepository.findAll().forEach(it -> {
System.out.printf("Tag - ID[%d], DESCRIPTION[%s]%n", it.getId(), it.getDescription());
});
}
}
O primeiro ponto a observar é a utilização da anotação @Repository
, pois ao utilizá-la o Spring traduz todas as exceções que são lançadas pelo banco de dados, convertendo-as para exceções do Spring. Isso é muito importante pois em um futuro facilita a migração de banco de dados, ou até fazer com que a aplicação trabalhe ao mesmo tempo com bancos de dados distintos.
No exemplo de teste também injetamos as interfaces criadas no passo anterior. É através delas que persistimos e buscamos os objetos no banco de dados.
Repare também que a classe implementa ApplicationRunner
, qual nos força a implementar o método run
, que é executado após o Spring criar todos os beans, e nesse método é que inserimos e buscamos objetos no banco de dados.
Ao executar a aplicação, temos a seguinte saída no console.
Post - ID[1], TITLE[Banco de dados MySQL com Spring Boot]
PostAuthor - ID[1], AUTHOR_NAME[Gaspar Barancelli Junior]
PostTag - ID[1], TAG_DESCRIPTION[Banco de Dados]
PostTag - ID[2], TAG_DESCRIPTION[Java]
PostTag - ID[3], TAG_DESCRIPTION[Mysql]
PostTag - ID[4], TAG_DESCRIPTION[JPA]
Author - ID[1], NAME[Gaspar Barancelli Junior]
Tag - ID[1], DESCRIPTION[Java]
Tag - ID[2], DESCRIPTION[Mysql]
Tag - ID[3], DESCRIPTION[Banco de Dados]
Tag - ID[4], DESCRIPTION[JPA]
Bônus - Utilização de scripts para migração de banco de dados
Vamos utilizar o Flyway como ferramenta para migração de banco de dados. Para isso vamos adicionar a dependências do Flyway no projeto.
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
Os scripts para migração devem estar localizados no diretório resources/db/migration
.

Como a imagem acima já trouxe um spoiler, o próximo passo é criar os scripts para migração. Por regra eles devem ter como prefixo o caractere V
seguido pelo número da sua versão Major, na sequência deve ter o caractere _
seguido pelo número da Minor, posteriormente os caracteres __
seguidos por um texto livre que serve como documentação, por fim a extensão .sql
.
Segue o contéudo dos scripts.
Script V1_1__create_table_tag.sql.
CREATE TABLE TAG (
ID BIGINT AUTO_INCREMENT NOT NULL,
DESCRIPTION VARCHAR(100) NOT NULL,
CONSTRAINT PK_TAG PRIMARY KEY (ID),
CONSTRAINT U_TAG_DESCRIPTION UNIQUE (DESCRIPTION)
);
Script V1_2__create_table_author.sql.
CREATE TABLE AUTHOR (
ID BIGINT AUTO_INCREMENT NOT NULL,
NAME VARCHAR(50) NOT NULL,
LINKEDIN VARCHAR(100),
FACEBOOK VARCHAR(100),
TWITTER VARCHAR(100),
SUMMARY TEXT,
CONSTRAINT PK_AUTHOR PRIMARY KEY (ID),
CONSTRAINT U_AUTHOR_NAME UNIQUE (NAME)
);
Script V1_3__create_table_post.sql.
CREATE TABLE POST (
ID BIGINT AUTO_INCREMENT NOT NULL,
TITLE VARCHAR(100) NOT NULL,
LAST_MODIFIED DATE NOT NULL,
SUMMARY TEXT NOT NULL,
DESCRIPTION TEXT NOT NULL,
CONSTRAINT PK_POST PRIMARY KEY (ID),
CONSTRAINT U_POST_TITLE UNIQUE (TITLE)
);
CREATE TABLE POST_TAG (
ID BIGINT AUTO_INCREMENT NOT NULL,
ID_POST BIGINT NOT NULL,
ID_TAG BIGINT NOT NULL,
CONSTRAINT PK_POST_TAG PRIMARY KEY (ID),
CONSTRAINT U_POST_TAG_FKS UNIQUE (ID_POST, ID_TAG),
CONSTRAINT FK_POST_TAG_POST FOREIGN KEY (ID_POST) REFERENCES POST (ID),
CONSTRAINT FK_POST_TAG_TAG FOREIGN KEY (ID_TAG) REFERENCES TAG (ID)
);
CREATE TABLE POST_AUTHOR (
ID BIGINT AUTO_INCREMENT NOT NULL,
ID_POST BIGINT NOT NULL,
ID_AUTHOR BIGINT NOT NULL,
CONSTRAINT PK_POST_AUTHOR PRIMARY KEY (ID),
CONSTRAINT U_POST_AUTHOR_FKS UNIQUE (ID_POST, ID_AUTHOR),
CONSTRAINT FK_POST_AUTHOR_POST FOREIGN KEY (ID_POST) REFERENCES POST (ID),
CONSTRAINT FK_POST_AUTHOR_AUTHOR FOREIGN KEY (ID_AUTHOR) REFERENCES AUTHOR (ID)
);
Agora altere o valor da propriedade spring.jpa.hibernate.ddl-auto
para none
, assim o Hibernate não vai criar as tabelas no banco de dados, deixando essa responsabilidade somente para o Flyway.
Também remova as tabelas existentes no banco de dados, caso contrario o Flyway vai lançar uma exceção.
Feito todos os passos anteriores, pode subir a aplicação e verificar no banco de dados, que o Flyway criou uma tabela para controle das execuções dos scripts, é por essa tabela que ele garante quando um script já foi executado, e quando houve alteração em algum script.
Bônus - Executar consultas nativas ao banco de dados
Em muitos casos precisamos executar consultas nativas em nosso banco de dados para ganhar performance, dentre tantos outros motivos. O problema disso é que ao executar essas consultas acabamos sujando nossas classes com concatenação de strings.
Por nossa sorte, existe um projeto chamado de Spring Native Query, com ele a execução de consultas nativas a banco de dados, se torna algo muito simples e o melhor de tudo, não poluímos as nossas classes com string gigantescas.
Vamos adicionar uma nova dependência ao projeto.
<dependency>
<groupId>io.github.gasparbarancelli</groupId>
<artifactId>spring-native-query</artifactId>
<version>1.0.29</version>
</dependency>
Também precisamos configurar o uso dessa biblioteca. Para isso, adicione as seguintes propriedades no arquivo de configuração application.properties
.
# pacote principal da nossa aplicação
native-query.package-scan=com.gasparbarancelli.mysqlnativequery
# extensão dos arquivos que contém as consultas nativas
native-query.file.sufix=sql
Por padrão a biblioteca padroniza o diretório onde ficam os arquivos contendo os scripts das consultas SQL. Os arquivos devem ficar no diretório resources/nativeQuery
.

Com os diretórios criados, agora podemos criar nosso arquivo contendo a consulta SQL.
Arquivo posts.sql.
SELECT
POST.TITLE as postTitle,
TAG.DESCRIPTION as tagDescription,
AUTHOR.NAME as authorName
FROM POST
INNER JOIN POST_TAG ON POST_TAG.ID_POST = POST.ID
INNER JOIN TAG ON TAG.ID = POST_TAG.ID_TAG
INNER JOIN POST_AUTHOR ON POST_AUTHOR.ID_POST = POST.ID
INNER JOIN AUTHOR ON AUTHOR.ID = POST_AUTHOR.ID_AUTHOR
WHERE 1=1
/* if (authorId != null) */
and AUTHOR.ID = :authorId
/* endif */
/* if (tagId != null) */
and TAG.ID = :tagId
/* endif */
A consulta SQL acima é bem simples, mas observe os parâmetros, utilizando a biblioteca Spring Native Query, podemos adicionar variáveis e inúmeras condições, pois os arquivos são processados antes de serem executados, portanto no exemplo acima, estamos adicionando condições dinâmicas, onde o filtro pelo código do autor e da tag são aplicados apenas se os valores recebidos nas variáveis não forem nulos.
O próximo passo é criar uma interface que aponta para essa consulta criada acima.
import com.gasparbarancelli.mysqlnativequery.to.PostTO;
import io.github.gasparbarancelli.NativeQuery;
import io.github.gasparbarancelli.NativeQueryParam;
import java.util.List;
public interface PostNativeQuery extends NativeQuery {
List<PostTO> posts(@NativeQueryParam("authorId") Long authorId, @NativeQueryParam("tagId") Long tagId);
}
Observer que a interface herda de NativeQuery
, que o método tem o mesmo nome do arquivo contendo a consulta SQL, e que os nomes dos parâmetros do método são os mesmos das variáveis utilizadas na consulta.
O Spring Native Query implementa as interfaces acima em tempo de execução, assim podemos injetar essa interface em qualquer bean do Spring.
Por fim, vamos alterar a nossa classe de testes utilizadas na primeira demonstração.
package com.gasparbarancelli.mysqlnativequery;
import com.gasparbarancelli.mysqlnativequery.entity.Author;
import com.gasparbarancelli.mysqlnativequery.entity.Post;
import com.gasparbarancelli.mysqlnativequery.entity.Tag;
import com.gasparbarancelli.mysqlnativequery.repository.AuthorRepository;
import com.gasparbarancelli.mysqlnativequery.repository.PostNativeQuery;
import com.gasparbarancelli.mysqlnativequery.repository.PostRepository;
import com.gasparbarancelli.mysqlnativequery.repository.TagRepository;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class Demo implements ApplicationRunner {
private final TagRepository tagRepository;
private final AuthorRepository authorRepository;
private final PostRepository postRepository;
private final PostNativeQuery postNativeQuery;
public Demo(TagRepository tagRepository, AuthorRepository authorRepository, PostRepository postRepository, PostNativeQuery postNativeQuery) {
this.tagRepository = tagRepository;
this.authorRepository = authorRepository;
this.postRepository = postRepository;
this.postNativeQuery = postNativeQuery;
}
@Override
public void run(ApplicationArguments args) throws Exception {
var post = Post.of(
"Banco de dados MySQL com Spring Boot",
"O MySQL é um sistema de gerenciamento de banco de dados...",
"O MySQL é um sistema de gerenciamento de banco de dados, que utiliza a linguagem SQL como interface. É atualmente um dos sistemas de gerenciamento de bancos de dados mais populares..."
);
var author = Author.builder("Gaspar Barancelli Junior")
.linkedIn("https://www.linkedin.com/in/gaspar-barancelli-junior-77681881/")
.twitter("https://twitter.com/gasparbjr")
.faceBook("https://www.facebook.com/gaspar.barancelli/")
.summary("Senior software engineer at Dextra, passionate about technology, because I understand that through it we can bring people together and make our world a better")
.build();
authorRepository.save(author);
post.addAuthor(author);
var tag = Tag.of("Java");
tagRepository.save(tag);
post.addTag(tag);
var tags = List.of(
Tag.of("Mysql"),
Tag.of("Banco de Dados"),
Tag.of("JPA")
);
tagRepository.saveAll(tags);
post.addTags(tags);
postRepository.save(post);
postNativeQuery.posts(null, null).forEach(it -> {
System.out.printf("PostTO - TITLE[%s], TAG[%s], AUTHOR[%s]%n", it.getPostTitle(), it.getTagDescription(), it.getAuthorName());
});
postNativeQuery.posts(null, tag.getId()).forEach(it -> {
System.out.printf("PostTO - TITLE[%s], TAG[%s], AUTHOR[%s]%n", it.getPostTitle(), it.getTagDescription(), it.getAuthorName());
});
postNativeQuery.posts(author.getId(), null).forEach(it -> {
System.out.printf("PostTO - TITLE[%s], TAG[%s], AUTHOR[%s]%n", it.getPostTitle(), it.getTagDescription(), it.getAuthorName());
});
}
}
Como podemos ver na classe acima, injetamos a interface PostNativeQuery
e executamos as consultas no método run
.
Ao executar a aplicação com as alterações realizadas, temos a seguinte saída.
PostTO - TITLE[Banco de dados MySQL com Spring Boot], TAG[Banco de Dados], AUTHOR[Gaspar Barancelli Junior]
PostTO - TITLE[Banco de dados MySQL com Spring Boot], TAG[Java], AUTHOR[Gaspar Barancelli Junior]
PostTO - TITLE[Banco de dados MySQL com Spring Boot], TAG[Mysql], AUTHOR[Gaspar Barancelli Junior]
PostTO - TITLE[Banco de dados MySQL com Spring Boot], TAG[JPA], AUTHOR[Gaspar Barancelli Junior]
PostTO - TITLE[Banco de dados MySQL com Spring Boot], TAG[Java], AUTHOR[Gaspar Barancelli Junior]
PostTO - TITLE[Banco de dados MySQL com Spring Boot], TAG[Banco de Dados], AUTHOR[Gaspar Barancelli Junior]
PostTO - TITLE[Banco de dados MySQL com Spring Boot], TAG[Java], AUTHOR[Gaspar Barancelli Junior]
PostTO - TITLE[Banco de dados MySQL com Spring Boot], TAG[Mysql], AUTHOR[Gaspar Barancelli Junior]
PostTO - TITLE[Banco de dados MySQL com Spring Boot], TAG[JPA], AUTHOR[Gaspar Barancelli Junior]
Conclusão
Nesse post tivemos uma introdução sobre o banco de dados MySQL, onde subimos o serviço do banco em um container Docker, e configuramos uma aplicação Spring Boot acessando esse banco de dados.
Os códigos fontes dos exemplos estão nos repositórios abaixo: