swh:1:snp:113c758bbca8ab355325fa13c5762925d199e835
Raw File
Tip revision: 669d5b245cbe2efedbf2ae777ed633accf98e9c4 authored by Iwao AVE! on 03 July 2024, 03:06:24 UTC
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 &#xea;tre obtenue &#xe0; l'aide du SqlSessionFactoryBuilder. SqlSessionFactoryBuilder peut cr&#xe9;er une instance de SqlSessionFactoryBuilder &#xe0; partir d'un fichier XML de configuration, o&#xf9; &#xe0; partir d'une instance personnalis&#xe9;e de la classe Configuration.</p><section>
<h2>Cr&#xe9;er une SqlSessionFactory &#xe0; partir d'un fichier XML</h2>
<p>Cr&#xe9;er une instance de SqlSessionFactory &#xe0; partir d'un fichier XML est tr&#xe8;s simple. Il est recommand&#xe9; d'utiliser un fichier pr&#xe9;sent dans le classpath, mais on peut utiliser n'importe quelle instance d'InputStream, y compris &#xe0; 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&#xe9;thodes facilitant le chargement de ressources du classpath ou d'ailleurs.</p>

<div class="verbatim">
<pre><code class="language-java">String resource = &quot;org/mybatis/example/mybatis-config.xml&quot;;
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
</code></pre></div>
<p>Le fichier de configuration XML contient les r&#xe9;glages pour le noyeau de MyBatis, y compris une DataSource pour obtenir les connections vers la base de donn&#xe9;es, ainsi qu'un TransactionManager pour contr&#xf4;ler les transactions et d&#xe9;terminer leur p&#xe9;rim&#xe8;tre. Le d&#xe9;tail complet du fichier de configuration XML est d&#xe9;crit plus tard dans le document, mais voici un exemple simple:</p>

<div class="verbatim">
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
&lt;!DOCTYPE configuration
  PUBLIC &quot;-//mybatis.org//DTD Config 3.0//EN&quot;
  &quot;https://mybatis.org/dtd/mybatis-3-config.dtd&quot;&gt;
&lt;configuration&gt;
  &lt;environments default=&quot;development&quot;&gt;
    &lt;environment id=&quot;development&quot;&gt;
      &lt;transactionManager type=&quot;JDBC&quot;/&gt;
      &lt;dataSource type=&quot;POOLED&quot;&gt;
        &lt;property name=&quot;driver&quot; value=&quot;${driver}&quot;/&gt;
        &lt;property name=&quot;url&quot; value=&quot;${url}&quot;/&gt;
        &lt;property name=&quot;username&quot; value=&quot;${username}&quot;/&gt;
        &lt;property name=&quot;password&quot; value=&quot;${password}&quot;/&gt;
      &lt;/dataSource&gt;
    &lt;/environment&gt;
  &lt;/environments&gt;
  &lt;mappers&gt;
    &lt;mapper resource=&quot;org/mybatis/example/BlogMapper.xml&quot;/&gt;
  &lt;/mappers&gt;
&lt;/configuration&gt;
</code></pre></div>
<p>Le fichier de configuration XML est loin de se limiter &#xe0; cela, mais l'exemple ci-dessus pr&#xe9;sente les points les plus critiques. Attention &#xe0; l'ent&#xea;te XML, n&#xe9;cessaire &#xe0; la validation du document XML. L'&#xe9;l&#xe9;ment environment contient la configuration du gestionnaire de transactions et du pool de connexions. L'&#xe9;l&#xe9;ment mappers contient une liste de mappers, des fichiers XML qui contiennent les requ&#xea;tes SQL et le mapping objet-relationnel.</p></section><section>
<h2>Cr&#xe9;er une SqlSessionFactory sans XML</h2>
<p>Il est possible de cr&#xe9;er la configuration directement en Java, plut&#xf4;t qu'en XML. MyBatis fournit une classe Configuration qui propose les m&#xea;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(&quot;development&quot;, 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 &#xe0; 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&#xe9;sence d'un fichier XML (dans le cas pr&#xe9;sent, BlogMapper.xml serait charg&#xe9; en se basant sur le classpath et le nom de BlogMapper.class). Le sujet sera approfondi plus tard.</p></section><section>
<h2>Acqu&#xe9;rir une SqlSession &#xe0; partir d'une SqlSessionFactory</h2>
<p>Maintenant que nous avons une SqlSessionFactory, comme le nom le sugg&#xe8;re, nous pouvons cr&#xe9;er une instance de SqlSession. Elle contient la totalit&#xe9; des m&#xe9;thodes n&#xe9;cessaires &#xe0; l'ex&#xe9;cution de requ&#xea;tes SQL. On peut directement ex&#xe9;cuter une requ&#xea;te d'un mapper &#xe0; partir d'une SqlSession. Par exemple :</p>

