Integração do MyBatis com Spring Boot via Anotações

Embora a configuração tradicional do MyBatis utilize arquivos XML para mapear instruções SQL, o Spring Boot permite uma abordagem muito mais enxuta baseada inteiramente em anotações Java. Esta técnica elimina a necessidade de arquivos de configuração externos para o mapeamento de consultas, facilitando a manutenção e a legibilidade do código em projetos menores ou microserviços.

Dependências Necessárias

Para começar, é necessário incluir o mybatis-spring-boot-starter e o driver do banco de dados no seu arquivo pom.xml. Esta dependência gerencia automaticamente a configuração do SqlSessionFactory e do SqlSessionTemplate.

<dependencies>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.4</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

Configuração do Datasource

No arquivo application.yml, defina os parâmetros de conexão com o seu banco de dados MySQL:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/sistema_financeiro?useUnicode=true&characterEncoding=UTF-8&useSSL=false
    username: dev_user
    password: senha_forte

Estrutura do Banco de Dados

Para este exemplo, utilizaremos uma tabela chamada user_account para gerenciar o saldo de usuários:

CREATE TABLE `user_account` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `owner_name` VARCHAR(50) NOT NULL DEFAULT '',
  `balance` BIGINT NOT NULL DEFAULT '0',
  `status` TINYINT(1) NOT NULL DEFAULT '1',
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
  `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Modelo de Dados (Antity)

Crie uma classe Java que represente a estrutura da tabela. Utilizaremos tipos padrão do Java para o mapeamento:

public class UserAccount {
    private Integer id;
    private String ownerName;
    private Long balance;
    private Integer status;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

    // Getters e Setters
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    public String getOwnerName() { return ownerName; }
    public void setOwnerName(String ownerName) { this.ownerName = ownerName; }
    public Long getBalance() { return balance; }
    public void setBalance(Long balance) { this.balance = balance; }
    public Integer getStatus() { return status; }
    public void setStatus(Integer status) { this.status = status; }
    // ... demais métodos
}

Definição do Mapper com Anotações

A interface Mapper é onde definimos as operações CRUD. Em vez de XML, usamos anotações como @Insert, @Select, @Update e @Delete.

@Mapper
public interface UserAccountMapper {

    @Insert("INSERT INTO user_account (owner_name, balance, status) VALUES (#{acc.ownerName}, #{acc.balance}, #{acc.status})")
    @Options(useGeneratedKeys = true, keyProperty = "acc.id", keyColumn = "id")
    int insertAccount(@Param("acc") UserAccount account);

    @Select("SELECT * FROM user_account WHERE owner_name = #{name}")
    @Results({
        @Result(property = "id", column = "id", id = true),
        @Result(property = "ownerName", column = "owner_name"),
        @Result(property = "balance", column = "balance"),
        @Result(property = "status", column = "status"),
        @Result(property = "createdAt", column = "created_at"),
        @Result(property = "updatedAt", column = "updated_at")
    })
    List<UserAccount> findByOwnerName(@Param("name") String name);

    @Update("UPDATE user_account SET balance = balance + #{amount} WHERE id = #{id}")
    int updateBalance(@Param("id") int id, @Param("amount") long amount);

    @Delete("DELETE FROM user_account WHERE id = #{id}")
    int removeAccount(@Param("id") int id);

    @Select("<script>" +
            "SELECT * FROM user_account " +
            "<where>" +
            "  <if test='id != null'> AND id = #{id} </if>" +
            "  <if test='ownerName != null'> AND owner_name = #{ownerName} </if>" +
            "</where>" +
            "</script>")
    @Results({
        @Result(property = "ownerName", column = "owner_name"),
        @Result(property = "balance", column = "balance")
    })
    List<UserAccount> searchDynamic(UserAccount filter);
}

Pontos importantes na impleemntação acima:

  • @Options: Permite recuperar o ID gerado automaticamente pelo banco de dados e injetá-lo de volta no objeto Java.
  • @Results: Mapeia manualmente as colunas do banco de dados para os atributos da classe, essencial quando os nomes não são idênticos (ex: snake_case para camelCase).
  • SQL Dinâmico: Ao usar a tag <script> dentro de uma enotação, é possível utilizar a sintaxe XML do MyBatis para criar consultas flexíveis com <if> e <where>.

Execução e Teste

Para validar a integração, podemos injetar o Mapper em um componente de serviço ou repositório:

@Service
public class AccountService {
    @Autowired
    private UserAccountMapper accountMapper;

    public void processarExemplo() {
        UserAccount novaConta = new UserAccount();
        novaConta.setOwnerName("TechUser");
        novaConta.setBalance(5000L);
        novaConta.setStatus(1);

        // Salvar
        accountMapper.insertAccount(novaConta);
        System.out.println("ID Gerado: " + novaConta.getId());

        // Atualizar
        accountMapper.updateBalance(novaConta.getId(), 1500L);

        // Buscar
        List<UserAccount> resultados = accountMapper.findByOwnerName("TechUser");
        resultados.forEach(acc -> System.out.println("Saldo: " + acc.getBalance()));

        // Remover
        accountMapper.removeAccount(novaConta.getId());
    }
}

Tags: Spring Boot MyBatis java MySQL ORM

Publicado em 7-11 18:46