Tutoriel MyBatis 3.2.2

MyBatis 3.2.2

Table des matières

1Mise en place
1.1Dépendance maven
1.2Configuration principal
1.3Fichier de mapping
1.4Classe java
1.4.1Création du DAO
1.4.2Création de l’objet (POJO)
1.5Classe utilitaire de connexion
1.6Création de la base de données
2Utilisation
2.1Lecture de tous les enregistrements (SELECT)
2.2Lecture d’un enregistrement (SELECT)
2.3Insérer un enregistrement (INSERT)
2.4Mettre à jour un enregistrement (UPDATE)
2.5Supprimer un enregistrement (DELETE)
3Utilisation avancée
3.1Trier les enregistrements
3.2Alias
3.3Étendre un type
3.4Association
3.5Annotation
3.5.1Création du DAO
3.5.2Fichier de mapping ou non
3.5.3Utilisation de l’interface (exemple avec un SELECT)
3.6SQL Dynamique
4Annexes

1 Mise en place

1.1 Dépendance maven

Créez un projet maven de type simple.
Nous utiliserons un base de données MySQL (vous pouvez utiliser WAMP par exemple).
Editez le fichier « pom.xml » et ajoutez la dépendance suivante :

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.2.1</version>
  <scope>compile</scope>
</dependency>

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.17</version>
  <scope>compile</scope>
</dependency>

<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.4</version>
</dependency>

1.2 Configuration principal

MyBatis requière un fichier de configuration principale qui sera dans cet exemple placé dans src/main/resources/mybatis-config.xml.
Attention, ce fichier doit respecter un syntaxe précise (ordre des balises) qui peut être parfois assez difficile à comprendre.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
       <properties resource="mybatis-config.properties" />

       <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="mapper/ClientMapper.xml" />
       </mappers>
</configuration>

Dans le fichier de configuration, on inclut un fichier de propriété mybatis-config.properties qui va contenir des variables utilisées dans le fichier de configuration.
Ce fichier contient les données suivantes :

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test-mybatis
username=root
password=

Ce fichier est situé dans le même répertoire que le fichier mybatis-config.xml.
Ensuite, il y a une notion d’environnement. Cela peut être superflu si les filtering de maven sont utilisés sur le fichier de propriétés.
A la fin, un fichier de mapping est spécifié.
C’est ce fichier qui va faire le lien entre le résultat de la requête et les objets Java.

1.3 Fichier de mapping

Afin d’obtenir des objets java après exécution d’une requête SQL, il est nécessaire d’avoir à faire à un mapping.
MyBatis utilise donc des fichiers de mapping XML pour décrire celui-ci.
Dans le point précédent nous avons vu qu’il y avait une référence au fichier src/main/resources/mapper/ClientMapper.xml.
Déclaration du DAO
Classe java recevant les données
Alias permettant de faire le lien entre la requête et le mapping

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mybatis.tutoriel.db.ClientDao">
       <resultMap id="ClientResultMap" type="mybatis.tutoriel.db.Client">
             <id property="id" column="id" />
             <result property="lastname" column="nom" />
             <result property="firstname" column="prenom" />
             <result property="birthday" column="date_de_naissance" />
             <result property="phonenumber" column="telephone" />
             <result property="age" column="age" />
       </resultMap>

       <select id="findAll" resultMap="ClientResultMap">
             select * from client
       </select>

       <select id="findOne" parameterType="int" resultMap="ClientResultMap">
             select * from client where id = #{id}
       </select>
</mapper>

1.4 Classe java

1.4.1 Création du DAO

package mybatis.tutoriel.db;

public class ClientDao {
}

Comme on peut le voir, la classe est vide.
C’est tout à faire normal car c’est MyBatis qui génère l’implémentation.

1.4.2 Création de l’objet (POJO)

package mybatis.tutoriel.db;

public class Client {
       private int id;
       private String lastname;
       private String firstname;
       private Date birthday;
       private String phonenumber;
       private int age;

       ...
}

1.5 Classe utilitaire de connexion

Afin de faciliter l’utilisation de MyBatis, nous allons créer la classe de connexion ci-dessous :

package mybatis.tutoriel.db;

import java.io.IOException;
import java.io.Reader;

import org.apache.commons.io.IOUtils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MybatisUtil {
       private static final String resource = "mybatis-config.xml";
       private static SqlSessionFactory sqlSessionFactory;

       static {
             Reader reader = null;

             try {
                    reader = Resources.getResourceAsReader(resource);
                    sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
             } catch (IOException e) {
                    System.err.println(e);
             } finally {
                    IOUtils.closeQuietly(reader);
             }
       }

       public static SqlSession getSession() {
             return sqlSessionFactory.openSession();
       }
}