<div class="verbatim">
<pre><code class="language-java">try (SqlSession session = sqlSessionFactory.openSession()) {
  Blog blog = session.selectOne(&quot;org.mybatis.example.BlogMapper.selectBlog&quot;, 101);
}
</code></pre></div>
<p>M&#xea;me si cette approche fonctionne, et qu'elle est bien connue des v&#xe9;t&#xe9;rans de MyBatis, il existe une approche plus propre. En utilisant une interface (e.g. BloggerMapper.class) qui d&#xe9;crit correctement les param&#xe8;tres et la valeur de retour pour une requ&#xea;te particuli&#xe8;re, on peut d&#xe9;sormais ex&#xe9;cuter du code plus propre et fortement typ&#xe9; et &#xe9;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&#xe9;cut&#xe9; ici.</p></section><section>
<h2>A la d&#xe9;couverte des requ&#xea;tes SQL mapp&#xe9;es</h2>
<p>Arriv&#xe9; ici vous vous demand&#xe9; peut-&#xea;tre ce qui est ex&#xe9;cut&#xe9; par la SqlSession ou le Mapper. Le sujet des requ&#xea;tes SQL mapp&#xe9;es est vaste, et il sera pr&#xe9;pond&#xe9;rant dans la majorit&#xe9; de cette documentation. Mais pour vous donner une id&#xe9;e de ce qui est ex&#xe9;cut&#xe9;, voici quelques exemples.</p>
<p>Dans chacun des exemples ci-dessus, les requ&#xea;tes auraient pu &#xea;tre d&#xe9;finies aussi bien en XML qu'avec des annotations. Jetons d'abord un coup d'&#x153;il &#xe0; l'XML. La totalit&#xe9; des fonctionnalit&#xe9;s de MyBatis est accessible avec le DSL bas&#xe9; sur XML qui a fait le succ&#xe8;s de MyBatis au travers des ann&#xe9;es. Si vous avez utilis&#xe9; MyBatis par le pass&#xe9;, vous serez familier du concept, mais le mapping XML a connu de nombreuses am&#xe9;liorations qui seront mises en lumi&#xe8;res. Voici un exemple de mapping XML compatible avec les exemples pr&#xe9;c&#xe9;dents d'utilisation de SqlSession.</p>

<div class="verbatim">
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
&lt;!DOCTYPE mapper
  PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;
  &quot;https://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;
&lt;mapper namespace=&quot;org.mybatis.example.BlogMapper&quot;&gt;
  &lt;select id=&quot;selectBlog&quot; resultType=&quot;Blog&quot;&gt;
    select * from Blog where id = #{id}
  &lt;/select&gt;
&lt;/mapper&gt;
</code></pre></div>
<p>Cela peut para&#xee;tre beaucoup d'overhead pour un exemple aussi simple, mais c'est en fait tr&#xe8;s l&#xe9;ger. On peut d&#xe9;finir autant de requ&#xea;tes dans un m&#xea;me mapper XML, si bien que les ent&#xea;tes XML paraissent insignifiants. Le reste du fichier parle de lui-m&#xea;me. On d&#xe9;finit un nom pour la requ&#xea;te &#x201c;selectBlog&#x201d;, dans le namespace &#x201c;org.mybatis.example.BlogMapper&#x201d;, ce qui nous permettrait de l'ex&#xe9;cuter par son nom canonique (fully qualified name) &#x201c;org.mybatis.example.BlogMapper.selectBlog&#x201d;, comme nous l'avions fait plus haut :</p>

