Le rôle central de MappedStatement dans MyBatis

MappedStatement constitue l'objet métadonnées fondamental de MyBatis, regroupant l'ensemble des informations associées à une requête SQL. Il contient le script SQL, les types de paramètres et de retour, la stratégie de génération de clés primaires, les configurations de cache et le type d'exécuteur.

En essence, chaque méthode annotée avec @Select, @Insert ou définie via XML comme select ou update est transformée en une instance de MappedStatement par MyBatis.

Fonction principales

  • Stockage des métadonnées d'une requête SQL (configuration et script)
  • Fourniture de ces données aux composants SqlSession et Executor pour l'exécution
  • Possibilité d'accéder dynamiquement, de modifier ou même de créer de nouveaux MappedStatement (utilisation avancée)

Concepts clés à maîtriser

La classe se trouve dans le paquet org.apache.ibatis.mapping.MappedStatement. On y accède via l'objet Configuration de MyBatis. Son identifiant unique suit le modèle : nom_complet_du_mapper.méthode, par exemple com.exemple.mapper.UtilisateurMapper.chercherParId.

Exemple de base : récupérer un MappedStatement

1. Définition d'une interface Mapper

public interface UtilisateurMapper {
    // Cette méthode correspondra à un MappedStatement spécifique
    Utilisateur chercherParId(Long id);
}

2. Classe utilitaire pour récupérer MappedStatement

import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;

@Component
public class AideMappedStatement {

    @Resource
    private SqlSessionFactory usineSessionSql;

    /**
     * Récupère un MappedStatement par son identifiant
     */
    public MappedStatement obtenirMappedStatement(String identifiantMs) {
        Configuration configuration = usineSessionSql.getConfiguration();
        // Récupération depuis la configuration globale de MyBatis
        return configuration.getMappedStatement(identifiantMs);
    }
}

3. Utilisation

// L'identifiant est composé du nom complet de la classe du mapper et de la méthode
String identifiantMs = "com.exemple.mapper.UtilisateurMapper.chercherParId";
MappedStatement ms = aideMappedStatement.obtenirMappedStatement(identifiantMs);

Propriétés utiles de MappedStatement

Une fois obtenu, on peut extraire plusieurs informations critiques :

1. Récupérer le SQL exécutable

// Obtenir le BoundSql contenant le SQL final et les paramètres
BoundSql sqlLie = ms.getBoundSql(objetParametre);
String requeteSql = sqlLie.getSql();

2. Identifier le type de commande SQL

TypeCommandeSql typeSql = ms.getSqlCommandType();
// Valeurs possibles : INSERT, UPDATE, DELETE, SELECT, etc.

3. Consulter le type des paramètres d'entrée

Class> typeParametre = ms.getParameterType();

4. Accéder au type des résultats

Class> typeResultat = ms.getResultMaps().get(0).getType();

5. Vérifier la stratégie de clé primaire

GenerateurCle generateur = ms.getKeyGenerator();

Scénario pratique 1 : extraire le SQL dynamique

// 1. Récupérer le MappedStatement
MappedStatement ms = configuration.getMappedStatement(identifiantMs);

// 2. Préparer les paramètres si la requête en nécessite
Map<String, Object> parametres = new HashMap<>();
parametres.put("identifiant", 123L);

// 3. Obtenir le SQL final
BoundSql sqlLie = ms.getBoundSql(parametres);
String sqlExec = sqlLie.getSql();

// Résultat : SELECT * FROM utilisateurs WHERE id = ?

Scénario pratique 2 : exécuter directement un MappedStatement

Il est possible d'exécuter le SQL sans passer par l'appel de méthode du mapper :

Utilisateur utilisateur = sessionSql.selectOne(identifiantMs, 123L);

Le processus interne se déroule ainsi :

  • Recherche du MappedStatement correspondant à l'identifiant
  • Transmission à l'Executor pour exécution

Scénario avancé : création dynamique de MappedStatement

Cette technique est au cœur des fonctionnalités comme les SQL dynamiques, le partitionnement de tables, le multi-tenant ou les DAO génériques.

Exemple : enregistrer dynamiquement une requête SELECT

/**
 * Crée et enregistre un MappedStatement dynamique
 */
public void enregistrementDynamique(Configuration config) {

    String sql = "SELECT * FROM produits WHERE reference = #{ref}";
    String identifiant = "com.exemple.mapper.ProduitMapper.rechercheDynamique";

    // 1. Construire le SqlSource (objet d'analyse SQL de MyBatis)
    SqlSource sourceSql = config.getSqlSourceBuilder().parse(
        sql,
        Object.class,
        Collections.emptyMap()
    );

    // 2. Construire le MappedStatement
    MappedStatement ms = new MappedStatement.Builder(
            config,
            identifiant,
            sourceSql,
            TypeCommandeSql.SELECT
        )
        .resultMaps(Collections.singletonList(
            new ResultMap.Builder(config, "carteResultats", Produit.class, new ArrayList<>())
                .build()
        ))
        .build();

    // 3. L'enregistrer dans MyBatis
    config.addMappedStatement(ms);
}

Utilisation après enregistrement

// Exécution directe de la requête dynamique
Produit produit = sessionSql.selectOne("com.exemple.mapper.ProduitMapper.rechercheDynamique", "REF001");

Flux d'exécution de MappedStatement

Interface Mapper ou XML → Analyse → MappedStatement → Stockage dans Configuration

SqlSession.selectOne(identifiant) → Récupération du MappedStatement

Executor exécute → Extraction du BoundSql → Exécution JDBC → Retour du résultat

Applications clés de MappedStatement

  • Accès aux métadonnées SQL pour journalisation, surveillance ou contrôle d'accès
  • Inscription dynamique de requêtes pour les mappers génériques ou le changement de tables
  • Interception et modification SQL pour les fonctionnalités multi-locataire ou de sécurité des données
  • Développement d'exécuteurs personnalisés pour étendre le cmoportement de MyBatis

Étiquettes: MyBatis MappedStatement SQL Java Configuration

Publié le 24 juin à 16h13