1.6 Création de la base de données

--
-- Structure de la table `client`
--
CREATE TABLE IF NOT EXISTS `client` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `nom` varchar(50) NOT NULL,
  `prenom` varchar(50) NOT NULL,
  `date_de_naissance` date NOT NULL,
  `telephone` varchar(10) NOT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

--
-- Contenu de la table `client`
--
INSERT INTO `client` (`id`, `nom`, `prenom`, `date_de_naissance`, `telephone`, `age`) VALUES
(1, 'PITT', 'Brad', '1963-12-18', '0606060606', 49),
(2, 'HELFER', 'Tricia', '1974-04-11', '0605050505', 39);

2 Utilisation

2.1 Lecture de tous les enregistrements (SELECT)

Voici un exemple de lecteur de la base de donnees :

package mybatis.tutoriel.test;

import java.util.List;
import org.apache.ibatis.session.SqlSession;

import mybatis.tutoriel.db.Client;
import mybatis.tutoriel.db.MybatisUtil;

public class TestSelectAll {
       public static void main(String[] args) {
       SqlSession session = MybatisUtil.getSession(); // (1)

       List listeClient = session.selectList("mybatis.tutoriel.db.ClientDao.findAll") ;

       for (Client c : listeClient) {
             System.out.println(c.toString());
       }

       session.close() ; //(2)
       }
}

Et le résultat :

Id : 1 Nom : PITT Prenom : Brad
Id : 2 Nom : HELFER Prenom : Tricia

On constate tout d’abord qu’il est nécessaire de créer et fermer manuellement la connexion à la base de données (1 et 2)
Ensuite, on demande à MyBatis de selectionner un liste d’élément pour l’interface ClientDao et une mystérieuse méthode « findAll ».
La méthode « findAll » est celle déclarée dans le fichier de mapping.
En effet, rappelez-vous que l’interface ClientDao est vide !

2.2 Lecture d’un enregistrement (SELECT)

Idem que l’exemple précédent, mais cette fois-ci nous utiliserons « findOne » :

Client c = session.selectOne("mybatis.tutoriel.db.ClientDao.findOne", 2) ;

System.out.println(c.toString());

> Id : 2 Nom : HELFER Prenom : Tricia

Ici, on constate qu’on utilise la méthode « selectOne » de l’objet « session » et que l’on fait appel à « findOne » de « ClientDao » avec le paramètre « 2 », qui est aussi déclaré dans le fichier de mapping.

2.3 Insérer un enregistrement (INSERT)

Afin d’insérer un enregistrement, il est nécessaire d’ajouter dans le fichier de mapping les instructions d’insersion :

<insert id="insert" parameterType="ClientAlias" keyProperty="id">
       INSERT INTO client (
       id, nom, prenom, date_de_naissance, telephone, age
       ) VALUES (
       #{id}, #{lastname}, #{firstname}, #{birthday}, #{phonenumber}, #{age}
       )

       <selectKey resultType="int" keyProperty="id" order="AFTER">
             SELECT LAST_INSERT_ID();
       </selectKey>
</insert>

Les choses se compliquent un peu.
Il y a un paramètre de requête de type ClientAlias qui est en fait notre classe mybatis.tutoriel.db.Client.
On est obligé de faire référence à un alias. Ce point est traité dans un autre chapitre que vous pouvez consultez dès à présent.
Ensuite, on constate que pour récupérer l’ID, on doit exécuter une requête propre à MySQL.
Cette requête est exécutée après la requête d’INSERT.

Enfin, voici le code de test :

package mybatis.tutoriel.test;

import java.util.Date;

import mybatis.tutoriel.db.Client;
import mybatis.tutoriel.db.MybatisUtil;

import org.apache.ibatis.session.SqlSession;

public class TestInsertOne {
       public static void main(String[] args) {
       SqlSession session = MybatisUtil.getSession();

       Client c = new Client() ;
    
       c.setFirstname("Emeric") ;
       c.setLastname("MARTINEAU") ;
       c.setAge(33) ;
       c.setPhonenumber("598675") ;
       c.setBirthday(new Date()) ;

       int result = session.insert("mybatis.tutoriel.db.ClientDao.insert", c) ;

       session.commit() ;

       System.out.println("Retour de l'insert : " + result);
       System.out.println("Id de l'objet : " + c.getId());

       session.close() ;
       }
}

Nous avons le résultat suivant :

Retour de l'insert : 1

Id de l'objet : 8