<div class="verbatim">
<pre><code class="language-java">Blog blog = session.selectOne(&quot;org.mybatis.example.BlogMapper.selectBlog&quot;, 101);
</code></pre></div>
<p>C'est tr&#xe8;s similaire &#xe0; un appel de m&#xe9;thode Java &#xe0; partir du nom canonique (sans import) de la classe, et il y a une raison pour &#xe7;a. Ce nom peut directement &#xea;tre associ&#xe9; &#xe0; une classe &#x201c;Mapper&#x201d; du m&#xea;me nom que le namespace, avec un nom de m&#xe9;thode qui correspond &#xe0; celui de la requ&#xea;te, le param&#xe8;tre, et le type de retour correspondant. Cela permet d'appeler facilement les m&#xe9;thodes de l'interface BlogMapper vue pr&#xe9;c&#xe9;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&#xe8;rement, on ne d&#xe9;pend pas d'une cha&#xee;ne de caract&#xe8;re mais d'un type, c'est plus s&#xfb;r. Deuxi&#xe8;mement, dans un IDE supportant l'auto-completion, cela facilite la recherche des requ&#xea;tes &#xe0; ex&#xe9;cuter.</p><hr />
<p><span class="label important">NOTE</span> <strong>A propos des namespaces.</strong></p>
<p>Les <strong>Namespaces</strong> &#xe9;taient optionnels dans les pr&#xe9;c&#xe9;dentes versions de MyBatis, ce qui n'aidait pas en plus d'&#xea;tre d&#xe9;routant. Ils sont maintenant obligatoires et ont un but au-del&#xe0; de la simple isolation des requ&#xea;tes (noms canoniques).</p>
<p>On constate que les namespaces permettent de faire le lien avec les interfaces, et m&#xea;me si vous ne pensez pas les utiliser aujourd'hui, il est vivement recommand&#xe9; de suivre ces pratiques. En utilisant d&#xe9;clarant un namespace, et en utilisant l'interface Java correspondante, &#xe0; long terme MyBatis devient plus simple &#xe0; utiliser et cela rend votre code plus fiable.</p>
<p><strong>R&#xe9;solution des noms:</strong> Afin de r&#xe9;duire la quantit&#xe9; de code &#xe0; produire, MyBatis utilise les r&#xe8;gles suivantes de r&#xe9;solution des &#xe9;l&#xe9;ments de configuration nomm&#xe9;s, dont les requ&#xea;tes, result maps, caches etc.</p>
<ul>

