O MyBatis é uma estrutura de persistência que utiliza arquivos XML para definir o mapeamento entre as consultas SQL e os métodos da interface Java. Estes arquivos, conhecidos como mapeamentos de Mapper, utilizam uma variedade de etiquetas para expressar operações de banco de dados complexas de forma declarativa.
Reutilização e Nomenclatura
Para evitar a duplicação de colunas SQL, a etiqueta <sql> permite definir um fragmento reutilizável. Este fragmento é então inserido em consultas maiores usando a etiqueta <include>, promovendo a manutenibilidade. O atributo id do fragmento é referenciado pelo atributo refid da inclusão.
<sql id="Campos_Departamento">
id, nome, codigo, gerente_id, data_criacao
</sql>
<select id="buscarDepartamento" resultType="Departamento">
SELECT <include refid="Campos_Departamento"/> FROM departamento
</select>
A etiqueta raiz <mapper> encapsula todos os mapeamentos e define o namespace, que deve corresponder à interface Java associada.
<mapper namespace="com.mapeamento.DepartamentoMapper">
...
</mapper>
Operações CRUD Básicas
As operações fundamentais de banco de dados são representadas por etiquetas específicas.
<!-- SELECT -->
<select id="listarTodos" resultType="com.modelo.Funcionario">
SELECT matricula, nome, email FROM funcionario
</select>
<!-- INSERT -->
<insert id="adicionarFuncionario" useGeneratedKeys="true" keyProperty="matricula">
INSERT INTO funcionario (nome, email, departamento_id)
VALUES (#{nome}, #{email}, #{departamentoId})
</insert>
<!-- UPDATE -->
<update id="atualizarProjeto">
UPDATE projeto SET nome = #{novoNome}, data_fim = #{novaDataFim} WHERE id = #{idProjeto}
</update>
<!-- DELETE -->
<delete id="excluirRegistroPorId">
DELETE FROM log_auditoria WHERE id = #{idLog}
</delete>
Para cenários onde o valor gerado pelo banco (como uma chave primária sequencial) precisa ser preenchido no objeto Java após a inserção, a etiqueta <selectKey> é utilizada dentro do <insert>.
<insert id="inserirOrdemServico">
<selectKey keyProperty="idOrdem" resultType="long" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO ordem_servico (descricao, status) VALUES (#{descricao}, #{status})
</insert>
Mapeamento de Resultados Complexos
Para mapear colunas de banco de dados para propriedades de objetos com nomes diferentes, ou para estruturas aninhadas, utiliza-se <resultMap>. A relação de um-para-muitos (ex.: um departamento com vários projetos) é gerida pela etiqueta <collection>.
<resultMap id="MapaDepartamento" type="com.modelo.Departamento">
<id column="departamento_id" property="id"/>
<result column="departamento_nome" property="nome"/>
<collection property="projetos" ofType="com.modelo.Projeto"
select="buscarProjetosPorDepartamento" column="departamento_id"/>
</resultMap>
<select id="buscarProjetosPorDepartamento" resultType="com.modelo.Projeto">
SELECT id, titulo, prazo FROM projeto WHERE departamento_id = #{departamento_id}
</select>
SQL Dinâmico
Construir consultas com cláusulas condicionais é facilitado por etiquetas dinâmicas. <if> adiciona uma cláusula se a condição for verdadeira.
<select id="filtrarAtividades" resultType="com.modelo.Atividade">
SELECT id, titulo, responsavel FROM atividade
WHERE status = 'PENDENTE'
<if test="responsavelId != null">
AND responsavel_id = #{responsavelId}
</if>
</select>
A etiqueta <where> envolve condições opcionais, automaticamente removendo operadores AND/OR iniciais indesejados.
<select id="buscarComFiltros" resultType="com.modelo.Pedido">
SELECT * FROM pedido
<where>
<if test="dataInicio != null"> AND data_pedido >= #{dataInicio} </if>
<if test="status != null"> AND status = #{status} </if>
<if test="valorMinimo != null"> AND valor_total >= #{valorMinimo} </if>
</where>
</select>
De maneira similar, <set> constrói dinamicamente a lista de colunas para atualizar em um UPDATE, adicionando as vírgulas necessárias.
<update id="atualizarDadosUsuario">
UPDATE usuario
<set>
<if test="nome != null"> nome = #{nome}, </if>
<if test="email != null"> email = #{email}, </if>
<if test="telefone != null"> telefone = #{telefone} </if>
</set>
WHERE id = #{id}
</update>
Para uma lógica condicional exclusiva (executar apenas a primeira condição verdadeira), a combinação <choose>, <when> e <otherwise> é equivalente a uma estrutura if-else if-else em SQL.
<select id="obterRegraDesconto" resultType="java.math.BigDecimal">
SELECT desconto FROM regra_comercial
<where>
<choose>
<when test="clienteTipo == 'VIP'"> cliente_tipo = 'VIP' </when>
<when test="pedidoValor > 1000"> valor_minimo <= #{pedidoValor} </when>
<otherwise> ativo = true </otherwise>
</choose>
</where>
</select>
Finalmente, a etiqueta <foreach> itera sobre uma coleção, sendo extremamente útil para cláusulas IN ou para operações em lote. Seus atributos controlam o item da iteração, o caractere separador e os delimitadores de abertura e fechamento.
<delete id="excluirPorLoteIds">
DELETE FROM item_estoque WHERE id IN
<foreach collection="listaIds" item="idItem" open="(" separator="," close=")">
#{idItem}
</foreach>
</delete>