Nous avons inséré 1 objet qui a comme Id (en MySQL) 8.
Notez bien, l’utilisation du commit pour persister les données.

2.4 Mettre à jour un enregistrement (UPDATE)

Tout comme l’insert, il est nécessaire d’ajouter dans le fichier de mapping les ordres SQL :

<update id="update" parameterType="ClientAlias">
       UPDATE client SET
       nom = #{lastname},
       prenom = #{firstname},
       date_de_naissance = #{birthday},
       telephone = #{phonenumber},
       age = #{age}
       WHERE id = #{id}
</update>

Ensuite à l’exécution du code suivant :

package mybatis.tutoriel.test;

import mybatis.tutoriel.db.Client;
import mybatis.tutoriel.db.MybatisUtil;

import org.apache.ibatis.session.SqlSession;

public class TestUpdateOne {
       public static void main(String[] args) {

       SqlSession session = MybatisUtil.getSession();

       Client c = session.selectOne("mybatis.tutoriel.db.ClientDao.findOne", 8) ;

       c.setAge(65) ;

       session.update("mybatis.tutoriel.db.ClientDao.update", c) ;

       session.commit() ;

       session.close() ;

       }
}

Et vive la retraite !

2.5 Supprimer un enregistrement (DELETE)

Pour supprimer un élément, la logique reste la même. Dans le fichier de mapping :

<delete id="delete" parameterType="ClientAlias">
       delete from client where id = #{id}
</delete> 

Et la classe de test :

package mybatis.tutoriel.test;

import mybatis.tutoriel.db.Client;
import mybatis.tutoriel.db.MybatisUtil;

import org.apache.ibatis.session.SqlSession;

public class TestDeleteOne {
       public static void main(String[] args) {

       SqlSession session = MybatisUtil.getSession();
       Client c = new Client() ;

       c.setId(8) ;

       session.delete("mybatis.tutoriel.db.ClientDao.delete", c) ;

       session.commit() ;

       session.close() ;
       }
}

La fraude a été détectée !

3 Utilisation avancée

3.1 Trier les enregistrements

Si vous reprenez le fichier de mapping, vous remarquerez qu’après la balise <resultMap>, il y a une succession de balise <result> et qu’on trouve une balise <id>.
La balise <id> qui détermine le passage à un nouvel objet, c’est donc en quelque sorte le order by par defaut.
Toutefois, il est possible de spécifier un order by dans la requete.

3.2 Alias

Dans le/les fichier(s) de mapping, il peut arriver d’écrire plusieurs resultMap avec la même classe.
Afin de ne pas répéter le nom de classe, il est possible de créer des alias dans le fichier principal de configuration, avant la balise <environnement> :

<typeAliases>
  <typeAlias alias="ClientAlias" type="mybatis.tutoriel.db.Client" />
</typeAliases>

3.3 Étendre un type

Il est possible avec MyBatis d’étendre un type (comme de l’héritage). Par exemble :

<resultMap id="ClientResultMap" type="mybatis.tutoriel.db.Client" extends="ClientBaseResultMap">
       <id property="id" column="id" />
       <result property="lastname" column="nom" />
       <result property="firstname" column="prenom" />
</resultMap>
<resultMap id="ClientBaseResultMap" type="ClientAlias">
       <result property="birthday" column="date_de_naissance" />
       <result property="phonenumber" column="telephone" />
       <result property="age" column="age" />
</resultMap>

Nous découpons notre type de résultat ClientResultMap en un sous type ClientBaseResultMap.

3.4 Association

MyBatis permet de faire des associations entre les tables.
Dans notre exemple, si une facture est lié à un client.
Nous voulons attacher au client la liste de ses factures.

Voici la table facture :

