swh:1:snp:113c758bbca8ab355325fa13c5762925d199e835
Tip revision: 669d5b245cbe2efedbf2ae777ed633accf98e9c4 authored by Iwao AVE! on 03 July 2024, 03:06:24 UTC
Reverted to 3.5.16
Reverted to 3.5.16
Tip revision: 669d5b2
getting-started.html
<!DOCTYPE html>
<!--
| Generated by Apache Maven Doxia Site Renderer 2.0.0-M16 from src/site/fr/markdown/getting-started.md at 03 juillet 2024
| Rendered using Apache Maven Fluido Skin 2.0.0-M8
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="fr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="generator" content="Apache Maven Doxia Site Renderer 2.0.0-M16" />
<meta name="author" content="Clinton Begin, Dridi Boukelmoune" />
<title>mybatis – MyBatis 3 | Premiers pas</title>
<link rel="stylesheet" href="./css/apache-maven-fluido-2.0.0-M8.min.css" />
<link rel="stylesheet" href="./css/site.css" />
<link rel="stylesheet" href="./css/print.css" media="print" />
<script src="./js/apache-maven-fluido-2.0.0-M8.min.js"></script>
</head>
<body>
<div class="container-fluid container-fluid-top">
<header>
<div id="banner">
<div class="pull-left"></div>
<div class="pull-right"><div id="bannerRight"><h1><a href="https://blog.mybatis.org/" class="externalLink"><img class="imageLink" src="../../images/mybatis-logo.png" alt="MyBatis logo" /> MyBatis</a></h1></div></div>
<div class="clear"><hr/></div>
</div>
<div id="breadcrumbs">
<ul class="breadcrumb">
<li id="publishDate">Dernière publication: 02 avril 2024<span class="divider">|</span>
</li>
<li id="projectVersion">Version: 3.5.16</li>
</ul>
</div>
</header>
<div class="row-fluid">
<header id="leftColumn" class="span2">
<nav class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">Core</li>
<li><a href="index.html">Introduction</a></li>
<li class="active"><a>Premiers pas</a></li>
<li><a href="configuration.html"><span class="icon-chevron-right"></span>Configuration XML</a></li>
<li><a href="sqlmap-xml.html"><span class="icon-chevron-right"></span>Fichiers Mappers XML</a></li>
<li><a href="dynamic-sql.html">SQL Dynamique</a></li>
<li><a href="java-api.html"><span class="icon-chevron-right"></span>API Java</a></li>
<li><a href="statement-builders.html"><span class="icon-chevron-right"></span>Construction de requêtes</a></li>
<li><a href="logging.html">Journalisation</a></li>
<li class="nav-header">Documentation sur le projet</li>
<li><a href="project-info.html"><span class="icon-chevron-right"></span>Info Projet</a></li>
<li><a href="project-reports.html"><span class="icon-chevron-right"></span>Rapports Projet</a></li>
</ul>
</nav>
<div class="well sidebar-nav">
<div id="poweredBy">
<div class="clear"></div>
<div class="clear"></div>
<div class="clear"></div>
<a href="https://maven.apache.org/" class="builtBy" target="_blank"><img class="builtBy" alt="Produit par Maven" src="./images/logos/maven-feather.png" /></a>
</div>
</div>
</header>
<main id="bodyColumn" class="span10">
<section>
<h1>Premiers pas</h1>
<p>Chaque application MyBatis tourne autour d'une instance de SqlSessionFactory. Une instance de SqlSessionFactory peut être obtenue à l'aide du SqlSessionFactoryBuilder. SqlSessionFactoryBuilder peut créer une instance de SqlSessionFactoryBuilder à partir d'un fichier XML de configuration, où à partir d'une instance personnalisée de la classe Configuration.</p><section>
<h2>Créer une SqlSessionFactory à partir d'un fichier XML</h2>
<p>Créer une instance de SqlSessionFactory à partir d'un fichier XML est très simple. Il est recommandé d'utiliser un fichier présent dans le classpath, mais on peut utiliser n'importe quelle instance d'InputStream, y compris à partir d'un chemin vers un fichier ou d'une URL de type <code>file://</code>. MyBatis contient une classe utilitaire, Resources, qui contient plusieurs méthodes facilitant le chargement de ressources du classpath ou d'ailleurs.</p>
<div class="verbatim">
<pre><code class="language-java">String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
</code></pre></div>
<p>Le fichier de configuration XML contient les réglages pour le noyeau de MyBatis, y compris une DataSource pour obtenir les connections vers la base de données, ainsi qu'un TransactionManager pour contrôler les transactions et déterminer leur périmètre. Le détail complet du fichier de configuration XML est décrit plus tard dans le document, mais voici un exemple simple:</p>
<div class="verbatim">
<pre><code class="language-xml"><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
</code></pre></div>
<p>Le fichier de configuration XML est loin de se limiter à cela, mais l'exemple ci-dessus présente les points les plus critiques. Attention à l'entête XML, nécessaire à la validation du document XML. L'élément environment contient la configuration du gestionnaire de transactions et du pool de connexions. L'élément mappers contient une liste de mappers, des fichiers XML qui contiennent les requêtes SQL et le mapping objet-relationnel.</p></section><section>
<h2>Créer une SqlSessionFactory sans XML</h2>
<p>Il est possible de créer la configuration directement en Java, plutôt qu'en XML. MyBatis fournit une classe Configuration qui propose les mêmes options de configuration qu'avec un fichier XML.</p>
<div class="verbatim">
<pre><code class="language-java">DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
</code></pre></div>
<p>On remarque dans ce cas l'ajout d'une classe mapper. Il est possible de configurer MyBatis à l'aide d'annotations. Cependant, en raison de certaines limitations des annotations faces aux cas les plus complexes de mapping avec MyBatis, XML est toujours requis (e.g. Nested Join Mapping). Pour cette raison, MyBatis cherchera toujours la présence d'un fichier XML (dans le cas présent, BlogMapper.xml serait chargé en se basant sur le classpath et le nom de BlogMapper.class). Le sujet sera approfondi plus tard.</p></section><section>
<h2>Acquérir une SqlSession à partir d'une SqlSessionFactory</h2>
<p>Maintenant que nous avons une SqlSessionFactory, comme le nom le suggère, nous pouvons créer une instance de SqlSession. Elle contient la totalité des méthodes nécessaires à l'exécution de requêtes SQL. On peut directement exécuter une requête d'un mapper à partir d'une SqlSession. Par exemple :</p>
<div class="verbatim">
<pre><code class="language-java">try (SqlSession session = sqlSessionFactory.openSession()) {
Blog blog = session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}
</code></pre></div>
<p>Même si cette approche fonctionne, et qu'elle est bien connue des vétérans de MyBatis, il existe une approche plus propre. En utilisant une interface (e.g. BloggerMapper.class) qui décrit correctement les paramètres et la valeur de retour pour une requête particulière, on peut désormais exécuter du code plus propre et fortement typé et éviter les erreurs classiques de transtypage.</p>
<p>Par exemple:</p>
<div class="verbatim">
<pre><code class="language-java">try (SqlSession session = sqlSessionFactory.openSession()) {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
}
</code></pre></div>
<p>Explorons maintenant ce qui est exécuté ici.</p></section><section>
<h2>A la découverte des requêtes SQL mappées</h2>
<p>Arrivé ici vous vous demandé peut-être ce qui est exécuté par la SqlSession ou le Mapper. Le sujet des requêtes SQL mappées est vaste, et il sera prépondérant dans la majorité de cette documentation. Mais pour vous donner une idée de ce qui est exécuté, voici quelques exemples.</p>
<p>Dans chacun des exemples ci-dessus, les requêtes auraient pu être définies aussi bien en XML qu'avec des annotations. Jetons d'abord un coup d'œil à l'XML. La totalité des fonctionnalités de MyBatis est accessible avec le DSL basé sur XML qui a fait le succès de MyBatis au travers des années. Si vous avez utilisé MyBatis par le passé, vous serez familier du concept, mais le mapping XML a connu de nombreuses améliorations qui seront mises en lumières. Voici un exemple de mapping XML compatible avec les exemples précédents d'utilisation de SqlSession.</p>
<div class="verbatim">
<pre><code class="language-xml"><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
</code></pre></div>
<p>Cela peut paraître beaucoup d'overhead pour un exemple aussi simple, mais c'est en fait très léger. On peut définir autant de requêtes dans un même mapper XML, si bien que les entêtes XML paraissent insignifiants. Le reste du fichier parle de lui-même. On définit un nom pour la requête “selectBlog”, dans le namespace “org.mybatis.example.BlogMapper”, ce qui nous permettrait de l'exécuter par son nom canonique (fully qualified name) “org.mybatis.example.BlogMapper.selectBlog”, comme nous l'avions fait plus haut :</p>
<div class="verbatim">
<pre><code class="language-java">Blog blog = session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
</code></pre></div>
<p>C'est très similaire à un appel de méthode Java à partir du nom canonique (sans import) de la classe, et il y a une raison pour ça. Ce nom peut directement être associé à une classe “Mapper” du même nom que le namespace, avec un nom de méthode qui correspond à celui de la requête, le paramètre, et le type de retour correspondant. Cela permet d'appeler facilement les méthodes de l'interface BlogMapper vue précédemment, mais on peut aussi l'utiliser comme dans l'exemple suivant:</p>
<div class="verbatim">
<pre><code class="language-java">BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
</code></pre></div>
<p>La seconde approche a de nombreux avantages. Premièrement, on ne dépend pas d'une chaîne de caractère mais d'un type, c'est plus sûr. Deuxièmement, dans un IDE supportant l'auto-completion, cela facilite la recherche des requêtes à exécuter.</p><hr />
<p><span class="label important">NOTE</span> <strong>A propos des namespaces.</strong></p>
<p>Les <strong>Namespaces</strong> étaient optionnels dans les précédentes versions de MyBatis, ce qui n'aidait pas en plus d'être déroutant. Ils sont maintenant obligatoires et ont un but au-delà de la simple isolation des requêtes (noms canoniques).</p>
<p>On constate que les namespaces permettent de faire le lien avec les interfaces, et même si vous ne pensez pas les utiliser aujourd'hui, il est vivement recommandé de suivre ces pratiques. En utilisant déclarant un namespace, et en utilisant l'interface Java correspondante, à long terme MyBatis devient plus simple à utiliser et cela rend votre code plus fiable.</p>
<p><strong>Résolution des noms:</strong> Afin de réduire la quantité de code à produire, MyBatis utilise les règles suivantes de résolution des éléments de configuration nommés, dont les requêtes, result maps, caches etc.</p>
<ul>
<li>Les noms canoniques (e.g. “com.mypackage.MyMapper.selectAllThings”) sont recherchés tels quels et utilisés lorsqu'ils existent.</li>
<li>Les noms courts (e.g. “selectAllThings”) peuvent être utilisés pour référencer les symboles en l'absence d'ambiguïté. Cependant, s'il en existe au moins deux (e.g. “com.foo.selectAllThings et com.bar.selectAllThings”), une exception sera levée expliquant que le nom est ambigu et doit donc être canonique, complet.</li>
</ul><hr />
<p>Une dernière possibilité s'offre aux mappers comme BlogMapper. Leurs requêtes n'ont pas nécessairement besoin d'un mapping XML. Il est possible de passer par des annotations Java. On peut par exemple remplacer le mapping XML par:</p>
<div class="verbatim">
<pre><code class="language-java">package org.mybatis.example;
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}
</code></pre></div>
<p>Les annotations génère moins d'overhead pour les requêtes simples, elles sont cependant limitées et plus fouillies pour des requêtes plus complexes. De fait, pour tout ce qui est compliqué, XML est à privilégier.</p>
<p>Il sera de votre ressort de déterminer quelle approche vous convient le mieux, et quelle importance vous accordez à la cohérence dans la définition de vos requêtes SQL. Ceci-dit, MyBatis ne vous enferme pas dans une approche unique. Il est facile de migrer des annotations vers l'XML et vice versa.</p></section><section>
<h2>Périmètre et Cycle de vie</h2>
<p>Il est très important de comprendre la portée des différentes classes qui ont été abordées jusqu'ici. Utilisées incorrectement, elles peuvent poser de sévères problèmes de concurrence.</p><hr />
<p><span class="label important">NOTE</span> <strong>Cycle de vie au sein d'un framework d'injection de dépendance</strong></p>
<p>Les frameworks d'injection de dépendance (ou IoC, inversion de contrôle) peuvent créer des SqlSession et des mappers transactionnels, thread safe, et les injecter directement dans vos beans si bien que vous n'avez plus à vous soucier de leur cycle de vie. Vous serez probablement intéressé par les sous-projets MyBatis-Spring et MyBatis-Guice pour apprendre plus sur l'injection de dépendances avec MyBatis.</p><hr /><section><section>
<h4>SqlSessionFactoryBuilder</h4>
<p>Cette classe peut être instanciée, utilisée puis jetée aux oubliettes. Il n'y a aucun intérêt à la conserver une fois qu'on a créé la SqlSessionFactory. De fait, le mieux est de limiter la portée des SqlSessionFactoryBuilder à une méthode (i.e. variable locale). On peut réutiliser une instance pour construire plusieurs SqlSessionFactory, mais il est préférable de ne pas garder de SqlSessionFactoryBuilder pour permettre la libération des ressources qui ont servi à <em>parser</em> les fichiers XML.</p></section><section>
<h4>SqlSessionFactory</h4>
<p>Une fois créée, la SqlSessionFactory devrait exister pendant toute l'exécution de l'application. Il n'y a pas ou peu de raisons de disposer d'une instance ou de la recréer. La bonne pratique est de ne pas créer de multiples instances pendant l'exécution d'une application. Par conséquent, la portée la plus adaptée est celle de l'application. Cela peut être fait de différentes façons. La plus simple est d'utiliser le pattern du Singleton ou du Static Singleton.</p></section><section>
<h4>SqlSession</h4>
<p>Chaque thread devrait avoir sa propre instance de SqlSession. Les instances de SqlSession n'ont pas été pensées pour être partagée et ne sont pas <em>thread safe</em>. De fait, les portées les plus adaptées sont méthode (scope method) ou requête (scope request). Ne conservez jamais de SqlSession dans un champ statique ni même dans un champ d'une classe (NDT sauf si la classe se trouve dans un scope de type request). Ne gardez pas non plus de référence de SqlSession dans un framework gérant ses propres cycles de vie (i.e. managed scope), comme par exemple HttpSession de l'API Servlet. Si vous utilisez un framework WEB, SqlSession devait avoir la même portée qu'une requête HTTP (NDT une requête est généralement ratachée à un unique thread). En d'autres termes, lorsque vous recevez une requête HTTP, vous pouvez ouvrir une SqlSession, et lors de la réponse HTTP, la refermer. Fermer la session est très important. Vous devez vous assurer de toujours fermer la session dans un bloc finally. Le pattern classique à suivre pour assurer la fermeture de la connexion :</p>
<div class="verbatim">
<pre><code class="language-java">try (SqlSession session = sqlSessionFactory.openSession()) {
// do work
}
</code></pre></div>
<p>En utilisant ce pattern de façon systématique, votre code assurera la fermeture de toutes les ressources de base de données.</p></section><section>
<h4>Mappers</h4>
<p>Les mappers sont des interfaces qui sont liées aux requêtes déclarées. Les instances de mappers sont obtenues à partir d'une SqlSession. Donc, techniquement, leur portée ne peut pas excéder celle de la SqlSession dont ils sont issus. Cependant, il convient de limiter la portée d'un mapper à une méthode. C'est à dire, un mapper devrait être créé, utilisé et libéré au sein d'une même méthode. Ils n'ont pas explicitement besoin d'être fermés. Même s'il n'est pas gênant de les conserver pendant toute une requête (e.g. HTTP), à l'image de leur SqlSession, vous prenez le risque d'être débordé face à la consommation de ressources induite. Le plus simple, c'est de limiter la portée d'un mapper à une méthode. Voici un exemple de mise en pratique (la portée du mapper est le bloc try):</p>
<div class="verbatim">
<pre><code class="language-java">try (SqlSession session = sqlSessionFactory.openSession()) {
BlogMapper mapper = session.getMapper(BlogMapper.class);
// do work
}
</code></pre></div></section></section></section></section>
</main>
</div>
</div>
<hr/>
<footer>
<div class="container-fluid">
<div class="row-fluid">
<p>© 2009–2024
<a href="https://www.mybatis.org/">MyBatis.org</a>
</p>
</div>
</div>
</footer>
<script>
if(anchors) {
anchors.add();
}
</script>
</body>
</html>