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