--
-- Structure de la table `facture`
--
CREATE TABLE IF NOT EXISTS `facture` (
  `id_client` int(11) NOT NULL,
  `facture_name` varchar(50) NOT NULL,
  `facture_cost` int(11) NOT NULL,
  KEY `id_client` (`id_client`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Contenu de la table `facture`
--
INSERT INTO `facture` (`id_client`, `facture_name`, `facture_cost`) VALUES
(1, 'Ritz hostel', 542000),
(2, 'Volvo', 20000),
(2, 'Game', 15);

On a donc pour le client 1, une facture et pour le client 2 deux factures.
A l’objet client, nous allons ajouter la liste des factures (avec son getter/setter) :

// La liste ne doit jamais être null !!!
private List factures = new ArrayList() ;

Créer l’objet Facture :

package mybatis.tutoriel.db;

public class Facture {
       private int id;
       private String name;
       private int cost;
}

Dans le fichier de mapping, il va falloir ajouter, le mapping de la facture :

<resultMap id="FactureResultMap" type="mybatis.tutoriel.db.Facture">
       <id property="id" column="client_id" />
       <result property="name" column="facture_name" />
       <result property="cost" column="facture_cost" />
</resultMap>

Indiquer qu’il y a une association dans ClientResultMap :

<resultMap id="ClientResultMap" type="mybatis.tutoriel.db.Client" extends="ClientBaseResultMap">
       <id property="id" column="id" />
       …
       <association property="factures" javaType="mybatis.tutoriel.db.Facture"
             resultMap="FactureResultMap" />        
</resultMap>

Et enfin la requête :

<select id="findAllWithFacture" resultMap="ClientResultMap">
       select * from client c, facture f WHERE c.id = f.id_client
</select>

Il est a noté que les requêtes ne ramenant rien de la table facture (comme les premières requêtes du tutoriel), n’ont pas d’incidence. La liste de facture sera vide.

3.5 Annotation

Plutôt que de tout faire dans un fichier de mapping, MyBatis permet d’utiliser les annotations pour écrire les requêtes.

3.5.1 Création du DAO

Le DAO ainsi que le mapping était précédemment fait dans un fichier de mapping. Grâce aux annotations, ce fichier peut ne plus être utilisé (on verra par la suite comment).
Il faut donc créer un interface DAO qui contient la requêtre SQL ainsi que le mapping à effectuer :

package mybatis.tutoriel.dao;

import java.util.List;

import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Result;
import mybatis.tutoriel.db.Client2 ;

public interface Client2Dao {
    String GET_ALL_CLIENT = "select * from client order by nom" ;

    @Select(GET_ALL_CLIENT)
    @Options(useCache=true)
    @Results(value = {
        @Result(property="id", column="id"),
        @Result(property="lastname", column="nom"),
        @Result(property="firstname", column="prenom"),
        @Result(property="birthday", column="date_de_naissance"),
        @Result(property="phonenumber", column="telephone")
        // Non necessaire car meme nom entre base et bean
        //@Result(property="age", column="age")
    })
    List selectAll() throws Exception;

}

Bien que pratique, les annotations peuvent vite devenir fastidieuses et illisibles.

3.5.2 Fichier de mapping ou non

Il est encore possible d’utiliser le fichier de mapping (pratique s’il y en a un qui existe déjà).
Dedans, il sera simplement nécessaire de déclarer le DAO comme suit :

<mapper namespace="mybatis.tutoriel.dao.Client2Dao">

</mapper>

Ou bien directement via du code java de MybatisUtil.java :

sqlSessionFactory.getConfiguration().addMapper(Client2Dao.class) ;

3.5.3 Utilisation de l’interface (exemple avec un SELECT)

A présent, l’utilisation est un peu différent :

package mybatis.tutoriel.test;

import java.util.List;

import org.apache.ibatis.session.SqlSession;

import mybatis.tutoriel.dao.Client2Dao;
import mybatis.tutoriel.db.Client2;
import mybatis.tutoriel.db.MybatisUtil;

public class TestSelectAllAnnotation {
       public static void main(String[] args) throws Exception {

       SqlSession session = MybatisUtil.getSession();

       // Avant avec fichier mapping
       //List listeClient = session.selectList("mybatis.tutoriel.db.ClientDao.findAll") ;
       List listeClient = session.getMapper(Client2Dao.class).selectAll() ;

       for (Client2 c : listeClient) {
             System.out.println(c.toString());
       }

       session.close() ;
       }
}

3.6 SQL Dynamique

MyBatis permet de créer dynamiquement des requêtes SQL.
Ce point n’est pas abordé ici car il s’agit d’une utilisation vraiment poussée.
De plus, la documentation officielle est très bien faite à ce sujet.
Vous pouvez la consulter sur : http://mybatis.github.io/mybatis-3/dynamic-sql.html

Toutefois, rappelez-vous bien que dans ce cas, vous ne pourrez pas utiliser les annotations.

4 Annexes

MyBatis :
http://blog.mybatis.org/
http://mybatis.github.io/mybatis-3/getting-started.html

Blog Zenika :
http://blog.zenika.com/index.php?post/2012/03/28/Presentation-de-MyBatis

Tutoriel :
http://loianegroner.com/2011/02/getting-started-with-ibatis-mybatis-annotations/
http://blog.soat.fr/2011/09/tutoriel-mybatis/
http://blog.idleworx.com/2011/09/mybatis-dao-example-code-tutorial.html

Aucun commentaire:

Enregistrer un commentaire