<li>Les noms canoniques (e.g. &#x201c;com.mypackage.MyMapper.selectAllThings&#x201d;) sont recherch&#xe9;s tels quels et utilis&#xe9;s lorsqu'ils existent.</li>
<li>Les noms courts (e.g. &#x201c;selectAllThings&#x201d;) peuvent &#xea;tre utilis&#xe9;s pour r&#xe9;f&#xe9;rencer les symboles en l'absence d'ambigu&#xef;t&#xe9;. Cependant, s'il en existe au moins deux (e.g. &#x201c;com.foo.selectAllThings et com.bar.selectAllThings&#x201d;), une exception sera lev&#xe9;e expliquant que le nom est ambigu et doit donc &#xea;tre canonique, complet.</li>
</ul><hr />
<p>Une derni&#xe8;re possibilit&#xe9; s'offre aux mappers comme BlogMapper. Leurs requ&#xea;tes n'ont pas n&#xe9;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(&quot;SELECT * FROM blog WHERE id = #{id}&quot;)
  Blog selectBlog(int id);
}
</code></pre></div>
<p>Les annotations g&#xe9;n&#xe8;re moins d'overhead pour les requ&#xea;tes simples, elles sont cependant limit&#xe9;es et plus fouillies pour des requ&#xea;tes plus complexes. De fait, pour tout ce qui est compliqu&#xe9;, XML est &#xe0; privil&#xe9;gier.</p>
<p>Il sera de votre ressort de d&#xe9;terminer quelle approche vous convient le mieux, et quelle importance vous accordez &#xe0; la coh&#xe9;rence dans la d&#xe9;finition de vos requ&#xea;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&#xe9;rim&#xe8;tre et Cycle de vie</h2>
<p>Il est tr&#xe8;s important de comprendre la port&#xe9;e des diff&#xe9;rentes classes qui ont &#xe9;t&#xe9; abord&#xe9;es jusqu'ici. Utilis&#xe9;es incorrectement, elles peuvent poser de s&#xe9;v&#xe8;res probl&#xe8;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&#xe9;pendance</strong></p>
<p>Les frameworks d'injection de d&#xe9;pendance (ou IoC, inversion de contr&#xf4;le) peuvent cr&#xe9;er des SqlSession et des mappers transactionnels, thread safe, et les injecter directement dans vos beans si bien que vous n'avez plus &#xe0; vous soucier de leur cycle de vie. Vous serez probablement int&#xe9;ress&#xe9; par les sous-projets MyBatis-Spring et MyBatis-Guice pour apprendre plus sur l'injection de d&#xe9;pendances avec MyBatis.</p><hr /><section><section>
<h4>SqlSessionFactoryBuilder</h4>
<p>Cette classe peut &#xea;tre instanci&#xe9;e, utilis&#xe9;e puis jet&#xe9;e aux oubliettes. Il n'y a aucun int&#xe9;r&#xea;t &#xe0; la conserver une fois qu'on a cr&#xe9;&#xe9; la SqlSessionFactory. De fait, le mieux est de limiter la port&#xe9;e des SqlSessionFactoryBuilder &#xe0; une m&#xe9;thode (i.e. variable locale). On peut r&#xe9;utiliser une instance pour construire plusieurs SqlSessionFactory, mais il est pr&#xe9;f&#xe9;rable de ne pas garder de SqlSessionFactoryBuilder pour permettre la lib&#xe9;ration des ressources qui ont servi &#xe0; <em>parser</em> les fichiers XML.</p></section><section>
<h4>SqlSessionFactory</h4>
<p>Une fois cr&#xe9;&#xe9;e, la SqlSessionFactory devrait exister pendant toute l'ex&#xe9;cution de l'application. Il n'y a pas ou peu de raisons de disposer d'une instance ou de la recr&#xe9;er. La bonne pratique est de ne pas cr&#xe9;er de multiples instances pendant l'ex&#xe9;cution d'une application. Par cons&#xe9;quent, la port&#xe9;e la plus adapt&#xe9;e est celle de l'application. Cela peut &#xea;tre fait de diff&#xe9;rentes fa&#xe7;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 &#xe9;t&#xe9; pens&#xe9;es pour &#xea;tre partag&#xe9;e et ne sont pas <em>thread safe</em>. De fait, les port&#xe9;es les plus adapt&#xe9;es sont m&#xe9;thode (scope method) ou requ&#xea;te (scope request). Ne conservez jamais de SqlSession dans un champ statique ni m&#xea;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&#xe9;f&#xe9;rence de SqlSession dans un framework g&#xe9;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&#xea;me port&#xe9;e qu'une requ&#xea;te HTTP (NDT une requ&#xea;te est g&#xe9;n&#xe9;ralement ratach&#xe9;e &#xe0; un unique thread). En d'autres termes, lorsque vous recevez une requ&#xea;te HTTP, vous pouvez ouvrir une SqlSession, et lors de la r&#xe9;ponse HTTP, la refermer. Fermer la session est tr&#xe8;s important. Vous devez vous assurer de toujours fermer la session dans un bloc finally. Le pattern classique &#xe0; 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&#xe7;on syst&#xe9;matique, votre code assurera la fermeture de toutes les ressources de base de donn&#xe9;es.</p></section><section>
<h4>Mappers</h4>
<p>Les mappers sont des interfaces qui sont li&#xe9;es aux requ&#xea;tes d&#xe9;clar&#xe9;es. Les instances de mappers sont obtenues &#xe0; partir d'une SqlSession. Donc, techniquement, leur port&#xe9;e ne peut pas exc&#xe9;der celle de la SqlSession dont ils sont issus. Cependant, il convient de limiter la port&#xe9;e d'un mapper &#xe0; une m&#xe9;thode. C'est &#xe0; dire, un mapper devrait &#xea;tre cr&#xe9;&#xe9;, utilis&#xe9; et lib&#xe9;r&#xe9; au sein d'une m&#xea;me m&#xe9;thode. Ils n'ont pas explicitement besoin d'&#xea;tre ferm&#xe9;s. M&#xea;me s'il n'est pas g&#xea;nant de les conserver pendant toute une requ&#xea;te (e.g. HTTP), &#xe0; l'image de leur SqlSession, vous prenez le risque d'&#xea;tre d&#xe9;bord&#xe9; face &#xe0; la consommation de ressources induite. Le plus simple, c'est de limiter la port&#xe9;e d'un mapper &#xe0; une m&#xe9;thode. Voici un exemple de mise en pratique (la port&#xe9;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>
back to top