MyBatis — Cheat Sheet

Tag: java, mybatis, orm, sql, jdbc, mapper, spring

Livello: intermedio

TL;DR: Framework di persistenza per Java che mappa il risultato delle query SQL su oggetti. Offre controllo totale sul codice SQL a differenza dei tradizionali ORM come Hibernate.

Concetti chiave

Non è un ORM completo ma un "SQL Mapper": il focus è sulla scrittura manuale delle query SQL.

Mantiene una separazione netta tra il codice Java e le query (generalmente scritte in file XML).

Consente la creazione di query dinamiche tramite costrutti XML specifici (<if>, <choose>, <where>, <foreach>).

Utilizza #{param} per inserire parametri in modo sicuro tramite PreparedStatement (previene SQL injection).

Utilizza ${param} per l'iniezione diretta di testo nella query (da usare con cautela, es. nomi colonne/tabelle dinamici).

Supporta mappature complesse per relazioni uno-a-uno (<association>) e uno-a-molti (<collection>).

Gestisce cache di primo livello (a livello di sessione) e secondo livello (a livello di namespace globale).

Si integra nativamente con Spring e Spring Boot tramite il pacchetto mybatis-spring-boot-starter.

Domande tipiche e risposte pronte

Q: Qual è la differenza principale tra MyBatis e Hibernate?R: Hibernate mappa le classi alle tabelle e genera le query automaticamente. MyBatis richiede di scrivere le query a mano, dandomi il controllo assoluto sulle performance e sulle ottimizzazioni del database.

Q: Qual è la differenza tra #{} e ${}?R: #{} usa i PreparedStatement di JDBC ed è sicuro contro le SQL injection. ${} inserisce la stringa in modo diretto (string substitution), lo uso solo per parametri strutturali come nomi di tabelle o colonne se strettamente necessario.

Q: Come risolvi il problema N+1 select in MyBatis?R: Sfrutto le join SQL direttamente nella query e uso il tag <collection> o <association> nel <resultMap> per mappare i dati annidati, evitando query aggiuntive per ogni record estratto.

Insidie e errori comuni

Utilizzare ${} per passare parametri inseriti dall'utente, creando vulnerabilità SQL Injection.

Creare file XML eccessivamente complessi con troppi tag dinamici, rendendo l'SQL incomprensibile e difficile da debuggare.

Dimenticare di configurare correttamente le annotazioni @Param nei metodi dell'interfaccia Java, causando errori nel binding dei parametri.

Non disabilitare o svuotare correttamente la cache di primo livello durante elaborazioni batch massicce, causando OutOfMemoryError.

Snippet e comandi

<!-- UserMapper.xml: Esempio di mapping dinamico -->
<mapper namespace="com.example.mapper.UserMapper">

  <resultMap id="UserResult" type="com.example.dto.User">
    <id property="id" column="id" />
    <result property="username" column="username" />
    <result property="email" column="email" />
  </resultMap>

  <select id="findUsers" resultMap="UserResult">
    SELECT id, username, email
    FROM users
    <where>
      <if test="status != null">
        status = #{status}
      </if>
      <if test="role != null">
        AND role = #{role}
      </if>
    </where>
  </select>

  <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO users (username, email)
    VALUES (#{username}, #{email})
  </insert>
</mapper>

Java

// UserMapper.java: Interfaccia corrispondente
@Mapper
public interface UserMapper {
    List<User> findUsers(@Param("status") String status, @Param("role") String role);
    void insertUser(User user);
}

Da ripassare

[ ] Implementazione e configurazione della cache di secondo livello (es. con Redis o Ehcache).

[ ] Utilizzo dei plugin/interceptor MyBatis per audit logging o paginazione custom.

[ ] Gestione del TypeHandler per mappare tipi Java complessi su tipi database nativi (es. JSON in PostgreSQL).

Riferimenti

MyBatis 3 Reference Documentation

Jarvis Interviews
Jarvis